From f3840de671c0c94236a54d9822c4948af41f6431 Mon Sep 17 00:00:00 2001 From: Taylor Thomas Date: Fri, 28 Jun 2024 15:15:49 -0600 Subject: [PATCH] feat(*)!: Uses wasm-pkg-client for loading dependencies This is a fairly large PR because this dependency is used everywhere. cargo component now uses the new wasm-pkg-tools toolchain to load deps, which means that both OCI and Warg are supported. This tries to stay as close to the original code style as possible, but I did have to make large changes to how dependencies were being resolved to account for the new library. There are a couple major breaking changes to be aware of and one question to answer. This PR is already quite large, so I figured it would be better to probably merge this and then deal with follow ups to any of the outstanding questions below: - Bindings are now generated every time. Where the actual dependency is being loaded from is now abstracted away by the client, so we can't check if those files have changed on disk. I personally don't think this is the worst thing, but if people really want that functionality, we can add support for that into the package tools. - Offline deps currently does not work, but that is something that will be added into wasm-pkg-client instead of doing checks within cargo component itself. - Currently the registries specified within Cargo.toml are not used in favor of using the config file for wasm-pkg-tools. I am not sure if we wanted to use that to override the wasm-pkg-tools config or just drop it entirely. I would like to address this one before merge. - Until wasm-pkg-client has support for publishing, I have left support in to use warg directly. Once we have that added to wasm-pkg-tools, we can change the behavior here Signed-off-by: Taylor Thomas --- Cargo.lock | 1495 +++++++++++++++++++--------- Cargo.toml | 121 +-- crates/core/Cargo.toml | 23 +- crates/core/src/command.rs | 17 +- crates/core/src/lib.rs | 28 +- crates/core/src/lock.rs | 27 +- crates/core/src/registry.rs | 605 ++++------- crates/wit/Cargo.toml | 31 +- crates/wit/src/commands/add.rs | 44 +- crates/wit/src/commands/build.rs | 26 +- crates/wit/src/commands/publish.rs | 23 +- crates/wit/src/commands/update.rs | 28 +- crates/wit/src/config.rs | 4 +- crates/wit/src/lib.rs | 34 +- crates/wit/src/lock.rs | 9 +- crates/wit/tests/add.rs | 65 +- crates/wit/tests/build.rs | 14 +- crates/wit/tests/init.rs | 12 +- crates/wit/tests/publish.rs | 44 +- crates/wit/tests/support/mod.rs | 190 +++- crates/wit/tests/update.rs | 176 ++-- crates/wit/tests/version.rs | 2 +- src/bin/cargo-component.rs | 36 +- src/bindings.rs | 149 +-- src/commands/add.rs | 62 +- src/commands/new.rs | 102 +- src/commands/publish.rs | 22 +- src/commands/update.rs | 9 +- src/config.rs | 29 +- src/generator.rs | 62 +- src/lib.rs | 133 ++- src/metadata.rs | 30 +- src/registry.rs | 53 +- tests/add.rs | 102 +- tests/bench.rs | 10 +- tests/build.rs | 125 ++- tests/check.rs | 26 +- tests/clippy.rs | 30 +- tests/doc.rs | 10 +- tests/metadata.rs | 23 +- tests/new.rs | 51 +- tests/publish.rs | 86 +- tests/run.rs | 14 +- tests/support/mod.rs | 210 +++- tests/test.rs | 14 +- tests/update.rs | 123 ++- tests/version.rs | 2 +- 47 files changed, 2596 insertions(+), 1935 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 01bac8cf..30dff224 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] @@ -19,14 +19,13 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aes" -version = "0.7.5" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", "cpufeatures", - "opaque-debug", ] [[package]] @@ -76,47 +75,48 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.13" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -124,9 +124,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.82" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "arrayvec" @@ -161,27 +161,25 @@ dependencies = [ [[package]] name = "async-channel" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" dependencies = [ "concurrent-queue", - "event-listener 5.3.0", - "event-listener-strategy 0.5.1", + "event-listener-strategy", "futures-core", "pin-project-lite", ] [[package]] name = "async-executor" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f98c37cf288e302c16ef6c8472aad1e034c6c84ce5ea7b8101c98eb4a802fee" +checksum = "c8828ec6e544c02b0d6691d21ed9f9218d0384a82542855073c2a3f58304aaf0" dependencies = [ - "async-lock 3.3.0", "async-task", "concurrent-queue", - "fastrand 2.0.2", + "fastrand 2.1.0", "futures-lite 2.3.0", "slab", ] @@ -220,18 +218,18 @@ dependencies = [ [[package]] name = "async-io" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884" +checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" dependencies = [ - "async-lock 3.3.0", + "async-lock 3.4.0", "cfg-if", "concurrent-queue", "futures-io", "futures-lite 2.3.0", "parking", - "polling 3.6.0", - "rustix 0.38.32", + "polling 3.7.2", + "rustix 0.38.34", "slab", "tracing", "windows-sys 0.52.0", @@ -248,12 +246,12 @@ dependencies = [ [[package]] name = "async-lock" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ - "event-listener 4.0.3", - "event-listener-strategy 0.4.0", + "event-listener 5.3.1", + "event-listener-strategy", "pin-project-lite", ] @@ -270,44 +268,44 @@ dependencies = [ "cfg-if", "event-listener 3.1.0", "futures-lite 1.13.0", - "rustix 0.38.32", + "rustix 0.38.34", "windows-sys 0.48.0", ] [[package]] name = "async-recursion" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30c5ef0ede93efbf733c1a727f3b6b5a1060bbedd5600183e66f6e4be4af0ec5" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] name = "async-signal" -version = "0.2.5" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e47d90f65a225c4527103a8d747001fc56e375203592b25ad103e1ca13124c5" +checksum = "794f185324c2f00e771cd9f1ae8b5ac68be2ca7abb129a87afd6e86d228bc54d" dependencies = [ - "async-io 2.3.2", - "async-lock 2.8.0", + "async-io 2.3.3", + "async-lock 3.4.0", "atomic-waker", "cfg-if", "futures-core", "futures-io", - "rustix 0.38.32", + "rustix 0.38.34", "signal-hook-registry", "slab", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "async-task" -version = "4.7.0" +version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" @@ -317,7 +315,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -339,9 +337,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "axum" @@ -366,7 +364,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustversion", - "serde 1.0.197", + "serde 1.0.203", "serde_json", "serde_path_to_error", "serde_urlencoded", @@ -408,14 +406,14 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ "addr2line", "cc", @@ -432,6 +430,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + [[package]] name = "base64" version = "0.21.7" @@ -487,35 +491,25 @@ dependencies = [ ] [[package]] -name = "block-modes" -version = "0.8.1" +name = "block-padding" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb03d1bed155d89dce0f845b7899b18a9a163e148fd004e1c28421a783e2d8e" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" dependencies = [ - "block-padding", - "cipher", + "generic-array", ] -[[package]] -name = "block-padding" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" - [[package]] name = "blocking" -version = "1.5.1" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" dependencies = [ "async-channel", - "async-lock 3.3.0", "async-task", - "fastrand 2.0.2", "futures-io", "futures-lite 2.3.0", "piper", - "tracing", ] [[package]] @@ -525,8 +519,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" dependencies = [ "memchr", - "regex-automata", - "serde 1.0.197", + "regex-automata 0.4.7", + "serde 1.0.203", ] [[package]] @@ -549,11 +543,11 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "camino" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" dependencies = [ - "serde 1.0.197", + "serde 1.0.203", ] [[package]] @@ -579,27 +573,28 @@ dependencies = [ "rand_core", "rpassword", "semver", - "serde 1.0.197", + "serde 1.0.203", "serde_json", "shell-escape", "tempfile", "tokio", "tokio-util", - "toml_edit 0.22.9", + "toml_edit 0.22.14", "url", "warg-client", "warg-crypto", "warg-protocol", "warg-server", - "wasm-metadata", + "wasm-metadata 0.208.1", + "wasm-pkg-client", "wasmparser 0.208.1", "wasmprinter 0.208.1", "wat", "which", "wit-bindgen-core", "wit-bindgen-rust", - "wit-component", - "wit-parser", + "wit-component 0.208.1", + "wit-parser 0.208.1", ] [[package]] @@ -608,35 +603,38 @@ version = "0.15.0-dev" dependencies = [ "anyhow", "clap", + "dirs", "futures", "indexmap 2.2.6", "libc", "log", "owo-colors", "semver", - "serde 1.0.197", + "serde 1.0.203", "tokio", - "toml_edit 0.22.9", + "tokio-util", + "toml_edit 0.22.14", "unicode-width", "url", "warg-client", "warg-crypto", "warg-protocol", + "wasm-pkg-client", "windows-sys 0.52.0", - "wit-component", - "wit-parser", + "wit-component 0.208.1", + "wit-parser 0.208.1", ] [[package]] name = "cargo-config2" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d9bdc858a15454c2d0a5138d8dcf4bcabc06fde679abdea8330393fbc0ef05" +checksum = "d83ce0be8bd1479e5de6202def660e6c7e27e4e0599bffa4fed05bd380ec2ede" dependencies = [ "home", - "serde 1.0.197", + "serde 1.0.203", "serde_derive", - "toml_edit 0.22.9", + "toml_edit 0.22.14", ] [[package]] @@ -645,7 +643,7 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" dependencies = [ - "serde 1.0.197", + "serde 1.0.203", ] [[package]] @@ -657,16 +655,25 @@ dependencies = [ "camino", "cargo-platform", "semver", - "serde 1.0.197", + "serde 1.0.203", "serde_json", "thiserror", ] +[[package]] +name = "cbc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher", +] + [[package]] name = "cc" -version = "1.0.92" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41" +checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" [[package]] name = "cfg-if" @@ -676,31 +683,34 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.37" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", - "num-traits 0.2.18", - "serde 1.0.197", + "js-sys", + "num-traits 0.2.19", + "serde 1.0.203", + "wasm-bindgen", "windows-targets 0.52.5", ] [[package]] name = "cipher" -version = "0.3.0" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "generic-array", + "crypto-common", + "inout", ] [[package]] name = "clap" -version = "4.5.4" +version = "4.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" dependencies = [ "clap_builder", "clap_derive", @@ -708,45 +718,45 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim 0.11.1", + "strsim", ] [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] name = "concurrent-queue" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ "crossbeam-utils", ] @@ -760,7 +770,7 @@ dependencies = [ "lazy_static 1.4.0", "nom", "rust-ini", - "serde 1.0.197", + "serde 1.0.203", "serde-hjson", "serde_json", "toml 0.5.11", @@ -813,9 +823,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crypto-bigint" @@ -841,9 +851,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.8" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" +checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1" dependencies = [ "darling_core", "darling_macro", @@ -851,27 +861,27 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.8" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" +checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", - "strsim 0.10.0", - "syn 2.0.58", + "strsim", + "syn 2.0.66", ] [[package]] name = "darling_macro" -version = "0.20.8" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" +checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" dependencies = [ "darling_core", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -892,7 +902,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", - "serde 1.0.197", + "serde 1.0.203", ] [[package]] @@ -978,12 +988,34 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "displaydoc" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "doc-comment" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "docker_credential" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31951f49556e34d90ed28342e1df7e1cb7a229c4cab0aecc627b5d91edd41d07" +dependencies = [ + "base64 0.21.7", + "serde 1.0.203", + "serde_json", +] + [[package]] name = "ecdsa" version = "0.16.9" @@ -1000,9 +1032,9 @@ dependencies = [ [[package]] name = "either" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" [[package]] name = "elliptic-curve" @@ -1041,23 +1073,23 @@ dependencies = [ [[package]] name = "enumflags2" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3278c9d5fb675e0a51dabcf4c0d355f692b064171535ba72361be1528a9d8e8d" +checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d" dependencies = [ "enumflags2_derive", - "serde 1.0.197", + "serde 1.0.203", ] [[package]] name = "enumflags2_derive" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4" +checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -1081,9 +1113,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", @@ -1108,20 +1140,9 @@ dependencies = [ [[package]] name = "event-listener" -version = "4.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener" -version = "5.3.0" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d9944b8ca13534cdfb2800775f8dd4902ff3fc75a50101466decadfdf322a24" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ "concurrent-queue", "parking", @@ -1130,21 +1151,11 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" -dependencies = [ - "event-listener 4.0.3", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "332f51cb23d20b0de8458b86580878211da09bcd4503cb579c225b3d124cabb3" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ - "event-listener 5.3.0", + "event-listener 5.3.1", "pin-project-lite", ] @@ -1159,9 +1170,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "ff" @@ -1185,7 +1196,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" dependencies = [ - "num-traits 0.2.18", + "num-traits 0.2.19", ] [[package]] @@ -1287,7 +1298,7 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ - "fastrand 2.0.2", + "fastrand 2.1.0", "futures-core", "futures-io", "parking", @@ -1302,7 +1313,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -1348,9 +1359,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -1359,9 +1370,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "group" @@ -1376,15 +1387,15 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "816ec7294445779408f36fe57bc5b7fc1cf59664059096c65f905c1c61f58069" +checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" dependencies = [ + "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "futures-util", "http", "indexmap 2.2.6", "slab", @@ -1401,12 +1412,12 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", - "serde 1.0.197", + "serde 1.0.203", ] [[package]] @@ -1436,6 +1447,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex" version = "0.4.3" @@ -1480,6 +1497,15 @@ dependencies = [ "itoa", ] +[[package]] +name = "http-auth" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643c9bbf6a4ea8a656d6b4cd53d34f79e3f841ad5203c1a55fb7d761923bc255" +dependencies = [ + "memchr", +] + [[package]] name = "http-body" version = "1.0.0" @@ -1492,12 +1518,12 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", - "futures-core", + "futures-util", "http", "http-body", "pin-project-lite", @@ -1505,15 +1531,15 @@ dependencies = [ [[package]] name = "http-range-header" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ce4ef31cda248bbdb6e6820603b82dfcd9e833db65a43e997a0ccec777d11fe" +checksum = "08a397c49fec283e3d6211adbe480be95aae5f304cfb923e9970e08956d5168a" [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "httpdate" @@ -1529,9 +1555,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a" +checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" dependencies = [ "bytes", "futures-channel", @@ -1548,6 +1574,23 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +dependencies = [ + "futures-util", + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + [[package]] name = "hyper-tls" version = "0.6.0" @@ -1566,9 +1609,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" dependencies = [ "bytes", "futures-channel", @@ -1577,7 +1620,7 @@ dependencies = [ "http-body", "hyper", "pin-project-lite", - "socket2 0.5.6", + "socket2 0.5.7", "tokio", "tower", "tower-service", @@ -1607,6 +1650,124 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f8ac670d7422d7f76b32e17a5db556510825b29ec9154f235977c9caba61036" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "id-arena" version = "2.2.1" @@ -1621,12 +1782,14 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.5.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "4716a3a0933a1d01c2f72450e89596eb51dd34ef3c211ccd875acdf1f8fe47ed" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "icu_normalizer", + "icu_properties", + "smallvec", + "utf8_iter", ] [[package]] @@ -1651,7 +1814,7 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", - "serde 1.0.197", + "serde 1.0.203", ] [[package]] @@ -1661,15 +1824,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.3", - "serde 1.0.197", + "hashbrown 0.14.5", + "serde 1.0.203", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "block-padding", + "generic-array", ] [[package]] name = "instant" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", ] @@ -1702,6 +1875,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + [[package]] name = "itertools" version = "0.11.0" @@ -1735,6 +1914,21 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jwt" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6204285f77fe7d9784db3fdc449ecce1a0114927a51d5a41c4c7a292011c015f" +dependencies = [ + "base64 0.13.1", + "crypto-common", + "digest", + "hmac", + "serde 1.0.203", + "serde_json", + "sha2", +] + [[package]] name = "keyring" version = "2.3.3" @@ -1782,9 +1976,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.153" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libredox" @@ -1820,15 +2014,21 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "litemap" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -1840,36 +2040,13 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" -[[package]] -name = "logos" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c000ca4d908ff18ac99b93a062cb8958d331c3220719c52e77cb19cc6ac5d2c1" -dependencies = [ - "logos-derive 0.13.0", -] - [[package]] name = "logos" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "161971eb88a0da7ae0c333e1063467c5b5727e7fb6b710b8db4814eade3a42e8" dependencies = [ - "logos-derive 0.14.0", -] - -[[package]] -name = "logos-codegen" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc487311295e0002e452025d6b580b77bb17286de87b57138f3b5db711cded68" -dependencies = [ - "beef", - "fnv", - "proc-macro2", - "quote", - "regex-syntax 0.6.29", - "syn 2.0.58", + "logos-derive", ] [[package]] @@ -1883,26 +2060,26 @@ dependencies = [ "lazy_static 1.4.0", "proc-macro2", "quote", - "regex-syntax 0.8.3", - "syn 2.0.58", + "regex-syntax 0.8.4", + "syn 2.0.66", ] [[package]] name = "logos-derive" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbfc0d229f1f42d790440136d941afd806bc9e949e2bcb8faa813b0f00d1267e" +checksum = "1c2a69b3eb68d5bd595107c9ee58d7e07fe2bb5e360cc85b0f084dedac80de0a" dependencies = [ - "logos-codegen 0.13.0", + "logos-codegen", ] [[package]] -name = "logos-derive" -version = "0.14.0" +name = "matchers" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c2a69b3eb68d5bd595107c9ee58d7e07fe2bb5e360cc85b0f084dedac80de0a" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "logos-codegen 0.14.0", + "regex-automata 0.1.10", ] [[package]] @@ -1913,9 +2090,9 @@ checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memoffset" @@ -1955,7 +2132,7 @@ checksum = "dcf09caffaac8068c346b6df2a7fc27a177fd20b39421a39ce0a211bde679a6c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -1976,9 +2153,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] @@ -2002,11 +2179,10 @@ checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" [[package]] name = "native-tls" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" dependencies = [ - "lazy_static 1.4.0", "libc", "log", "openssl", @@ -2068,36 +2244,35 @@ dependencies = [ [[package]] name = "num" -version = "0.4.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" dependencies = [ "num-bigint", "num-complex", "num-integer", "num-iter", "num-rational", - "num-traits 0.2.18", + "num-traits 0.2.19", ] [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" dependencies = [ - "autocfg", "num-integer", - "num-traits 0.2.18", + "num-traits 0.2.19", ] [[package]] name = "num-complex" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" dependencies = [ - "num-traits 0.2.18", + "num-traits 0.2.19", ] [[package]] @@ -2112,30 +2287,29 @@ version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "num-traits 0.2.18", + "num-traits 0.2.19", ] [[package]] name = "num-iter" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", - "num-traits 0.2.18", + "num-traits 0.2.19", ] [[package]] name = "num-rational" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "autocfg", "num-bigint", "num-integer", - "num-traits 0.2.18", + "num-traits 0.2.19", ] [[package]] @@ -2144,14 +2318,14 @@ version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" dependencies = [ - "num-traits 0.2.18", + "num-traits 0.2.19", ] [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] @@ -2168,24 +2342,71 @@ dependencies = [ [[package]] name = "object" -version = "0.32.2" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" dependencies = [ "memchr", ] [[package]] -name = "once_cell" -version = "1.19.0" +name = "oci-distribution" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "b95a2c51531af0cb93761f66094044ca6ea879320bccd35ab747ff3fcab3f422" +dependencies = [ + "bytes", + "chrono", + "futures-util", + "http", + "http-auth", + "jwt", + "lazy_static 1.4.0", + "olpc-cjson", + "regex", + "reqwest", + "serde 1.0.203", + "serde_json", + "sha2", + "thiserror", + "tokio", + "tracing", + "unicase", +] [[package]] -name = "opaque-debug" -version = "0.3.1" +name = "oci-wasm" +version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +checksum = "a91502e5352f927156f2b6a28d2558cc59558b1f441b681df3f706ced6937e07" +dependencies = [ + "anyhow", + "chrono", + "oci-distribution", + "serde 1.0.203", + "serde_json", + "sha2", + "tokio", + "wit-component 0.209.1", + "wit-parser 0.209.1", +] + +[[package]] +name = "olpc-cjson" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d637c9c15b639ccff597da8f4fa968300651ad2f1e968aefc3b4927a6fb2027a" +dependencies = [ + "serde 1.0.203", + "serde_json", + "unicode-normalization", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" @@ -2210,7 +2431,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -2243,7 +2464,7 @@ version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" dependencies = [ - "num-traits 0.2.18", + "num-traits 0.2.19", ] [[package]] @@ -2288,9 +2509,9 @@ checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -2298,15 +2519,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.5", ] [[package]] @@ -2328,7 +2549,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1030c719b0ec2a2d25a5df729d6cff1acf3cc230bf766f4f97833591f7577b90" dependencies = [ "base64 0.21.7", - "serde 1.0.197", + "serde 1.0.203", ] [[package]] @@ -2355,7 +2576,7 @@ dependencies = [ "pbjson-build", "prost", "prost-build", - "serde 1.0.197", + "serde 1.0.203", ] [[package]] @@ -2375,9 +2596,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "petgraph" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", "indexmap 2.2.6", @@ -2400,7 +2621,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -2417,12 +2638,12 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piper" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" +checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" dependencies = [ "atomic-waker", - "fastrand 2.0.2", + "fastrand 2.1.0", "futures-io", ] @@ -2460,15 +2681,15 @@ dependencies = [ [[package]] name = "polling" -version = "3.6.0" +version = "3.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c976a60b2d7e99d6f229e414670a9b85d13ac305cc6d1e9c134de58c5aaaf6" +checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" dependencies = [ "cfg-if", "concurrent-queue", - "hermit-abi 0.3.9", + "hermit-abi 0.4.0", "pin-project-lite", - "rustix 0.38.32", + "rustix 0.38.34", "tracing", "windows-sys 0.52.0", ] @@ -2527,12 +2748,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7" +checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -2556,18 +2777,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] [[package]] name = "prost" -version = "0.12.4" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f5d036824e4761737860779c906171497f6d55681139d8312388f8fe398922" +checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" dependencies = [ "bytes", "prost-derive", @@ -2575,9 +2796,9 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.12.4" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80b776a1b2dc779f5ee0641f8ade0125bc1298dd41a9a0c16d8bd57b42d222b1" +checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" dependencies = [ "bytes", "heck 0.5.0", @@ -2590,21 +2811,21 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.58", + "syn 2.0.66", "tempfile", ] [[package]] name = "prost-derive" -version = "0.12.4" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19de2de2a00075bf566bee3bd4db014b11587e84184d3f7a791bc17f1a8e9e48" +checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -2613,7 +2834,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f5eec97d5d34bdd17ad2db2219aabf46b054c6c41bd5529767c9ce55be5898f" dependencies = [ - "logos 0.14.0", + "logos", "miette", "once_cell", "prost", @@ -2622,18 +2843,18 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.12.4" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3235c33eb02c1f1e212abdbe34c78b264b038fb58ca612664343271e36e55ffe" +checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" dependencies = [ "prost", ] [[package]] name = "protox" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a29b3c5596eb23a849deba860b53ffd468199d9ad5fe4402a7d55379e16aa2d2" +checksum = "ac532509cee918d40f38c3e12f8ef9230f215f017d54de7dd975015538a42ce7" dependencies = [ "bytes", "miette", @@ -2646,11 +2867,11 @@ dependencies = [ [[package]] name = "protox-parse" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "033b939d76d358f7c32120c86c71f515bae45e64f2bde455200356557276276c" +checksum = "7f6c33f43516fe397e2f930779d720ca12cd057f7da4cd6326a0ef78d69dee96" dependencies = [ - "logos 0.13.0", + "logos", "miette", "prost-types", "thiserror", @@ -2667,7 +2888,7 @@ dependencies = [ "config", "directories", "petgraph", - "serde 1.0.197", + "serde 1.0.203", "serde-value", "tint", ] @@ -2722,11 +2943,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", ] [[package]] @@ -2742,25 +2963,34 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.4" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax 0.8.3", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.3", + "regex-syntax 0.8.4", ] [[package]] @@ -2771,15 +3001,15 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "reqwest" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" +checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" dependencies = [ "base64 0.22.1", "bytes", @@ -2791,6 +3021,7 @@ dependencies = [ "http-body", "http-body-util", "hyper", + "hyper-rustls", "hyper-tls", "hyper-util", "ipnet", @@ -2802,10 +3033,10 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustls-pemfile", - "serde 1.0.197", + "serde 1.0.203", "serde_json", "serde_urlencoded", - "sync_wrapper 0.1.2", + "sync_wrapper 1.0.1", "system-configuration", "tokio", "tokio-native-tls", @@ -2830,6 +3061,21 @@ dependencies = [ "subtle", ] +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "rpassword" version = "7.3.1" @@ -2859,9 +3105,9 @@ checksum = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2" [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustix" @@ -2879,17 +3125,30 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.32" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ "bitflags 2.5.0", "errno", "libc", - "linux-raw-sys 0.4.13", + "linux-raw-sys 0.4.14", "windows-sys 0.52.0", ] +[[package]] +name = "rustls" +version = "0.23.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + [[package]] name = "rustls-pemfile" version = "2.1.2" @@ -2906,17 +3165,28 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +[[package]] +name = "rustls-webpki" +version = "0.102.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -2962,35 +3232,36 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" dependencies = [ + "serde 1.0.203", "zeroize", ] [[package]] name = "secret-service" -version = "3.0.1" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da1a5ad4d28c03536f82f77d9f36603f5e37d8869ac98f0a750d5b5686d8d95" +checksum = "b5204d39df37f06d1944935232fd2dfe05008def7ca599bf28c0800366c8a8f9" dependencies = [ "aes", - "block-modes", + "cbc", "futures-util", "generic-array", "hkdf", "num", "once_cell", "rand", - "serde 1.0.197", + "serde 1.0.203", "sha2", "zbus", ] [[package]] name = "security-framework" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "core-foundation", "core-foundation-sys", "libc", @@ -2999,9 +3270,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" dependencies = [ "core-foundation-sys", "libc", @@ -3009,11 +3280,11 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" dependencies = [ - "serde 1.0.197", + "serde 1.0.203", ] [[package]] @@ -3024,9 +3295,9 @@ checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] @@ -3050,29 +3321,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" dependencies = [ "ordered-float", - "serde 1.0.197", + "serde 1.0.203", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] name = "serde_json" -version = "1.0.115" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", - "serde 1.0.197", + "serde 1.0.203", ] [[package]] @@ -3082,7 +3353,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" dependencies = [ "itoa", - "serde 1.0.197", + "serde 1.0.203", ] [[package]] @@ -3093,16 +3364,16 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] name = "serde_spanned" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" dependencies = [ - "serde 1.0.197", + "serde 1.0.203", ] [[package]] @@ -3114,21 +3385,21 @@ dependencies = [ "form_urlencoded", "itoa", "ryu", - "serde 1.0.197", + "serde 1.0.203", ] [[package]] name = "serde_with" -version = "3.7.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee80b0e361bbf88fd2f6e242ccd19cfda072cb0faa6ae694ecee08199938569a" +checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", "indexmap 2.2.6", - "serde 1.0.197", + "serde 1.0.203", "serde_derive", "serde_json", "serde_with_macros", @@ -3137,14 +3408,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.7.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6561dc161a9224638a31d876ccdfefbc1df91d3f3a8342eddb35f055d48c7655" +checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -3156,7 +3427,7 @@ dependencies = [ "indexmap 2.2.6", "itoa", "ryu", - "serde 1.0.197", + "serde 1.0.203", "unsafe-libyaml", ] @@ -3218,9 +3489,9 @@ checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] @@ -3272,9 +3543,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", "windows-sys 0.52.0", @@ -3282,13 +3553,19 @@ dependencies = [ [[package]] name = "spdx" -version = "0.10.4" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ef1a0fa1e39ac22972c8db23ff89aea700ab96aa87114e1fb55937a631a0c9" +checksum = "47317bbaf63785b53861e1ae2d11b80d6b624211d42cb20efcd210ee6f8a14bc" dependencies = [ "smallvec", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "spki" version = "0.7.3" @@ -3300,16 +3577,16 @@ dependencies = [ ] [[package]] -name = "static_assertions" -version = "1.1.0" +name = "stable_deref_trait" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] -name = "strsim" -version = "0.10.0" +name = "static_assertions" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strsim" @@ -3336,9 +3613,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.58" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", @@ -3357,6 +3634,17 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "system-configuration" version = "0.5.1" @@ -3385,8 +3673,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", - "fastrand 2.0.2", - "rustix 0.38.32", + "fastrand 2.1.0", + "rustix 0.38.34", "windows-sys 0.52.0", ] @@ -3407,22 +3695,22 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "thiserror" -version = "1.0.58" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -3445,7 +3733,7 @@ dependencies = [ "itoa", "num-conv", "powerfmt", - "serde 1.0.197", + "serde 1.0.203", "time-core", "time-macros", ] @@ -3475,6 +3763,16 @@ dependencies = [ "lazy_static 0.2.11", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -3492,9 +3790,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.37.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ "backtrace", "bytes", @@ -3504,20 +3802,20 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.6", + "socket2 0.5.7", "tokio-macros", "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -3530,6 +3828,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls", + "rustls-pki-types", + "tokio", +] + [[package]] name = "tokio-socks" version = "0.5.1" @@ -3544,16 +3853,15 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ "bytes", "futures-core", "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] @@ -3562,28 +3870,28 @@ version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ - "serde 1.0.197", + "serde 1.0.203", ] [[package]] name = "toml" -version = "0.8.12" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" dependencies = [ - "serde 1.0.197", + "serde 1.0.203", "serde_spanned", "toml_datetime", - "toml_edit 0.22.9", + "toml_edit 0.22.14", ] [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" dependencies = [ - "serde 1.0.197", + "serde 1.0.203", ] [[package]] @@ -3599,15 +3907,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.9" +version = "0.22.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4" +checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" dependencies = [ "indexmap 2.2.6", - "serde 1.0.197", + "serde 1.0.203", "serde_spanned", "toml_datetime", - "winnow 0.6.6", + "winnow 0.6.13", ] [[package]] @@ -3683,7 +3991,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", ] [[package]] @@ -3713,10 +4021,14 @@ version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ + "matchers", "nu-ansi-term", + "once_cell", + "regex", "sharded-slab", "smallvec", "thread_local", + "tracing", "tracing-core", "tracing-log", ] @@ -3753,12 +4065,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - [[package]] name = "unicode-ident" version = "1.0.12" @@ -3776,9 +4082,9 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unicode-xid" @@ -3792,23 +4098,41 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" -version = "2.5.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "f7c25da092f0a868cdf09e8674cd3b7ef3a7d92a24253e663a2fb85e2496de56" dependencies = [ "form_urlencoded", "idna", "percent-encoding", - "serde 1.0.197", + "serde 1.0.203", ] +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "valuable" @@ -3839,9 +4163,9 @@ dependencies = [ [[package]] name = "waker-fn" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" [[package]] name = "walkdir" @@ -3870,7 +4194,7 @@ checksum = "6a22d3c9026f2f6a628cf386963844cdb7baea3b3419ba090c9096da114f977d" dependencies = [ "indexmap 2.2.6", "itertools 0.12.1", - "serde 1.0.197", + "serde 1.0.203", "serde_with", "thiserror", "warg-crypto", @@ -3902,7 +4226,7 @@ dependencies = [ "reqwest", "secrecy", "semver", - "serde 1.0.197", + "serde 1.0.203", "serde_json", "sha256", "tempfile", @@ -3938,7 +4262,7 @@ dependencies = [ "p256", "rand_core", "secrecy", - "serde 1.0.197", + "serde 1.0.203", "sha2", "signature", "thiserror", @@ -3959,7 +4283,7 @@ dependencies = [ "prost-types", "protox", "regex", - "serde 1.0.197", + "serde 1.0.203", "warg-crypto", ] @@ -3977,7 +4301,7 @@ dependencies = [ "prost", "prost-types", "semver", - "serde 1.0.197", + "serde 1.0.203", "serde_with", "thiserror", "warg-crypto", @@ -3999,12 +4323,12 @@ dependencies = [ "futures", "indexmap 2.2.6", "secrecy", - "serde 1.0.197", + "serde 1.0.203", "tempfile", "thiserror", "tokio", "tokio-util", - "toml 0.8.12", + "toml 0.8.14", "tower", "tower-http", "tracing", @@ -4058,7 +4382,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", "wasm-bindgen-shared", ] @@ -4092,7 +4416,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4115,7 +4439,7 @@ dependencies = [ "indexmap 2.2.6", "log", "petgraph", - "serde 1.0.197", + "serde 1.0.203", "serde_derive", "serde_yaml", "smallvec", @@ -4143,6 +4467,24 @@ dependencies = [ "leb128", ] +[[package]] +name = "wasm-encoder" +version = "0.209.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4a05336882dae732ce6bd48b7e11fe597293cb72c13da4f35d7d5f8d53b2a7" +dependencies = [ + "leb128", +] + +[[package]] +name = "wasm-encoder" +version = "0.210.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e3764d9d6edabd8c9e16195e177be0d20f6ab942ad18af52860f12f82bc59a" +dependencies = [ + "leb128", +] + [[package]] name = "wasm-metadata" version = "0.208.1" @@ -4151,7 +4493,7 @@ checksum = "42a2c4280ad374a6db3d76d4bb61e2ec4b3b9ce5469cc4f2bbc5708047a2bbff" dependencies = [ "anyhow", "indexmap 2.2.6", - "serde 1.0.197", + "serde 1.0.203", "serde_derive", "serde_json", "spdx", @@ -4159,6 +4501,73 @@ dependencies = [ "wasmparser 0.208.1", ] +[[package]] +name = "wasm-metadata" +version = "0.209.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d32029ce424f6d3c2b39b4419fb45a0e2d84fb0751e0c0a32b7ce8bd5d97f46" +dependencies = [ + "anyhow", + "indexmap 2.2.6", + "serde 1.0.203", + "serde_derive", + "serde_json", + "spdx", + "wasm-encoder 0.209.1", + "wasmparser 0.209.1", +] + +[[package]] +name = "wasm-pkg-client" +version = "0.4.1" +source = "git+https://github.com/thomastaylor312/wasm-pkg-tools.git?branch=fix/cached_versions#637284b2fff19c91205b489c7a34cff0cfb707a8" +dependencies = [ + "anyhow", + "async-trait", + "base64 0.22.1", + "bytes", + "dirs", + "docker_credential", + "futures-util", + "oci-distribution", + "oci-wasm", + "secrecy", + "serde 1.0.203", + "serde_json", + "sha2", + "thiserror", + "tokio", + "tokio-util", + "toml 0.8.14", + "tracing", + "tracing-subscriber", + "url", + "warg-client", + "warg-protocol", + "wasm-pkg-common", +] + +[[package]] +name = "wasm-pkg-common" +version = "0.4.1" +source = "git+https://github.com/thomastaylor312/wasm-pkg-tools.git?branch=fix/cached_versions#637284b2fff19c91205b489c7a34cff0cfb707a8" +dependencies = [ + "anyhow", + "bytes", + "dirs", + "futures-util", + "http", + "reqwest", + "semver", + "serde 1.0.203", + "serde_json", + "sha2", + "thiserror", + "tokio", + "toml 0.8.14", + "tracing", +] + [[package]] name = "wasm-streams" version = "0.4.0" @@ -4191,10 +4600,23 @@ checksum = "dd921789c9dcc495f589cb37d200155dee65b4a4beeb853323b5e24e0a5f9c58" dependencies = [ "ahash", "bitflags 2.5.0", - "hashbrown 0.14.3", + "hashbrown 0.14.5", + "indexmap 2.2.6", + "semver", + "serde 1.0.203", +] + +[[package]] +name = "wasmparser" +version = "0.209.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07035cc9a9b41e62d3bb3a3815a66ab87c993c06fe1cf6b2a3f2a18499d937db" +dependencies = [ + "ahash", + "bitflags 2.5.0", + "hashbrown 0.14.5", "indexmap 2.2.6", "semver", - "serde 1.0.197", ] [[package]] @@ -4219,22 +4641,22 @@ dependencies = [ [[package]] name = "wast" -version = "208.0.1" +version = "210.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc00b3f023b4e2ccd2e054e240294263db52ae962892e6523e550783c83a67f1" +checksum = "aa835c59bd615e00f16be65705d85517d40b44b3c831d724e450244685176c3c" dependencies = [ "bumpalo", "leb128", "memchr", "unicode-width", - "wasm-encoder 0.208.1", + "wasm-encoder 0.210.0", ] [[package]] name = "wat" -version = "1.208.1" +version = "1.210.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58ed38e59176550214c025ea2bd0eeefd8e86b92d0af6698d5ba95020ec2e07b" +checksum = "67faece8487996430c6812be7f8776dc563ca0efcd3db77f8839070480c0d1a6" dependencies = [ "wast", ] @@ -4257,7 +4679,7 @@ checksum = "8211e4f58a2b2805adfbefbc07bab82958fc91e3836339b1ab7ae32465dce0d7" dependencies = [ "either", "home", - "rustix 0.38.32", + "rustix 0.38.34", "winsafe", ] @@ -4279,11 +4701,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -4451,9 +4873,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.6" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c976aaaa0e1f90dbb21e9587cdaf1d9679a1cde8875c0d6bd83ab96a208352" +checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" dependencies = [ "memchr", ] @@ -4492,20 +4914,21 @@ dependencies = [ "rand_core", "rpassword", "semver", - "serde 1.0.197", + "serde 1.0.203", "tempfile", "tokio", "tokio-util", - "toml_edit 0.22.9", + "toml_edit 0.22.14", "url", "warg-client", "warg-crypto", "warg-protocol", "warg-server", - "wasm-metadata", + "wasm-metadata 0.208.1", + "wasm-pkg-client", "wasmparser 0.208.1", - "wit-component", - "wit-parser", + "wit-component 0.208.1", + "wit-parser 0.208.1", ] [[package]] @@ -4516,7 +4939,7 @@ checksum = "7076a12e69af6e1f6093bd16657d7ae61c30cfd3c5f62321046eb863b17ab1e2" dependencies = [ "anyhow", "heck 0.5.0", - "wit-parser", + "wit-parser 0.208.1", ] [[package]] @@ -4528,9 +4951,9 @@ dependencies = [ "anyhow", "heck 0.5.0", "indexmap 2.2.6", - "wasm-metadata", + "wasm-metadata 0.208.1", "wit-bindgen-core", - "wit-component", + "wit-component 0.208.1", ] [[package]] @@ -4543,13 +4966,32 @@ dependencies = [ "bitflags 2.5.0", "indexmap 2.2.6", "log", - "serde 1.0.197", + "serde 1.0.203", "serde_derive", "serde_json", "wasm-encoder 0.208.1", - "wasm-metadata", + "wasm-metadata 0.208.1", "wasmparser 0.208.1", - "wit-parser", + "wit-parser 0.208.1", +] + +[[package]] +name = "wit-component" +version = "0.209.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bb5b039f9cb03425e1d5a6e54b441ca4ca1b1d4fa6a0924db67a55168f99" +dependencies = [ + "anyhow", + "bitflags 2.5.0", + "indexmap 2.2.6", + "log", + "serde 1.0.203", + "serde_derive", + "serde_json", + "wasm-encoder 0.209.1", + "wasm-metadata 0.209.1", + "wasmparser 0.209.1", + "wit-parser 0.209.1", ] [[package]] @@ -4563,21 +5005,51 @@ dependencies = [ "indexmap 2.2.6", "log", "semver", - "serde 1.0.197", + "serde 1.0.203", "serde_derive", "serde_json", "unicode-xid", "wasmparser 0.208.1", ] +[[package]] +name = "wit-parser" +version = "0.209.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e79b9e3c0b6bb589dec46317e645851e0db2734c44e2be5e251b03ff4a51269" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.2.6", + "log", + "semver", + "serde 1.0.203", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser 0.209.1", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "xdg-home" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e5a325c3cb8398ad6cf859c1135b25dd29e186679cf2da7581d9679f63b38e" +checksum = "ca91dcf8f93db085f3a0a29358cd0b9d670915468f4290e8b85d118a34211ab8" dependencies = [ "libc", - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -4589,6 +5061,30 @@ dependencies = [ "linked-hash-map", ] +[[package]] +name = "yoke" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +dependencies = [ + "serde 1.0.203", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", + "synstructure", +] + [[package]] name = "zbus" version = "3.15.2" @@ -4617,7 +5113,7 @@ dependencies = [ "once_cell", "ordered-stream", "rand", - "serde 1.0.197", + "serde 1.0.203", "serde_repr", "sha1", "static_assertions", @@ -4650,7 +5146,7 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "437d738d3750bed6ca9b8d423ccc7a8eb284f6b1d6d4e225a0e4e6258d864c8d" dependencies = [ - "serde 1.0.197", + "serde 1.0.203", "static_assertions", "zvariant", ] @@ -4672,14 +5168,57 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.66", +] + +[[package]] +name = "zerofrom" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", + "synstructure", ] [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerovec" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "bb2cc8827d6c0994478a15c53f374f46fbd41bea663d809b14744bc42e6b109c" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97cf56601ee5052b4417d90c8755c6683473c926039908196cf35d99f893ebe7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] [[package]] name = "zvariant" @@ -4690,7 +5229,7 @@ dependencies = [ "byteorder", "enumflags2", "libc", - "serde 1.0.197", + "serde 1.0.203", "static_assertions", "zvariant_derive", ] diff --git a/Cargo.toml b/Cargo.toml index 512b4c1d..809bc041 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,95 +18,102 @@ keywords = ["webassembly", "wasm", "components", "component-model"] repository = "https://github.com/bytecodealliance/cargo-component" [dependencies] -cargo-component-core = { workspace = true } anyhow = { workspace = true } +bytes = { workspace = true } +cargo_metadata = { workspace = true } +cargo-component-core = { workspace = true } +cargo-config2 = { workspace = true } clap = { workspace = true } -toml_edit = { workspace = true } -pretty_env_logger = { workspace = true } -log = { workspace = true } -tokio = { workspace = true } -tokio-util = { workspace = true } +futures = { workspace = true } heck = { workspace = true } -semver = { workspace = true } -serde = { workspace = true } -serde_json = { workspace = true } indexmap = { workspace = true } -url = { workspace = true } -wit-bindgen-rust = { workspace = true } -wit-bindgen-core = { workspace = true } -wit-parser = { workspace = true } -wit-component = { workspace = true } -wasm-metadata = { workspace = true } -wasmparser = { workspace = true } -parse_arg = { workspace = true } -cargo_metadata = { workspace = true } -cargo-config2 = { workspace = true } libc = { workspace = true } -warg-protocol = { workspace = true } -warg-crypto = { workspace = true } -warg-client = { workspace = true } +log = { workspace = true } p256 = { workspace = true } +parse_arg = { workspace = true } +pretty_env_logger = { workspace = true } rand_core = { workspace = true } rpassword = { workspace = true } -futures = { workspace = true } -bytes = { workspace = true } -which = { workspace = true } +semver = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } shell-escape = "0.1.5" tempfile = { workspace = true } +tokio = { workspace = true } +tokio-util = { workspace = true } +toml_edit = { workspace = true } +url = { workspace = true } +warg-client = { workspace = true } +warg-crypto = { workspace = true } +warg-protocol = { workspace = true } +wasm-metadata = { workspace = true } +wasm-pkg-client = { workspace = true } +wasmparser = { workspace = true } +which = { workspace = true } +wit-bindgen-core = { workspace = true } +wit-bindgen-rust = { workspace = true } +wit-component = { workspace = true } +wit-parser = { workspace = true } [dev-dependencies] assert_cmd = { workspace = true } predicates = { workspace = true } -wat = { workspace = true } -warg-server = { workspace = true } tempfile = { workspace = true } +warg-server = { workspace = true } wasmprinter = { workspace = true } +wat = { workspace = true } [workspace] members = ["crates/core", "crates/wit"] [workspace.dependencies] -cargo-component-core = { path = "crates/core", version = "0.15.0-dev" } -warg-protocol = "0.7.0" -warg-crypto = "0.7.0" -warg-client = "0.7.0" -warg-server = "0.7.0" anyhow = "1.0.82" -clap = { version = "4.5.4", features = ["derive"] } -toml_edit = { version = "0.22.9", features = ["serde"] } -pretty_env_logger = "0.5.0" -log = "0.4.21" -tokio = { version = "1.37.0", default-features = false, features = ["macros", "rt-multi-thread"] } -tokio-util = "0.7.10" -heck = "0.5.0" -semver = "1.0.22" -serde = { version = "1.0.197", features = ["derive"] } -serde_json = "1.0.115" -indexmap = "2.2.6" -url = { version = "2.5.0", features = ["serde"] } -wit-parser = "0.208.1" -wit-component = "0.208.1" -wasm-metadata = "0.208.1" -parse_arg = "0.1.4" +assert_cmd = "2.0.14" +bytes = "1.6.0" cargo_metadata = "0.18.1" +cargo-component-core = { path = "crates/core", version = "0.15.0-dev" } cargo-config2 = "0.1.24" +clap = { version = "4.5.4", features = ["derive", "env"] } +dirs = "5" +futures = "0.3.30" +heck = "0.5.0" +indexmap = "2.2.6" libc = "0.2.153" +log = "0.4.21" +oci-distribution = "0.11" owo-colors = "4.0.0" -unicode-width = "0.1.11" p256 = "0.13.2" +parse_arg = "0.1.4" +predicates = "3.1.0" +pretty_env_logger = "0.5.0" rand_core = "0.6.4" rpassword = "7.3.1" -futures = "0.3.30" -bytes = "1.6.0" -which = "6.0.1" -wit-bindgen-rust = "0.25.0" -wit-bindgen-core = "0.25.0" +semver = "1" +serde = { version = "1.0.197", features = ["derive"] } +serde_json = "1.0.115" tempfile = "3.10.1" -assert_cmd = "2.0.14" -predicates = "3.1.0" +tokio = { version = "1.37.0", default-features = false, features = [ + "macros", + "rt-multi-thread", +] } +tokio-util = "0.7.10" +toml_edit = { version = "0.22.9", features = ["serde"] } +unicode-width = "0.1.11" +url = { version = "2.5.0", features = ["serde"] } +warg-client = "0.7.0" +warg-crypto = "0.7.0" +warg-protocol = "0.7.0" +warg-server = "0.7.0" +wasm-metadata = "0.208.1" +wasm-pkg-client = { git = "https://github.com/thomastaylor312/wasm-pkg-tools.git", branch = "fix/cached_versions" } wasmparser = "0.208.1" -wat = "1.208.1" wasmprinter = "0.208.1" +wat = "1.208.1" +which = "6.0.1" +wit-bindgen-core = "0.25.0" +wit-bindgen-rust = "0.25.0" +wit-component = "0.208.1" +wit-parser = "0.208.1" [profile.release] panic = "abort" diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 0a07dc89..7bc43a47 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -11,23 +11,26 @@ repository = { workspace = true } [dependencies] anyhow = { workspace = true } +clap = { workspace = true } +dirs = { workspace = true } +futures = { workspace = true } +indexmap = { workspace = true } libc = { workspace = true } +log = { workspace = true } owo-colors = { workspace = true } -unicode-width = { workspace = true } -warg-crypto = { workspace = true } -warg-protocol = { workspace = true } -warg-client = { workspace = true } -toml_edit = { workspace = true } semver = { workspace = true } serde = { workspace = true } -indexmap = { workspace = true } -futures = { workspace = true } +tokio = { workspace = true } +tokio-util = { workspace = true, features = ["io"] } +toml_edit = { workspace = true } +unicode-width = { workspace = true } url = { workspace = true } +warg-client = { workspace = true } +warg-crypto = { workspace = true } +warg-protocol = { workspace = true } +wasm-pkg-client = { workspace = true } wit-component = { workspace = true } wit-parser = { workspace = true } -log = { workspace = true } -tokio = { workspace = true } -clap = { workspace = true } [target.'cfg(windows)'.dependencies.windows-sys] version = "0.52" diff --git a/crates/core/src/command.rs b/crates/core/src/command.rs index 3d92ccbb..e1e6ebfb 100644 --- a/crates/core/src/command.rs +++ b/crates/core/src/command.rs @@ -1,8 +1,15 @@ //! Module for common command implementation. +use std::path::PathBuf; -use crate::terminal::{Color, Terminal, Verbosity}; use clap::{ArgAction, Args}; +use crate::terminal::{Color, Terminal, Verbosity}; + +/// The environment variable name for setting a cache directory location +pub const CACHE_DIR_ENV_VAR: &str = "CARGO_COMPONENT_CACHE_DIR"; +/// The environment variable name for setting a path to a config file +pub const CONFIG_FILE_ENV_VAR: &str = "CARGO_COMPONENT_CONFIG_FILE"; + /// Common options for commands. #[derive(Args)] #[command( @@ -24,6 +31,14 @@ pub struct CommonOptions { /// Coloring: auto, always, never #[clap(long = "color", value_name = "WHEN")] pub color: Option, + + /// The path to the cache directory to store component dependencies. + #[clap(long = "cache-dir", env = CACHE_DIR_ENV_VAR)] + pub cache_dir: Option, + + /// The path to the pkg-tools config file + #[clap(long = "config", env = CONFIG_FILE_ENV_VAR)] + pub config: Option, } impl CommonOptions { diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 87ae52fe..870258f1 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -2,10 +2,12 @@ #![deny(missing_docs)] +use std::path::PathBuf; +use std::str::FromStr; + use anyhow::Context; use semver::VersionReq; -use std::str::FromStr; -use warg_protocol::registry::PackageName; +use wasm_pkg_client::PackageRef; pub mod command; pub mod lock; @@ -13,11 +15,31 @@ pub mod progress; pub mod registry; pub mod terminal; +/// The root directory name used for default cargo component directories +pub const CARGO_COMPONENT_DIR: &str = "cargo-component"; +/// The cache directory name used by default +pub const CACHE_DIR: &str = "cache"; + +/// Returns the path to the default cache directory, returning an error if a cache directory cannot be found. +pub fn default_cache_dir() -> anyhow::Result { + dirs::cache_dir() + .map(|p| p.join(CARGO_COMPONENT_DIR).join(CACHE_DIR)) + .ok_or_else(|| anyhow::anyhow!("failed to find cache directory")) +} + +/// A helper that fetches the default directory if the given directory is `None`. +pub fn cache_dir(dir: Option) -> anyhow::Result { + match dir { + Some(dir) => Ok(dir), + None => default_cache_dir(), + } +} + /// Represents a versioned component package name. #[derive(Clone)] pub struct VersionedPackageName { /// The package name. - pub name: PackageName, + pub name: PackageRef, /// The optional package version. pub version: Option, } diff --git a/crates/core/src/lock.rs b/crates/core/src/lock.rs index 90a9f59d..30f9a51a 100644 --- a/crates/core/src/lock.rs +++ b/crates/core/src/lock.rs @@ -10,8 +10,7 @@ use std::{ path::{Path, PathBuf}, }; use toml_edit::{DocumentMut, Item, Value}; -use warg_crypto::hash::AnyHash; -use warg_protocol::registry::PackageName; +use wasm_pkg_client::{ContentDigest, PackageRef}; /// The file format version of the lock file. const LOCK_FILE_VERSION: i64 = 1; @@ -21,7 +20,7 @@ const LOCK_FILE_VERSION: i64 = 1; #[serde(rename_all = "kebab-case")] pub struct LockedPackage { /// The name of the locked package. - pub name: PackageName, + pub name: PackageRef, /// The registry the package was resolved from. /// /// Defaults to the default registry if not specified. @@ -37,9 +36,10 @@ pub struct LockedPackage { impl LockedPackage { /// Gets the key used in sorting and searching the package list. - pub fn key(&self) -> (&PackageName, &str) { + pub fn key(&self) -> (&str, &str, &str) { ( - &self.name, + self.name.namespace().as_ref(), + self.name.name().as_ref(), self.registry.as_deref().unwrap_or(DEFAULT_REGISTRY_NAME), ) } @@ -53,7 +53,7 @@ pub struct LockedPackageVersion { /// The version the package is locked to. pub version: Version, /// The digest of the package contents. - pub digest: AnyHash, + pub digest: ContentDigest, } impl LockedPackageVersion { @@ -81,13 +81,20 @@ impl<'a> LockFileResolver<'a> { pub fn resolve( &'a self, registry: &str, - name: &PackageName, + package_ref: &PackageRef, requirement: &VersionReq, ) -> Result> { if let Some(pkg) = self .0 .packages - .binary_search_by_key(&(name, registry), LockedPackage::key) + .binary_search_by_key( + &( + package_ref.namespace().as_ref(), + package_ref.name().as_ref(), + registry, + ), + LockedPackage::key, + ) .ok() .map(|i| &self.0.packages[i]) { @@ -96,12 +103,12 @@ impl<'a> LockFileResolver<'a> { .binary_search_by_key(&requirement.to_string().as_str(), LockedPackageVersion::key) { let locked = &pkg.versions[index]; - log::info!("dependency package `{name}` from registry `{registry}` with requirement `{requirement}` was resolved by the lock file to version {version}", version = locked.version); + log::info!("dependency package `{package_ref}` from registry `{registry}` with requirement `{requirement}` was resolved by the lock file to version {version}", version = locked.version); return Ok(Some(locked)); } } - log::info!("dependency package `{name}` from registry `{registry}` with requirement `{requirement}` was not in the lock file"); + log::info!("dependency package `{package_ref}` from registry `{registry}` with requirement `{requirement}` was not in the lock file"); Ok(None) } } diff --git a/crates/core/src/registry.rs b/crates/core/src/registry.rs index 2391babb..c5684816 100644 --- a/crates/core/src/registry.rs +++ b/crates/core/src/registry.rs @@ -1,35 +1,36 @@ //! Module for resolving dependencies from a component registry. - -use crate::{ - lock::{LockFileResolver, LockedPackageVersion}, - progress::{ProgressBar, ProgressStyle}, - terminal::{Colors, Terminal}, +use std::{ + collections::{hash_map, HashMap}, + fmt::Debug, + path::{Path, PathBuf}, + str::FromStr, + sync::Arc, }; + use anyhow::{bail, Context, Result}; -use futures::{stream::FuturesUnordered, StreamExt}; +use futures::TryStreamExt; use indexmap::IndexMap; use semver::{Comparator, Op, Version, VersionReq}; use serde::{ de::{self, value::MapAccessDeserializer}, Deserialize, Serialize, }; -use std::{ - collections::{hash_map, HashMap, HashSet}, - fs, - path::{Path, PathBuf}, - str::FromStr, - sync::Arc, -}; + +use tokio::io::AsyncReadExt; use url::Url; -use warg_client::{ - storage::{ContentStorage, PackageInfo}, - Config, FileSystemClient, StorageLockResult, +use warg_client::{Config as WargConfig, FileSystemClient, StorageLockResult}; +use wasm_pkg_client::{ + caching::{CachingClient, FileCache}, + Client, Config, ContentDigest, Error as WasmPkgError, PackageRef, Release, VersionInfo, }; -use warg_crypto::hash::AnyHash; -use warg_protocol::registry; use wit_component::DecodedWasm; use wit_parser::{PackageId, PackageName, Resolve, UnresolvedPackage, WorldId}; +use crate::{ + lock::{LockFileResolver, LockedPackageVersion}, + terminal::{Colors, Terminal}, +}; + /// The name of the default registry. pub const DEFAULT_REGISTRY_NAME: &str = "default"; @@ -51,7 +52,7 @@ pub fn find_url<'a>( /// Creates a registry client with the given warg configuration. pub async fn create_client( - config: &warg_client::Config, + config: &WargConfig, url: &str, terminal: &Terminal, ) -> Result { @@ -92,7 +93,7 @@ impl Serialize for Dependency { } else { #[derive(Serialize)] struct Entry<'a> { - package: Option<&'a registry::PackageName>, + package: Option<&'a PackageRef>, version: &'a str, registry: Option<&'a str>, } @@ -146,7 +147,7 @@ impl<'de> Deserialize<'de> for Dependency { #[serde(default, deny_unknown_fields)] struct Entry { path: Option, - package: Option, + package: Option, version: Option, registry: Option, } @@ -196,7 +197,7 @@ pub struct RegistryPackage { /// The name of the package. /// /// If not specified, the name from the mapping will be used. - pub name: Option, + pub name: Option, /// The version requirement of the package. pub version: VersionReq, @@ -222,14 +223,14 @@ impl FromStr for RegistryPackage { } /// Represents information about a resolution of a registry package. -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct RegistryResolution { /// The name of the dependency that was resolved. /// /// This may differ from `package` if the dependency was renamed. - pub name: registry::PackageName, + pub name: PackageRef, /// The name of the package from the registry that was resolved. - pub package: registry::PackageName, + pub package: PackageRef, /// The name of the registry used to resolve the package. /// /// A value of `None` indicates that the default registry was used. @@ -239,16 +240,29 @@ pub struct RegistryResolution { /// The package version that was resolved. pub version: Version, /// The digest of the package contents. - pub digest: AnyHash, - /// The path to the resolved dependency. - pub path: PathBuf, + pub digest: ContentDigest, + /// The client to use for fetching the package contents. + client: Arc>, +} + +impl Debug for RegistryResolution { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.debug_struct("RegistryResolution") + .field("name", &self.name) + .field("package", &self.package) + .field("registry", &self.registry) + .field("requirement", &self.requirement) + .field("version", &self.version) + .field("digest", &self.digest) + .finish() + } } /// Represents information about a resolution of a local file. #[derive(Clone, Debug)] pub struct LocalResolution { /// The name of the dependency that was resolved. - pub name: registry::PackageName, + pub name: PackageRef, /// The path to the resolved dependency. pub path: PathBuf, } @@ -265,21 +279,13 @@ pub enum DependencyResolution { impl DependencyResolution { /// Gets the name of the dependency that was resolved. - pub fn name(&self) -> ®istry::PackageName { + pub fn name(&self) -> &PackageRef { match self { Self::Registry(res) => &res.name, Self::Local(res) => &res.name, } } - /// Gets the path to the resolved dependency. - pub fn path(&self) -> &Path { - match self { - Self::Registry(res) => &res.path, - Self::Local(res) => &res.path, - } - } - /// Gets the resolved version. /// /// Returns `None` if the dependency is not resolved from a registry package. @@ -293,7 +299,7 @@ impl DependencyResolution { /// The key used in sorting and searching the lock file package list. /// /// Returns `None` if the dependency is not resolved from a registry package. - pub fn key(&self) -> Option<(®istry::PackageName, Option<&str>)> { + pub fn key(&self) -> Option<(&PackageRef, Option<&str>)> { match self { DependencyResolution::Registry(pkg) => Some((&pkg.package, pkg.registry.as_deref())), DependencyResolution::Local(_) => None, @@ -301,37 +307,60 @@ impl DependencyResolution { } /// Decodes the resolved dependency. - pub fn decode(&self) -> Result { + pub async fn decode(&self) -> Result { // If the dependency path is a directory, assume it contains wit to parse as a package. - if self.path().is_dir() { - return Ok(DecodedDependency::Wit { - resolution: self, - package: UnresolvedPackage::parse_dir(self.path()).with_context(|| { + let bytes = match self { + DependencyResolution::Local(LocalResolution { path, .. }) + if tokio::fs::metadata(path).await?.is_dir() => + { + return Ok(DecodedDependency::Wit { + resolution: self, + package: UnresolvedPackage::parse_dir(path).with_context(|| { + format!("failed to parse dependency `{path}`", path = path.display()) + })?, + }); + } + DependencyResolution::Local(LocalResolution { path, .. }) => { + tokio::fs::read(path).await.with_context(|| { format!( - "failed to parse dependency `{path}`", - path = self.path().display() + "failed to read content of dependency `{name}` at path `{path}`", + name = self.name(), + path = path.display() ) - })?, - }); - } + })? + } + DependencyResolution::Registry(res) => { + let stream = res + .client + .get_content( + &res.package, + &Release { + version: res.version.clone(), + content_digest: res.digest.clone(), + }, + ) + .await?; - let bytes = fs::read(self.path()).with_context(|| { - format!( - "failed to read content of dependency `{name}` at path `{path}`", - name = self.name(), - path = self.path().display() - ) - })?; + let mut buf = Vec::new(); + tokio_util::io::StreamReader::new( + stream.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e)), + ) + .read_to_end(&mut buf) + .await?; + buf + } + }; if &bytes[0..4] != b"\0asm" { return Ok(DecodedDependency::Wit { resolution: self, package: UnresolvedPackage::parse( - self.path(), + // This is fake, but it's needed for the parser to work. + self.name().to_string().as_ref(), std::str::from_utf8(&bytes).with_context(|| { format!( - "dependency `{path}` is not UTF-8 encoded", - path = self.path().display() + "dependency `{name}` is not UTF-8 encoded", + name = self.name() ) })?, )?, @@ -342,9 +371,8 @@ impl DependencyResolution { resolution: self, decoded: wit_component::decode(&bytes).with_context(|| { format!( - "failed to decode content of dependency `{name}` at path `{path}`", + "failed to decode content of dependency `{name}`", name = self.name(), - path = self.path().display() ) })?, }) @@ -416,39 +444,42 @@ impl<'a> DecodedDependency<'a> { /// Used to resolve dependencies for a WIT package. pub struct DependencyResolver<'a> { - terminal: &'a Terminal, - registry_urls: &'a HashMap, - warg_config: &'a Config, + client: Arc>, lock_file: Option>, registries: IndexMap<&'a str, Registry<'a>>, - resolutions: HashMap, - network_allowed: bool, + resolutions: HashMap, } impl<'a> DependencyResolver<'a> { /// Creates a new dependency resolver. - pub fn new( - warg_config: &'a Config, - registry_urls: &'a HashMap, + pub fn new(config: Config, lock_file: Option>, cache: FileCache) -> Self { + let client = CachingClient::new(Client::new(config), cache); + DependencyResolver { + client: Arc::new(client), + lock_file, + registries: Default::default(), + resolutions: Default::default(), + } + } + + /// Creates a new dependency resolver with the given client. This is useful when you already + /// have a client available + pub fn new_with_client( + client: Arc>, lock_file: Option>, - terminal: &'a Terminal, - network_allowed: bool, - ) -> Result { - Ok(DependencyResolver { - terminal, - registry_urls, - warg_config, + ) -> Self { + DependencyResolver { + client, lock_file, registries: Default::default(), resolutions: Default::default(), - network_allowed, - }) + } } /// Add a dependency to the resolver. pub async fn add_dependency( &mut self, - name: &'a registry::PackageName, + name: &'a PackageRef, dependency: &'a Dependency, ) -> Result<()> { match dependency { @@ -470,25 +501,15 @@ impl<'a> DependencyResolver<'a> { let registry = match self.registries.entry(registry_name) { indexmap::map::Entry::Occupied(e) => e.into_mut(), - indexmap::map::Entry::Vacant(e) => { - let url = find_url( - Some(registry_name), - self.registry_urls, - self.warg_config.home_url.as_deref(), - )?; - e.insert(Registry { - client: Arc::new( - create_client(self.warg_config, url, self.terminal).await?, - ), - packages: HashMap::new(), - dependencies: Vec::new(), - upserts: HashSet::new(), - }) - } + indexmap::map::Entry::Vacant(e) => e.insert(Registry { + client: self.client.clone(), + packages: HashMap::new(), + dependencies: Vec::new(), + }), }; registry - .add_dependency(name, package_name, &package.version, registry_name, locked) + .add_dependency(name, package_name, &package.version, locked) .await?; } Dependency::Local(p) => { @@ -511,202 +532,44 @@ impl<'a> DependencyResolver<'a> { /// This will download all dependencies that are not already present in client storage. /// /// Returns the dependency resolution map. - pub async fn resolve(self) -> Result { - let Self { - mut registries, - mut resolutions, - terminal, - network_allowed, - .. - } = self; - - // Start by updating the packages that need updating - // This will determine the contents that need to be downloaded - let downloads = Self::update_packages(&mut registries, terminal, network_allowed).await?; - - // Finally, download and resolve the dependencies - for resolution in - Self::download_and_resolve(registries, downloads, terminal, network_allowed).await? - { - let prev = resolutions.insert(resolution.name().clone(), resolution); - assert!(prev.is_none()); - } - - Ok(resolutions) - } - - async fn update_packages( - registries: &mut IndexMap<&'a str, Registry<'a>>, - terminal: &Terminal, - network_allowed: bool, - ) -> Result> { - let task_count = registries - .iter() - .filter(|(_, r)| !r.upserts.is_empty()) - .count(); - - let mut progress = ProgressBar::with_style("Updating", ProgressStyle::Ratio, terminal); - - if task_count > 0 { - if !network_allowed { - bail!("a component registry update is required but network access is disabled"); - } - - terminal.status("Updating", "component registry package logs")?; - progress.tick_now(0, task_count, "")?; - } - - let mut downloads = DownloadMap::new(); - let mut futures = FuturesUnordered::new(); - for (index, (name, registry)) in registries.iter_mut().enumerate() { - let upserts = std::mem::take(&mut registry.upserts); - if upserts.is_empty() { - // No upserts needed, add the necessary downloads now - registry.add_downloads(name, &mut downloads).await?; - continue; - } - - log::info!("updating package logs for registry `{name}`"); - - let client = registry.client.clone(); - futures.push(tokio::spawn(async move { - (index, client.fetch_packages(upserts.iter()).await) - })) + pub async fn resolve(mut self) -> Result { + // Resolve all dependencies + for (name, registry) in self.registries.iter_mut() { + registry.resolve(name).await?; } - assert_eq!(futures.len(), task_count); - - let mut finished = 0; - while let Some(res) = futures.next().await { - let (index, res) = res.context("failed to join registry update task")?; - let (name, registry) = registries - .get_index_mut(index) - .expect("out of bounds registry index"); - - res.with_context(|| { - format!("failed to update package logs for component registry `{name}`") - })?; - - log::info!("package logs successfully updated for component registry `{name}`"); - finished += 1; - progress.tick_now(finished, task_count, ": updated `{name}`")?; - registry.add_downloads(name, &mut downloads).await?; - } - - assert_eq!(finished, task_count); - - progress.clear(); - - Ok(downloads) - } - - async fn download_and_resolve( - mut registries: IndexMap<&'a str, Registry<'a>>, - downloads: DownloadMap<'a>, - terminal: &Terminal, - network_allowed: bool, - ) -> Result + 'a> { - if !downloads.is_empty() { - if !network_allowed { - bail!("a component package download is required but network access is disabled"); - } - - terminal.status("Downloading", "component registry packages")?; - - let mut progress = - ProgressBar::with_style("Downloading", ProgressStyle::Ratio, terminal); - - let count = downloads.len(); - progress.tick_now(0, count, "")?; - - let mut futures = FuturesUnordered::new(); - for ((registry_name, name, version), deps) in downloads { - let registry_index = registries.get_index_of(registry_name).unwrap(); - let (_, registry) = registries.get_index(registry_index).unwrap(); - - log::info!("downloading content for package `{name}` from component registry `{registry_name}`"); - - let client = registry.client.clone(); - futures.push(tokio::spawn(async move { - let res = client.download_exact(&name, &version).await; - (registry_index, name, version, deps, res) - })) - } - - assert_eq!(futures.len(), count); - - let mut finished = 0; - while let Some(res) = futures.next().await { - let (registry_index, name, version, deps, res) = - res.context("failed to join content download task")?; - let (registry_name, registry) = registries - .get_index_mut(registry_index) - .expect("out of bounds registry index"); - - let download = res.with_context(|| { - format!("failed to download package `{name}` (v{version}) from component registry `{registry_name}`") - })?; - - log::info!( - "downloaded contents of package `{name}` (v{version}) from component registry `{registry_name}`" - ); - - finished += 1; - progress.tick_now( - finished, - count, - &format!(": downloaded `{name}` (v{version})"), - )?; - - for index in deps { - let dependency = &mut registry.dependencies[index]; - assert!(dependency.resolution.is_none()); - dependency.resolution = Some(RegistryResolution { - name: dependency.name.clone(), - package: dependency.package.clone(), - registry: if *registry_name == DEFAULT_REGISTRY_NAME { - None - } else { - Some(registry_name.to_string()) - }, - requirement: dependency.version.clone(), - version: download.version.clone(), - digest: download.digest.clone(), - path: download.path.clone(), - }); - } - } - - assert_eq!(finished, count); - - progress.clear(); - } - - Ok(registries + for resolution in self + .registries .into_values() .flat_map(|r| r.dependencies.into_iter()) .map(|d| { DependencyResolution::Registry( d.resolution.expect("dependency should have been resolved"), ) - })) + }) + { + let prev = self + .resolutions + .insert(resolution.name().clone(), resolution); + assert!(prev.is_none()); + } + + Ok(self.resolutions) } } struct Registry<'a> { - client: Arc, - packages: HashMap, + client: Arc>, + packages: HashMap>, dependencies: Vec>, - upserts: HashSet, } impl<'a> Registry<'a> { async fn add_dependency( &mut self, - name: &'a registry::PackageName, - package: registry::PackageName, + name: &'a PackageRef, + package: PackageRef, version: &'a VersionReq, - registry: &str, locked: Option<&LockedPackageVersion>, ) -> Result<()> { let dep = RegistryDependency { @@ -719,56 +582,28 @@ impl<'a> Registry<'a> { self.dependencies.push(dep); - let mut needs_upsert = true; - if let Some(locked) = locked { - if let Some(package) = - Self::load_package(&self.client, &mut self.packages, package.clone()).await? - { - if package - .state - .release(&locked.version) - .and_then(|r| r.content()) - .is_some() - { - // Don't need to upsert this package as it is present - // in the lock file and in client storage. - needs_upsert = false; - } - } - } - - if needs_upsert && self.upserts.insert(package.clone()) { - log::info!( - "package `{package}` from component registry `{registry}` needs to be updated" - ); - } - Ok(()) } - async fn add_downloads( - &mut self, - registry: &'a str, - downloads: &mut DownloadMap<'a>, - ) -> Result<()> { - let Self { - dependencies, - packages, - client, - .. - } = self; - - for (index, dependency) in dependencies.iter_mut().enumerate() { - let package = Self::load_package(client, packages, dependency.package.clone()) - .await? - .with_context(|| { - format!( - "package `{name}` was not found in component registry `{registry}`", - name = dependency.package - ) - })?; + async fn resolve(&mut self, registry: &'a str) -> Result<()> { + for dependency in self.dependencies.iter_mut() { + // We need to clone a handle to the client because we mutably borrow self below. Might + // be worth replacing the mutable borrow with a RwLock down the line. + let client = self.client.clone(); + let versions = load_package( + &mut self.packages, + &self.client.client, + dependency.package.clone(), + ) + .await? + .with_context(|| { + format!( + "package `{name}` was not found in component registry `{registry}`", + name = dependency.package + ) + })?; - let release = match &dependency.locked { + let (selected_version, digest) = match &dependency.locked { Some((version, digest)) => { // The dependency had a lock file entry, so attempt to do an exact match first let exact_req = VersionReq { @@ -781,104 +616,86 @@ impl<'a> Registry<'a> { }], }; - // If an exact match can't be found, fallback to the latest release to - // satisfy the version requirement; this can happen when packages are yanked - package.state.find_latest_release(&exact_req).map(|r| { - // Exact match, verify the content digests match - let content = r.content().expect("release must have content"); - if content != digest { - bail!( - "component registry package `{name}` (v`{version}`) has digest `{content}` but the lock file specifies digest `{digest}`", - name = dependency.package, - ); - } - Ok(r) - }).transpose()?.or_else(|| package.state.find_latest_release(dependency.version)) + // If an exact match can't be found, fallback to the latest release to satisfy + // the version requirement; this can happen when packages are yanked. If we did + // find an exact match, return the digest for comparison after fetching the + // release + find_latest_release(versions, &exact_req).map(|v| (v, Some(digest))).or_else(|| find_latest_release(versions, dependency.version).map(|v| (v, None))) } - None => package.state.find_latest_release(dependency.version), + None => find_latest_release(versions, dependency.version).map(|v| (v, None)), }.with_context(|| format!("component registry package `{name}` has no release matching version requirement `{version}`", name = dependency.package, version = dependency.version))?; - - let digest = release.content().expect("release must have content"); - match client.content().content_location(digest) { - Some(path) => { - // Content is already present, set the resolution - assert!(dependency.resolution.is_none()); - dependency.resolution = Some(RegistryResolution { - name: dependency.name.clone(), - package: dependency.package.clone(), - registry: if registry == DEFAULT_REGISTRY_NAME { - None - } else { - Some(registry.to_string()) - }, - requirement: dependency.version.clone(), - version: release.version.clone(), - digest: digest.clone(), - path, - }); - - log::info!( - "version {version} of registry package `{name}` from registry `{registry}` is already in client storage", + // We need to clone a handle to the client because we mutably borrow self above. Might + // be worth replacing the mutable borrow with a RwLock down the line. + let release = client + .client + .get_release(&dependency.package, &selected_version.version) + .await?; + if let Some(digest) = digest { + if &release.content_digest != digest { + bail!( + "component registry package `{name}` (v`{version}`) has digest `{content}` but the lock file specifies digest `{digest}`", name = dependency.package, version = release.version, + content = release.content_digest, ); } - None => { - // Content needs to be downloaded - let indexes = downloads - .entry(( - registry, - dependency.package.clone(), - release.version.clone(), - )) - .or_default(); - - if indexes.is_empty() { - log::info!( - "version {version} of registry package `{name}` from registry `{registry}` needs to be downloaded", - name = dependency.package, - version = release.version, - ); - } - - indexes.push(index); - } } + + dependency.resolution = Some(RegistryResolution { + name: dependency.name.clone(), + package: dependency.package.clone(), + registry: if registry == DEFAULT_REGISTRY_NAME { + None + } else { + Some(registry.to_string()) + }, + requirement: dependency.version.clone(), + version: release.version.clone(), + digest: release.content_digest.clone(), + client: self.client.clone(), + }); } Ok(()) } +} - async fn load_package<'b>( - client: &FileSystemClient, - packages: &'b mut HashMap, - name: registry::PackageName, - ) -> Result> { - match packages.entry(name) { - hash_map::Entry::Occupied(e) => Ok(Some(e.into_mut())), - hash_map::Entry::Vacant(e) => match client.package(e.key()).await { - Ok(p) => Ok(Some(e.insert(p))), - Err(warg_client::ClientError::PackageDoesNotExist { .. }) => Ok(None), - Err(err) => Err(err.into()), - }, - } +async fn load_package<'b>( + packages: &'b mut HashMap>, + client: &Client, + package: PackageRef, +) -> Result>> { + match packages.entry(package) { + hash_map::Entry::Occupied(e) => Ok(Some(e.into_mut())), + hash_map::Entry::Vacant(e) => match client.list_all_versions(e.key()).await { + Ok(p) => Ok(Some(e.insert(p))), + Err(WasmPkgError::PackageNotFound) => Ok(None), + Err(err) => Err(err.into()), + }, } } -type DownloadMapKey<'a> = (&'a str, registry::PackageName, Version); -type DownloadMap<'a> = HashMap, Vec>; - struct RegistryDependency<'a> { /// The package name assigned in the configuration file. - name: &'a registry::PackageName, + name: &'a PackageRef, /// The package name of the registry package. - package: registry::PackageName, + package: PackageRef, version: &'a VersionReq, - locked: Option<(Version, AnyHash)>, + locked: Option<(Version, ContentDigest)>, resolution: Option, } /// Represents a map of dependency resolutions. /// /// The key to the map is the package name of the dependency. -pub type DependencyResolutionMap = HashMap; +pub type DependencyResolutionMap = HashMap; + +fn find_latest_release<'a>( + versions: &'a [VersionInfo], + req: &VersionReq, +) -> Option<&'a VersionInfo> { + versions + .iter() + .filter(|info| !info.yanked && req.matches(&info.version)) + .max_by(|a, b| a.version.cmp(&b.version)) +} diff --git a/crates/wit/Cargo.toml b/crates/wit/Cargo.toml index b2933524..da1b91bf 100644 --- a/crates/wit/Cargo.toml +++ b/crates/wit/Cargo.toml @@ -12,28 +12,29 @@ repository = { workspace = true } readme = "README.md" [dependencies] -cargo-component-core = { workspace = true } anyhow = { workspace = true } +bytes = { workspace = true } +cargo-component-core = { workspace = true } +clap = { workspace = true } +futures = { workspace = true } +indexmap = { workspace = true } +log = { workspace = true } +p256 = { workspace = true } +pretty_env_logger = { workspace = true } +rand_core = { workspace = true } +rpassword = { workspace = true } semver = { workspace = true } -url = { workspace = true } serde = { workspace = true } +tokio = { workspace = true } toml_edit = { workspace = true } -warg-protocol = { workspace = true } +url = { workspace = true } +wasm-pkg-client = { workspace = true } warg-client = { workspace = true } warg-crypto = { workspace = true } -log = { workspace = true } -clap = { workspace = true } -rpassword = { workspace = true } -rand_core = { workspace = true } -p256 = { workspace = true } -indexmap = { workspace = true } -wit-parser = { workspace = true } -wit-component = { workspace = true } +warg-protocol = { workspace = true } wasm-metadata = { workspace = true } -futures = { workspace = true } -bytes = { workspace = true } -tokio = { workspace = true } -pretty_env_logger = { workspace = true } +wit-component = { workspace = true } +wit-parser = { workspace = true } [dev-dependencies] assert_cmd = { workspace = true } diff --git a/crates/wit/src/commands/add.rs b/crates/wit/src/commands/add.rs index 93eb4611..86e0144d 100644 --- a/crates/wit/src/commands/add.rs +++ b/crates/wit/src/commands/add.rs @@ -1,25 +1,25 @@ -use crate::config::{Config, CONFIG_FILE_NAME}; +use std::path::PathBuf; + use anyhow::{bail, Context, Result}; use cargo_component_core::{ + cache_dir, command::CommonOptions, registry::{Dependency, DependencyResolution, DependencyResolver, RegistryPackage}, - terminal::Terminal, VersionedPackageName, }; use clap::Args; use semver::VersionReq; -use std::path::PathBuf; -use warg_protocol::registry::PackageName; +use wasm_pkg_client::{caching::FileCache, PackageRef}; + +use crate::config::{Config, CONFIG_FILE_NAME}; async fn resolve_version( - config: &Config, - warg_config: &warg_client::Config, + pkg_config: wasm_pkg_client::Config, package: &VersionedPackageName, registry: &Option, - terminal: &Terminal, + file_cache: FileCache, ) -> Result { - let mut resolver = - DependencyResolver::new(warg_config, &config.registries, None, terminal, true)?; + let mut resolver = DependencyResolver::new(pkg_config, None, file_cache); let dependency = Dependency::Package(RegistryPackage { name: Some(package.name.clone()), version: package @@ -63,7 +63,7 @@ pub struct AddCommand { /// The name of the dependency to use; defaults to the package name. #[clap(long, value_name = "NAME")] - pub name: Option, + pub name: Option, /// Add a package dependency to a file or directory. #[clap(long = "path", value_name = "PATH")] @@ -82,13 +82,23 @@ impl AddCommand { let (mut config, config_path) = Config::from_default_file()? .with_context(|| format!("failed to find configuration file `{CONFIG_FILE_NAME}`"))?; + let terminal = self.common.new_terminal(); + let pkg_config = if let Some(config_file) = self.common.config { + wasm_pkg_client::Config::from_file(&config_file).context(format!( + "failed to load configuration file from {}", + config_file.display() + ))? + } else { + wasm_pkg_client::Config::global_defaults()? + }; + + let file_cache = FileCache::new(cache_dir(self.common.cache_dir)?).await?; + let name = self.name.as_ref().unwrap_or(&self.package.name); if config.dependencies.contains_key(name) { bail!("cannot add dependency `{name}` as it conflicts with an existing dependency"); } - let warg_config = warg_client::Config::from_default_file()?.unwrap_or_default(); - let terminal = self.common.new_terminal(); let message = match self.path.as_deref() { Some(path) => { config @@ -102,14 +112,8 @@ impl AddCommand { ) } None => { - let version = resolve_version( - &config, - &warg_config, - &self.package, - &self.registry, - &terminal, - ) - .await?; + let version = + resolve_version(pkg_config, &self.package, &self.registry, file_cache).await?; let package = RegistryPackage { name: self.name.is_some().then(|| self.package.name.clone()), diff --git a/crates/wit/src/commands/build.rs b/crates/wit/src/commands/build.rs index cf672164..5887b8b4 100644 --- a/crates/wit/src/commands/build.rs +++ b/crates/wit/src/commands/build.rs @@ -1,11 +1,14 @@ +use std::{fs, path::PathBuf}; + +use anyhow::{Context, Result}; +use cargo_component_core::{cache_dir, command::CommonOptions}; +use clap::Args; +use wasm_pkg_client::caching::FileCache; + use crate::{ build_wit_package, config::{Config, CONFIG_FILE_NAME}, }; -use anyhow::{Context, Result}; -use cargo_component_core::command::CommonOptions; -use clap::Args; -use std::{fs, path::PathBuf}; /// Build a binary WIT package. #[derive(Args)] @@ -28,10 +31,19 @@ impl BuildCommand { let (config, config_path) = Config::from_default_file()? .with_context(|| format!("failed to find configuration file `{CONFIG_FILE_NAME}`"))?; - let warg_config = warg_client::Config::from_default_file()?.unwrap_or_default(); - let terminal = self.common.new_terminal(); - let (id, bytes) = build_wit_package(&config, &config_path, &warg_config, &terminal).await?; + let pkg_config = if let Some(config_file) = self.common.config { + wasm_pkg_client::Config::from_file(&config_file).context(format!( + "failed to load configuration file from {}", + config_file.display() + ))? + } else { + wasm_pkg_client::Config::global_defaults()? + }; + let file_cache = FileCache::new(cache_dir(self.common.cache_dir)?).await?; + + let (id, bytes) = + build_wit_package(&config, &config_path, pkg_config, &terminal, file_cache).await?; let output = self .output diff --git a/crates/wit/src/commands/publish.rs b/crates/wit/src/commands/publish.rs index 6141d149..58d2cd01 100644 --- a/crates/wit/src/commands/publish.rs +++ b/crates/wit/src/commands/publish.rs @@ -1,12 +1,14 @@ -use crate::{ - config::{Config, CONFIG_FILE_NAME}, - publish_wit_package, PublishOptions, -}; use anyhow::{Context, Result}; -use cargo_component_core::{command::CommonOptions, registry::find_url}; +use cargo_component_core::{cache_dir, command::CommonOptions, registry::find_url}; use clap::Args; use warg_crypto::signing::PrivateKey; use warg_protocol::registry::PackageName; +use wasm_pkg_client::caching::FileCache; + +use crate::{ + config::{Config, CONFIG_FILE_NAME}, + publish_wit_package, PublishOptions, +}; /// Publish a WIT package to a registry. #[derive(Args)] @@ -43,6 +45,15 @@ impl PublishCommand { let terminal = self.common.new_terminal(); let warg_config = warg_client::Config::from_default_file()?.unwrap_or_default(); + let pkg_config = if let Some(config_file) = self.common.config { + wasm_pkg_client::Config::from_file(&config_file).context(format!( + "failed to load configuration file from {}", + config_file.display() + ))? + } else { + wasm_pkg_client::Config::global_defaults()? + }; + let file_cache = FileCache::new(cache_dir(self.common.cache_dir)?).await?; let url = find_url( self.registry.as_deref(), @@ -63,6 +74,8 @@ impl PublishCommand { config: &config, config_path: &config_path, warg_config: &warg_config, + pkg_config, + cache: file_cache, url, signing_key, package: self.package.as_ref(), diff --git a/crates/wit/src/commands/update.rs b/crates/wit/src/commands/update.rs index c8f4b6e6..d183025c 100644 --- a/crates/wit/src/commands/update.rs +++ b/crates/wit/src/commands/update.rs @@ -1,7 +1,9 @@ -use crate::config::{Config, CONFIG_FILE_NAME}; use anyhow::{Context, Result}; -use cargo_component_core::command::CommonOptions; +use cargo_component_core::{cache_dir, command::CommonOptions}; use clap::Args; +use wasm_pkg_client::caching::FileCache; + +use crate::config::{Config, CONFIG_FILE_NAME}; /// Update dependencies as recorded in the lock file. #[derive(Args)] @@ -24,9 +26,25 @@ impl UpdateCommand { let (config, config_path) = Config::from_default_file()? .with_context(|| format!("failed to find configuration file `{CONFIG_FILE_NAME}`"))?; - let warg_config = warg_client::Config::from_default_file()?.unwrap_or_default(); - let terminal = self.common.new_terminal(); - crate::update_lockfile(&config, &config_path, &warg_config, &terminal, self.dry_run).await + let pkg_config = if let Some(config_file) = self.common.config { + wasm_pkg_client::Config::from_file(&config_file).context(format!( + "failed to load configuration file from {}", + config_file.display() + ))? + } else { + wasm_pkg_client::Config::global_defaults()? + }; + let file_cache = FileCache::new(cache_dir(self.common.cache_dir)?).await?; + + crate::update_lockfile( + &config, + &config_path, + pkg_config, + &terminal, + self.dry_run, + file_cache, + ) + .await } } diff --git a/crates/wit/src/config.rs b/crates/wit/src/config.rs index 16d19561..69442605 100644 --- a/crates/wit/src/config.rs +++ b/crates/wit/src/config.rs @@ -11,7 +11,7 @@ use std::{ }; use toml_edit::Item; use url::Url; -use warg_protocol::registry::PackageName; +use wasm_pkg_client::PackageRef; /// The default name of the configuration file. pub const CONFIG_FILE_NAME: &str = "wit.toml"; @@ -80,7 +80,7 @@ pub struct Config { pub version: Version, /// The package dependencies. #[serde(default, skip_serializing_if = "HashMap::is_empty")] - pub dependencies: HashMap, + pub dependencies: HashMap, /// The registries to use for sourcing packages. #[serde(default, skip_serializing_if = "HashMap::is_empty")] pub registries: HashMap, diff --git a/crates/wit/src/lib.rs b/crates/wit/src/lib.rs index 8b402948..76d571c5 100644 --- a/crates/wit/src/lib.rs +++ b/crates/wit/src/lib.rs @@ -17,6 +17,7 @@ use warg_client::storage::{ContentStorage, PublishEntry, PublishInfo}; use warg_crypto::signing::PrivateKey; use warg_protocol::registry; use wasm_metadata::{Link, LinkType, RegistryMetadata}; +use wasm_pkg_client::caching::FileCache; use wit_component::DecodedWasm; use wit_parser::{PackageId, PackageName, Resolve, UnresolvedPackage}; @@ -27,9 +28,10 @@ mod lock; async fn resolve_dependencies( config: &Config, config_path: &Path, - warg_config: &warg_client::Config, + pkg_config: wasm_pkg_client::Config, terminal: &Terminal, update_lock_file: bool, + file_cache: FileCache, ) -> Result { let file_lock = acquire_lock_file_ro(terminal, config_path)?; let lock_file = file_lock @@ -45,12 +47,10 @@ async fn resolve_dependencies( .transpose()?; let mut resolver = DependencyResolver::new( - warg_config, - &config.registries, + pkg_config, lock_file.as_ref().map(LockFileResolver::new), - terminal, - true, - )?; + file_cache, + ); for (name, dep) in &config.dependencies { resolver.add_dependency(name, dep).await?; @@ -78,7 +78,7 @@ async fn resolve_dependencies( Ok(map) } -fn parse_wit_package( +async fn parse_wit_package( dir: &Path, dependencies: &DependencyResolutionMap, ) -> Result<(Resolve, PackageId)> { @@ -87,7 +87,7 @@ fn parse_wit_package( // Start by decoding all of the dependencies let mut deps = IndexMap::new(); for (name, resolution) in dependencies { - let decoded = resolution.decode()?; + let decoded = resolution.decode().await?; if let Some(prev) = deps.insert(decoded.package_name().clone(), decoded) { bail!( "duplicate definitions of package `{prev}` found while decoding dependency `{name}`", @@ -222,15 +222,16 @@ fn parse_wit_package( async fn build_wit_package( config: &Config, config_path: &Path, - warg_config: &warg_client::Config, + pkg_config: wasm_pkg_client::Config, terminal: &Terminal, + file_cache: FileCache, ) -> Result<(registry::PackageName, Vec)> { let dependencies = - resolve_dependencies(config, config_path, warg_config, terminal, true).await?; + resolve_dependencies(config, config_path, pkg_config, terminal, true, file_cache).await?; let dir = config_path.parent().unwrap_or_else(|| Path::new(".")); - let (mut resolve, package) = parse_wit_package(dir, &dependencies)?; + let (mut resolve, package) = parse_wit_package(dir, &dependencies).await?; let pkg = &mut resolve.packages[package]; let name = format!("{ns}:{name}", ns = pkg.name.namespace, name = pkg.name.name).parse()?; @@ -255,11 +256,13 @@ struct PublishOptions<'a> { config: &'a Config, config_path: &'a Path, warg_config: &'a warg_client::Config, + pkg_config: wasm_pkg_client::Config, url: &'a str, signing_key: Option, package: Option<&'a registry::PackageName>, init: bool, dry_run: bool, + cache: FileCache, } fn add_registry_metadata(config: &Config, bytes: &[u8]) -> Result> { @@ -316,8 +319,9 @@ async fn publish_wit_package(options: PublishOptions<'_>, terminal: &Terminal) - let (name, bytes) = build_wit_package( options.config, options.config_path, - options.warg_config, + options.pkg_config, terminal, + options.cache, ) .await?; @@ -379,13 +383,13 @@ async fn publish_wit_package(options: PublishOptions<'_>, terminal: &Terminal) - pub async fn update_lockfile( config: &Config, config_path: &Path, - warg_config: &warg_client::Config, + pkg_config: wasm_pkg_client::Config, terminal: &Terminal, dry_run: bool, + file_cache: FileCache, ) -> Result<()> { // Resolve all dependencies as if the lock file does not exist - let mut resolver = - DependencyResolver::new(warg_config, &config.registries, None, terminal, true)?; + let mut resolver = DependencyResolver::new(pkg_config, None, file_cache); for (name, dep) in &config.dependencies { resolver.add_dependency(name, dep).await?; } diff --git a/crates/wit/src/lock.rs b/crates/wit/src/lock.rs index 59df150a..60a2cc76 100644 --- a/crates/wit/src/lock.rs +++ b/crates/wit/src/lock.rs @@ -1,4 +1,5 @@ //! Module for the lock file implementation. +use std::{collections::HashMap, path::Path}; use anyhow::Result; use cargo_component_core::{ @@ -7,9 +8,7 @@ use cargo_component_core::{ terminal::{Colors, Terminal}, }; use semver::Version; -use std::{collections::HashMap, path::Path}; -use warg_crypto::hash::AnyHash; -use warg_protocol::registry::PackageName; +use wasm_pkg_client::{ContentDigest, PackageRef}; /// The name of the lock file. pub const LOCK_FILE_NAME: &str = "wit.lock"; @@ -57,8 +56,8 @@ pub(crate) fn acquire_lock_file_rw(terminal: &Terminal, config_path: &Path) -> R /// Constructs a `LockFile` from a `DependencyResolutionMap`. pub fn to_lock_file(map: &DependencyResolutionMap) -> LockFile { - type PackageKey = (PackageName, Option); - type VersionsMap = HashMap; + type PackageKey = (PackageRef, Option); + type VersionsMap = HashMap; let mut packages: HashMap = HashMap::new(); for resolution in map.values() { diff --git a/crates/wit/tests/add.rs b/crates/wit/tests/add.rs index f4d87a35..c040f95d 100644 --- a/crates/wit/tests/add.rs +++ b/crates/wit/tests/add.rs @@ -1,16 +1,17 @@ -use crate::support::*; +use std::fs; + use anyhow::Result; use assert_cmd::prelude::*; use predicates::{prelude::*, str::contains}; -use std::{fs, rc::Rc}; -use tempfile::TempDir; + +use crate::support::*; mod support; #[test] fn help() { for arg in ["help add", "add -h", "add --help"] { - wit(arg) + wit(arg.split_whitespace()) .assert() .stdout(contains( "Adds a reference to a WIT package from a registry", @@ -21,7 +22,7 @@ fn help() { #[test] fn it_fails_with_missing_toml_file() -> Result<()> { - wit("add foo:bar") + wit(["add", "foo:bar"]) .assert() .stderr(contains( "error: failed to find configuration file `wit.toml`", @@ -32,7 +33,7 @@ fn it_fails_with_missing_toml_file() -> Result<()> { #[test] fn requires_package() { - wit("add") + wit(["add"]) .assert() .stderr(contains("wit add ")) .failure(); @@ -40,16 +41,14 @@ fn requires_package() { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn validate_the_package_exists() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, _, _) = spawn_server(["foo"]).await?; - let project = Project::with_dir(dir.clone(), "foo", "")?; + let project = server.project("foo", Vec::::new())?; project - .wit("add foo:bar") + .wit(["add", "foo:bar"]) .assert() - .stderr(contains("package `foo:bar` does not exist")) + .stderr(contains("package `foo:bar` was not found")) .failure(); Ok(()) @@ -57,22 +56,20 @@ async fn validate_the_package_exists() -> Result<()> { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn validate_the_version_exists() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, _, _) = spawn_server(Vec::::new()).await?; - let project = Project::with_dir(dir.clone(), "foo", "")?; + let project = server.project("foo", Vec::::new())?; project.file("foo.wit", "package test:bar;\n")?; project - .wit("publish --init") + .wit(["publish", "--init"]) .env("WIT_PUBLISH_KEY", test_signing_key()) .assert() .stderr(contains("Published package `test:bar` v0.1.0")) .success(); - let project = Project::with_dir(dir.clone(), "bar", "")?; + let project = server.project("bar", Vec::::new())?; project - .wit("add test:bar") + .wit(["add", "test:bar"]) .assert() .stderr(contains("Added dependency `test:bar` with version `0.1.0`")) .success(); @@ -81,7 +78,7 @@ async fn validate_the_version_exists() -> Result<()> { assert!(contains(r#""test:bar" = "0.1.0""#).eval(&manifest)); project - .wit("add --name test:bar2 test:bar@2.0.0") + .wit(["add", "--name", "test:bar2", "test:bar@2.0.0"]) .assert() .stderr(contains( "component registry package `test:bar` has no release matching version requirement `^2.0.0`", @@ -93,22 +90,20 @@ async fn validate_the_version_exists() -> Result<()> { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn checks_for_duplicate_dependencies() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, _, _) = spawn_server(Vec::::new()).await?; - let project = Project::with_dir(dir.clone(), "foo", "")?; + let project = server.project("foo", Vec::::new())?; project.file("foo.wit", "package test:bar;\n")?; project - .wit("publish --init") + .wit(["publish", "--init"]) .env("WIT_PUBLISH_KEY", test_signing_key()) .assert() .stderr(contains("Published package `test:bar` v0.1.0")) .success(); - let project = Project::with_dir(dir.clone(), "bar", "")?; + let project = server.project("bar", Vec::::new())?; project - .wit("add test:bar") + .wit(["add", "test:bar"]) .assert() .stderr(contains("Added dependency `test:bar` with version `0.1.0`")) .success(); @@ -117,7 +112,7 @@ async fn checks_for_duplicate_dependencies() -> Result<()> { assert!(contains(r#""test:bar" = "0.1.0""#).eval(&manifest)); project - .wit("add test:bar") + .wit(["add", "test:bar"]) .assert() .stderr(contains( "cannot add dependency `test:bar` as it conflicts with an existing dependency", @@ -129,22 +124,20 @@ async fn checks_for_duplicate_dependencies() -> Result<()> { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn does_not_modify_manifest_for_dry_run() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, _, _) = spawn_server(Vec::::new()).await?; - let project = Project::with_dir(dir.clone(), "foo", "")?; + let project = server.project("foo", Vec::::new())?; project.file("foo.wit", "package test:bar;\n")?; project - .wit("publish --init") + .wit(["publish", "--init"]) .env("WIT_PUBLISH_KEY", test_signing_key()) .assert() .stderr(contains("Published package `test:bar` v0.1.0")) .success(); - let project = Project::with_dir(dir.clone(), "bar", "")?; + let project = server.project("bar", Vec::::new())?; project - .wit("add test:bar --dry-run") + .wit(["add", "test:bar", "--dry-run"]) .assert() .stderr(contains( "Would add dependency `test:bar` with version `0.1.0` (dry run)", @@ -162,7 +155,7 @@ fn validate_add_from_path() -> Result<()> { let project = Project::new("foo")?; project - .wit("add --path foo/baz foo:baz") + .wit(["add", "--path", "foo/baz", "foo:baz"]) .assert() .stderr(contains("Added dependency `foo:baz` from path `foo/baz`")); diff --git a/crates/wit/tests/build.rs b/crates/wit/tests/build.rs index 83da4220..ad82c21f 100644 --- a/crates/wit/tests/build.rs +++ b/crates/wit/tests/build.rs @@ -1,15 +1,17 @@ -use crate::support::*; +use std::fs; + use anyhow::{Context, Result}; use assert_cmd::prelude::*; use predicates::str::contains; -use std::fs; + +use crate::support::*; mod support; #[test] fn help() { for arg in ["help build", "build -h", "build --help"] { - wit(arg) + wit(arg.split_whitespace()) .assert() .stdout(contains("Build a binary WIT package")) .success(); @@ -18,7 +20,7 @@ fn help() { #[test] fn it_fails_with_missing_toml_file() -> Result<()> { - wit("build") + wit(["build"]) .assert() .stderr(contains( "error: failed to find configuration file `wit.toml`", @@ -46,7 +48,7 @@ world baz-world {} )?; project - .wit("build") + .wit(["build"]) .assert() .stderr(contains("Created package `bar.wasm`")) .success(); @@ -74,7 +76,7 @@ fn it_adds_a_producers_field() -> Result<()> { project.file("producers.wit", "package test:producers;")?; project - .wit("build") + .wit(["build"]) .assert() .stderr(contains("Created package `producers.wasm`")) .success(); diff --git a/crates/wit/tests/init.rs b/crates/wit/tests/init.rs index c016811d..7b5bd0df 100644 --- a/crates/wit/tests/init.rs +++ b/crates/wit/tests/init.rs @@ -1,16 +1,18 @@ -use crate::support::*; +use std::{fs, path::Path}; + use anyhow::Result; use assert_cmd::prelude::*; use predicates::str::contains; -use std::{fs, path::Path}; use tempfile::TempDir; +use crate::support::*; + mod support; #[test] fn help() { for arg in ["help init", "init -h", "init --help"] { - wit(arg) + wit(arg.split_whitespace()) .assert() .stdout(contains("Initialize a new WIT package")) .success(); @@ -21,7 +23,7 @@ fn help() { fn it_creates_the_expected_files() -> Result<()> { let dir = TempDir::new()?; - wit("init foo") + wit(["init", "foo"]) .current_dir(dir.path()) .assert() .stderr(contains(format!( @@ -40,7 +42,7 @@ fn it_creates_the_expected_files() -> Result<()> { fn it_supports_registry_option() -> Result<()> { let dir = TempDir::new()?; - wit("init bar --registry https://example.com") + wit(["init", "bar", "--registry", "https://example.com"]) .current_dir(dir.path()) .assert() .stderr(contains(format!( diff --git a/crates/wit/tests/publish.rs b/crates/wit/tests/publish.rs index a2d3c2a6..83203385 100644 --- a/crates/wit/tests/publish.rs +++ b/crates/wit/tests/publish.rs @@ -1,22 +1,23 @@ -use std::{fs, rc::Rc}; +use std::fs; -use crate::support::*; use anyhow::{Context, Result}; use assert_cmd::prelude::*; use predicates::str::contains; use semver::Version; -use tempfile::TempDir; use toml_edit::{value, Array}; use warg_client::{Client, FileSystemClient}; use warg_protocol::registry::PackageName; use wasm_metadata::LinkType; +use wasm_pkg_client::warg::WargRegistryConfig; + +use crate::support::*; mod support; #[test] fn help() { for arg in ["help publish", "publish -h", "publish --help"] { - wit(arg) + wit(arg.split_whitespace()) .assert() .stdout(contains("Publish a WIT package to a registry")) .success(); @@ -25,7 +26,7 @@ fn help() { #[test] fn it_fails_with_missing_toml_file() -> Result<()> { - wit("publish") + wit(["publish"]) .assert() .stderr(contains( "error: failed to find configuration file `wit.toml`", @@ -36,14 +37,12 @@ fn it_fails_with_missing_toml_file() -> Result<()> { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn it_publishes_a_wit_package() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, _, _) = spawn_server(Vec::::new()).await?; - let project = Project::with_dir(dir.clone(), "foo", "")?; + let project = server.project("foo", Vec::::new())?; project.file("baz.wit", "package test:qux;\n")?; project - .wit("publish --init") + .wit(["publish", "--init"]) .env("WIT_PUBLISH_KEY", test_signing_key()) .assert() .stderr(contains("Published package `test:qux` v0.1.0")) @@ -54,14 +53,14 @@ async fn it_publishes_a_wit_package() -> Result<()> { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn it_does_a_dry_run_publish() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, config, registry) = spawn_server(Vec::::new()).await?; + let warg_config = + WargRegistryConfig::try_from(config.registry_config(®istry).unwrap()).unwrap(); - let project = Project::with_dir(dir.clone(), "foo", "")?; + let project = server.project("foo", Vec::::new())?; project.file("baz.wit", "package test:qux;\n")?; project - .wit("publish --init --dry-run") + .wit(["publish", "--init", "--dry-run"]) .env("WIT_PUBLISH_KEY", test_signing_key()) .assert() .stderr(contains( @@ -69,7 +68,7 @@ async fn it_does_a_dry_run_publish() -> Result<()> { )) .success(); - let client = FileSystemClient::new_with_config(None, &config, None).await?; + let client = FileSystemClient::new_with_config(None, &warg_config.client_config, None).await?; assert!(client .download(&"test:qux".parse().unwrap(), &"0.1.0".parse().unwrap()) @@ -83,9 +82,11 @@ async fn it_does_a_dry_run_publish() -> Result<()> { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn it_publishes_with_registry_metadata() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, config, registry) = spawn_server(Vec::::new()).await?; + let warg_config = + WargRegistryConfig::try_from(config.registry_config(®istry).unwrap()).unwrap(); + + let project = server.project("foo", Vec::::new())?; let authors = ["Jane Doe "]; let categories = ["wasm"]; @@ -95,7 +96,6 @@ async fn it_publishes_with_registry_metadata() -> Result<()> { let homepage = "https://example.com/home"; let repository = "https://example.com/repo"; - let project = Project::with_dir(dir.clone(), "foo", "")?; project.file("baz.wit", "package test:qux;\n")?; project.update_manifest(|mut doc| { @@ -110,13 +110,13 @@ async fn it_publishes_with_registry_metadata() -> Result<()> { })?; project - .wit("publish --init") + .wit(["publish", "--init"]) .env("WIT_PUBLISH_KEY", test_signing_key()) .assert() .stderr(contains("Published package `test:qux` v0.1.0")) .success(); - let client = Client::new_with_config(None, &config, None).await?; + let client = Client::new_with_config(None, &warg_config.client_config, None).await?; let download = client .download_exact(&PackageName::new("test:qux")?, &Version::parse("0.1.0")?) .await?; diff --git a/crates/wit/tests/support/mod.rs b/crates/wit/tests/support/mod.rs index 88744afd..e87fbedd 100644 --- a/crates/wit/tests/support/mod.rs +++ b/crates/wit/tests/support/mod.rs @@ -2,9 +2,12 @@ use anyhow::{bail, Context, Result}; use assert_cmd::prelude::OutputAssertExt; +use cargo_component_core::command::{CACHE_DIR_ENV_VAR, CONFIG_FILE_ENV_VAR}; use indexmap::IndexSet; use std::{ - env, fs, + env, + ffi::OsStr, + fs, path::{Path, PathBuf}, process::Command, rc::Rc, @@ -17,8 +20,12 @@ use toml_edit::DocumentMut; use warg_crypto::signing::PrivateKey; use warg_protocol::operator::NamespaceState; use warg_server::{policy::content::WasmContentPolicy, Config, Server}; +use wasm_pkg_client::Registry; use wasmparser::{Chunk, Encoding, Parser, Payload, Validator}; +const WARG_CONFIG_NAME: &str = "warg-config.json"; +const WASM_PKG_CONFIG_NAME: &str = "wasm-pkg-config.json"; + pub fn test_operator_key() -> &'static str { "ecdsa-p256:I+UlDo0HxyBBFeelhPPWmD+LnklOpqZDkrFP5VduASk=" } @@ -53,7 +60,11 @@ fn exclude_test_directories() -> Result<()> { Ok(()) } -pub fn wit(args: &str) -> Command { +pub fn wit(args: I) -> Command +where + I: IntoIterator, + S: AsRef, +{ let mut exe = std::env::current_exe().unwrap(); exe.pop(); // remove test exe name exe.pop(); // remove `deps` @@ -61,16 +72,37 @@ pub fn wit(args: &str) -> Command { exe.set_extension(std::env::consts::EXE_EXTENSION); let mut cmd = Command::new(&exe); - for arg in args.split_whitespace() { - cmd.arg(arg); - } + cmd.args(args); cmd } +// NOTE(thomastaylor312): This is basically a copy/paste of the same helper in the top level +// integration tests. Honestly we should just put this in the crates dir for everything to use in +// this repo, but this is how it was initially, so I am not going to change it for now. pub struct ServerInstance { task: Option>, shutdown: CancellationToken, + root: Rc, +} + +impl ServerInstance { + /// Returns a `Project` that is configured to use the server instance with the correct config. + pub fn project(&self, name: &str, additional_args: I) -> Result + where + I: IntoIterator, + S: Into, + { + let proj = Project { + dir: self.root.clone(), + root: self.root.path().join(name), + config_file: Some(self.root.path().join(WASM_PKG_CONFIG_NAME)), + }; + + proj.new_inner(name, additional_args)?; + + Ok(proj) + } } impl Drop for ServerInstance { @@ -82,17 +114,20 @@ impl Drop for ServerInstance { } } -/// Spawns a server as a background task. -pub async fn spawn_server(root: &Path) -> Result<(ServerInstance, warg_client::Config)> { +/// Spawns a server as a background task. This will start a +pub async fn spawn_server( + additional_namespaces: I, +) -> Result<(ServerInstance, wasm_pkg_client::Config, Registry)> +where + I: IntoIterator, + S: AsRef, +{ + let root = Rc::new(TempDir::new().context("failed to create temp dir")?); let shutdown = CancellationToken::new(); let config = Config::new( PrivateKey::decode(test_operator_key().to_string())?, - Some( - [("test".to_string(), NamespaceState::Defined)] - .into_iter() - .collect(), - ), - root.join("server"), + Some(vec![("test".to_string(), NamespaceState::Defined)]), + root.path().join("server"), ) .with_addr(([127, 0, 0, 1], 0)) .with_shutdown(shutdown.clone().cancelled_owned()) @@ -109,13 +144,14 @@ pub async fn spawn_server(root: &Path) -> Result<(ServerInstance, warg_client::C let instance = ServerInstance { task: Some(task), shutdown, + root: root.to_owned(), }; - let config = warg_client::Config { + let warg_config = warg_client::Config { home_url: Some(format!("http://{addr}")), - registries_dir: Some(root.join("registries")), - content_dir: Some(root.join("content")), - namespace_map_path: Some(root.join("namespaces")), + registries_dir: Some(root.path().join("registries")), + content_dir: Some(root.path().join("content")), + namespace_map_path: Some(root.path().join("namespaces")), keys: IndexSet::new(), keyring_auth: false, keyring_backend: None, @@ -124,40 +160,111 @@ pub async fn spawn_server(root: &Path) -> Result<(ServerInstance, warg_client::C disable_interactive: true, }; - Ok((instance, config)) + let config_file = root.path().join(WARG_CONFIG_NAME); + warg_config.write_to_file(&config_file)?; + + let mut config = wasm_pkg_client::Config::default(); + // We should probably update wasm-pkg-tools to use http for "localhost" or "127.0.0.1" + let registry: Registry = format!("localhost:{}", addr.port()).parse().unwrap(); + config.set_namespace_registry("test".parse().unwrap(), registry.clone()); + for ns in additional_namespaces { + config.set_namespace_registry(ns.as_ref().parse().unwrap(), registry.clone()); + } + let reg_conf = config.get_or_insert_registry_config_mut(®istry); + reg_conf.set_backend_type(Some("warg".to_string())); + reg_conf + .set_backend_config( + "warg", + wasm_pkg_client::warg::WargRegistryConfig { + client_config: warg_config, + auth_token: None, + config_file: Some(config_file), + }, + ) + .expect("Should be able to set backend config"); + + config.to_file(root.path().join(WASM_PKG_CONFIG_NAME))?; + + Ok((instance, config, registry)) } pub struct Project { dir: Rc, root: PathBuf, + config_file: Option, } impl Project { + /// Creates a new project with the given name and whether or not to create a library instead of + /// a binary. This should only be used if you want an "empty" project that doesn't have things + /// like warg config or wasm pkg tools config configured. If you want a project with a warg + /// config and wasm pkg tools config, use the `project` method of `ServerInstance`. pub fn new(name: &str) -> Result { let dir = TempDir::new()?; + let root = dir.path().join(name); + let proj = Self { + dir: Rc::new(dir), + root, + config_file: None, + }; - wit(&format!("init {name}")) - .current_dir(&dir) - .assert() - .try_success()?; + proj.new_inner(name, Vec::::new())?; - let root = dir.path().join(name); + Ok(proj) + } - Ok(Self { + /// Same as `new` but allows you to specify additional arguments to pass to `cargo component + /// new` + pub fn new_with_args(name: &str, additional_args: I) -> Result + where + I: IntoIterator, + S: Into, + { + let dir = TempDir::new()?; + let root = dir.path().join(name); + let proj = Self { dir: Rc::new(dir), root, - }) + config_file: None, + }; + + proj.new_inner(name, additional_args)?; + + Ok(proj) + } + + /// Same as `new` but uses the given temp directory instead of creating a new one. + pub fn with_dir(dir: Rc, name: &str, args: I) -> Result + where + I: IntoIterator, + S: Into, + { + let root = dir.path().join(name); + let proj = Self { + dir, + root, + config_file: None, + }; + + proj.new_inner(name, args)?; + + Ok(proj) } - pub fn with_dir(dir: Rc, name: &str, args: &str) -> Result { - wit(&format!("init {name} {args}")) - .current_dir(dir.as_ref()) + fn new_inner(&self, name: &str, additional_args: I) -> Result<()> + where + I: IntoIterator, + S: Into, + { + let mut args = vec!["init".to_string(), name.to_string()]; + args.extend(additional_args.into_iter().map(|arg| arg.into())); + + self.wit(args) + .current_dir(self.dir.path()) .assert() .try_success()?; - let root = dir.path().join(name); - - Ok(Self { dir, root }) + Ok(()) } pub fn file>(&self, path: B, body: &str) -> Result<&Self> { @@ -175,8 +282,25 @@ impl Project { &self.dir } - pub fn wit(&self, cmd: &str) -> Command { - let mut cmd = wit(cmd); + pub fn cache_dir(&self) -> PathBuf { + self.dir.path().join("cache") + } + + pub fn config_file(&self) -> Option<&Path> { + self.config_file.as_deref() + } + + pub fn wit(&self, args: I) -> Command + where + I: IntoIterator, + S: AsRef, + { + let mut cmd = wit(args); + // Set the cache dir and the config file env var for every command + if let Some(config_file) = self.config_file() { + cmd.env(CONFIG_FILE_ENV_VAR, config_file); + } + cmd.env(CACHE_DIR_ENV_VAR, self.cache_dir()); cmd.current_dir(&self.root); cmd } diff --git a/crates/wit/tests/update.rs b/crates/wit/tests/update.rs index 0a527d1b..f415d654 100644 --- a/crates/wit/tests/update.rs +++ b/crates/wit/tests/update.rs @@ -1,16 +1,17 @@ -use crate::support::*; +use std::fs; + use anyhow::Result; use assert_cmd::prelude::*; use predicates::{prelude::PredicateBooleanExt, str::contains, Predicate}; -use std::{fs, rc::Rc}; -use tempfile::TempDir; + +use crate::support::*; mod support; #[test] fn help() { for arg in ["help update", "update -h", "update --help"] { - wit(arg) + wit(arg.split_whitespace()) .assert() .stdout(contains("Update dependencies as recorded in the lock file")) .success(); @@ -19,7 +20,7 @@ fn help() { #[test] fn it_fails_with_missing_toml_file() -> Result<()> { - wit("update") + wit(["update"]) .assert() .stderr(contains( "error: failed to find configuration file `wit.toml`", @@ -30,35 +31,33 @@ fn it_fails_with_missing_toml_file() -> Result<()> { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn update_without_changes_is_a_noop() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, _, _) = spawn_server(Vec::::new()).await?; - let project = Project::with_dir(dir.clone(), "bar", "")?; + let project = server.project("bar", Vec::::new())?; project.file("bar.wit", "package test:bar;\n")?; project - .wit("publish --init") + .wit(["publish", "--init"]) .env("WIT_PUBLISH_KEY", test_signing_key()) .assert() .stderr(contains("Published package `test:bar` v0.1.0")) .success(); - let project = Project::with_dir(dir.clone(), "baz", "")?; + let project = server.project("baz", Vec::::new())?; project.file("baz.wit", "package test:baz;\n")?; project - .wit("add test:bar") + .wit(["add", "test:bar"]) .assert() .stderr(contains("Added dependency `test:bar` with version `0.1.0")) .success(); project - .wit("build") + .wit(["build"]) .assert() .success() .stderr(contains("Created package `baz.wasm`")); project - .wit("update") + .wit(["update"]) .assert() .success() .stderr(contains("test:bar").not()); @@ -68,47 +67,46 @@ async fn update_without_changes_is_a_noop() -> Result<()> { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn test_update_without_compatible_changes_is_a_noop() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, _, _) = spawn_server(Vec::::new()).await?; - let project = Project::with_dir(dir.clone(), "bar", "")?; - project.file("bar.wit", "package test:bar;\n")?; - project - .wit("publish --init") + let project1 = server.project("bar", Vec::::new())?; + project1.file("bar.wit", "package test:bar;\n")?; + + project1 + .wit(["publish", "--init"]) .env("WIT_PUBLISH_KEY", test_signing_key()) .assert() .stderr(contains("Published package `test:bar` v0.1.0")) .success(); - let project = Project::with_dir(dir.clone(), "baz", "")?; - project.file("baz.wit", "package test:baz;\n")?; - project - .wit("add test:bar") + let project2 = server.project("baz", Vec::::new())?; + project2.file("baz.wit", "package test:baz;\n")?; + project2 + .wit(["add", "test:bar"]) .assert() .stderr(contains("Added dependency `test:bar` with version `0.1.0")) .success(); - project - .wit("build") + project2 + .wit(["build"]) .assert() .success() .stderr(contains("Created package `baz.wasm`")); - fs::write( - dir.path().join("bar/wit.toml"), + project1.file( + "wit.toml", "version = \"1.0.0\"\n[dependencies]\n[registries]\n", )?; - wit("publish") + project1 + .wit(["publish"]) .env("WIT_PUBLISH_KEY", test_signing_key()) - .current_dir(dir.path().join("bar")) .assert() .stderr(contains("Published package `test:bar` v1.0.0")) .success(); - project - .wit("update") + project2 + .wit(["update"]) .assert() .success() .stderr(contains("test:bar").not()); @@ -118,57 +116,55 @@ async fn test_update_without_compatible_changes_is_a_noop() -> Result<()> { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn update_with_compatible_changes() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, _, _) = spawn_server(Vec::::new()).await?; - let project = Project::with_dir(dir.clone(), "bar", "")?; - project.file("bar.wit", "package test:bar;\n")?; - project.file( + let project1 = server.project("bar", Vec::::new())?; + project1.file("bar.wit", "package test:bar;\n")?; + project1.file( "wit.toml", "version = \"1.0.0\"\n[dependencies]\n[registries]\n", )?; - project - .wit("publish --init") + project1 + .wit(["publish", "--init"]) .env("WIT_PUBLISH_KEY", test_signing_key()) .assert() .stderr(contains("Published package `test:bar` v1.0.0")) .success(); - let project = Project::with_dir(dir.clone(), "baz", "")?; - project.file("baz.wit", "package test:baz;\n")?; - project - .wit("add test:bar") + let project2 = server.project("baz", Vec::::new())?; + project2.file("baz.wit", "package test:baz;\n")?; + project2 + .wit(["add", "test:bar"]) .assert() .stderr(contains("Added dependency `test:bar` with version `1.0.0")) .success(); - project - .wit("build") + project2 + .wit(["build"]) .assert() .success() .stderr(contains("Created package `baz.wasm`")); - fs::write( - dir.path().join("bar/wit.toml"), + project1.file( + "wit.toml", "version = \"1.1.0\"\n[dependencies]\n[registries]\n", )?; - wit("publish") + project1 + .wit(["publish"]) .env("WIT_PUBLISH_KEY", test_signing_key()) - .current_dir(dir.path().join("bar")) .assert() .stderr(contains("Published package `test:bar` v1.1.0")) .success(); - project - .wit("update") + project2 + .wit(["update"]) .assert() .success() .stderr(contains("Updating dependency `test:bar` v1.0.0 -> v1.1.0")); - let lock_file = fs::read_to_string(project.root().join("wit.lock"))?; + let lock_file = fs::read_to_string(project2.root().join("wit.lock"))?; assert!(contains("version = \"1.1.0\"").eval(&lock_file)); Ok(()) @@ -176,57 +172,59 @@ async fn update_with_compatible_changes() -> Result<()> { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn update_with_compatible_changes_is_noop_for_dryrun() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, _, _) = spawn_server(Vec::::new()).await?; - let project = Project::with_dir(dir.clone(), "bar", "")?; - project.file("bar.wit", "package test:bar;\n")?; - project.file( + let project1 = server.project("bar", Vec::::new())?; + project1.file("bar.wit", "package test:bar;\n")?; + project1.file( "wit.toml", "version = \"1.0.0\"\n[dependencies]\n[registries]\n", )?; - project - .wit("publish --init") + project1 + .wit(["publish", "--init"]) .env("WIT_PUBLISH_KEY", test_signing_key()) .assert() .stderr(contains("Published package `test:bar` v1.0.0")) .success(); - let project = Project::with_dir(dir.clone(), "baz", "")?; - project.file("baz.wit", "package test:baz;\n")?; - project - .wit("add test:bar") + let project2 = server.project("baz", Vec::::new())?; + project2.file("baz.wit", "package test:baz;\n")?; + project2 + .wit(["add", "test:bar"]) .assert() .stderr(contains("Added dependency `test:bar` with version `1.0.0")) .success(); - project - .wit("build") + project2 + .wit(["build"]) .assert() .success() .stderr(contains("Created package `baz.wasm`")); - fs::write( - dir.path().join("bar/wit.toml"), + project1.file( + "wit.toml", "version = \"1.1.0\"\n[dependencies]\n[registries]\n", )?; - wit("publish") + project1 + .wit(["publish"]) .env("WIT_PUBLISH_KEY", test_signing_key()) - .current_dir(dir.path().join("bar")) .assert() .stderr(contains("Published package `test:bar` v1.1.0")) .success(); - project.wit("update --dry-run").assert().success().stderr( - contains("Would update dependency `test:bar` v1.0.0 -> v1.1.0").and(contains( - "warning: not updating lock file due to --dry-run option", - )), - ); + project2 + .wit(["update", "--dry-run"]) + .assert() + .success() + .stderr( + contains("Would update dependency `test:bar` v1.0.0 -> v1.1.0").and(contains( + "warning: not updating lock file due to --dry-run option", + )), + ); - let lock_file = fs::read_to_string(project.root().join("wit.lock"))?; + let lock_file = fs::read_to_string(project2.root().join("wit.lock"))?; assert!(contains("version = \"1.1.0\"").not().eval(&lock_file)); Ok(()) @@ -234,11 +232,9 @@ async fn update_with_compatible_changes_is_noop_for_dryrun() -> Result<()> { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn update_with_changed_dependencies() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, _, _) = spawn_server(Vec::::new()).await?; - let project = Project::with_dir(dir.clone(), "bar", "")?; + let project = server.project("bar", Vec::::new())?; project.file("bar.wit", "package test:bar;\n")?; project.file( "wit.toml", @@ -246,13 +242,13 @@ async fn update_with_changed_dependencies() -> Result<()> { )?; project - .wit("publish --init") + .wit(["publish", "--init"]) .env("WIT_PUBLISH_KEY", test_signing_key()) .assert() .stderr(contains("Published package `test:bar` v1.0.0")) .success(); - let project = Project::with_dir(dir.clone(), "baz", "")?; + let project = server.project("baz", Vec::::new())?; project.file("baz.wit", "package test:baz;\n")?; project.file( "wit.toml", @@ -260,22 +256,22 @@ async fn update_with_changed_dependencies() -> Result<()> { )?; project - .wit("publish --init") + .wit(["publish", "--init"]) .env("WIT_PUBLISH_KEY", test_signing_key()) .assert() .stderr(contains("Published package `test:baz` v1.0.0")) .success(); - let project = Project::with_dir(dir.clone(), "qux", "")?; + let project = server.project("qux", Vec::::new())?; project.file("qux.wit", "package test:qux;\n")?; project - .wit("add test:bar") + .wit(["add", "test:bar"]) .assert() .stderr(contains("Added dependency `test:bar` with version `1.0.0")) .success(); project - .wit("build") + .wit(["build"]) .assert() .stderr(contains("Created package `qux.wasm`")) .success(); @@ -286,7 +282,7 @@ async fn update_with_changed_dependencies() -> Result<()> { )?; project - .wit("update") + .wit(["update"]) .assert() .stderr( contains("Removing dependency `test:bar` v1.0.0") @@ -295,7 +291,7 @@ async fn update_with_changed_dependencies() -> Result<()> { .success(); project - .wit("build") + .wit(["build"]) .assert() .stderr(contains("Created package `qux.wasm`")) .success(); diff --git a/crates/wit/tests/version.rs b/crates/wit/tests/version.rs index d17fc45d..b9d0d0d8 100644 --- a/crates/wit/tests/version.rs +++ b/crates/wit/tests/version.rs @@ -7,7 +7,7 @@ mod support; #[test] fn help() { for arg in ["-V", "--version"] { - wit(arg) + wit(arg.split_whitespace()) .assert() .stdout(contains(env!("CARGO_PKG_VERSION"))) .success(); diff --git a/src/bin/cargo-component.rs b/src/bin/cargo-component.rs index 49a700f9..7a5e74cf 100644 --- a/src/bin/cargo-component.rs +++ b/src/bin/cargo-component.rs @@ -1,10 +1,15 @@ +use std::path::PathBuf; + use anyhow::{bail, Result}; use cargo_component::{ commands::{AddCommand, NewCommand, PublishCommand, UpdateCommand}, config::{CargoArguments, Config}, load_component_metadata, load_metadata, run_cargo_command, }; -use cargo_component_core::terminal::{Color, Terminal, Verbosity}; +use cargo_component_core::{ + command::{CACHE_DIR_ENV_VAR, CONFIG_FILE_ENV_VAR}, + terminal::{Color, Terminal, Verbosity}, +}; use clap::{CommandFactory, Parser}; fn version() -> &'static str { @@ -144,17 +149,22 @@ async fn main() -> Result<()> { _ => { // Not a built-in command, run the cargo command let cargo_args = CargoArguments::parse()?; - let config = Config::new(Terminal::new( - if cargo_args.quiet { - Verbosity::Quiet - } else { - match cargo_args.verbose { - 0 => Verbosity::Normal, - _ => Verbosity::Verbose, - } - }, - cargo_args.color.unwrap_or_default(), - ))?; + let cache_dir = std::env::var(CACHE_DIR_ENV_VAR).map(PathBuf::from).ok(); + let config_file = std::env::var(CONFIG_FILE_ENV_VAR).map(PathBuf::from).ok(); + let config = Config::new( + Terminal::new( + if cargo_args.quiet { + Verbosity::Quiet + } else { + match cargo_args.verbose { + 0 => Verbosity::Normal, + _ => Verbosity::Verbose, + } + }, + cargo_args.color.unwrap_or_default(), + ), + config_file, + )?; let metadata = load_metadata(cargo_args.manifest_path.as_deref())?; let packages = load_component_metadata( @@ -171,7 +181,9 @@ async fn main() -> Result<()> { } let spawn_args: Vec<_> = std::env::args().skip(1).collect(); + let client = config.client(cache_dir).await?; if let Err(e) = run_cargo_command( + client, &config, &metadata, &packages, diff --git a/src/bindings.rs b/src/bindings.rs index b9b646cf..4d55ab12 100644 --- a/src/bindings.rs +++ b/src/bindings.rs @@ -1,21 +1,15 @@ //! Module for bindings generation. - -use crate::{ - last_modified_time, - metadata::{ComponentMetadata, Ownership}, - registry::PackageDependencyResolution, +use std::{ + collections::{HashMap, HashSet}, + path::{Path, PathBuf}, }; + use anyhow::{bail, Context, Result}; use cargo_component_core::registry::DecodedDependency; use heck::ToKebabCase; use indexmap::{IndexMap, IndexSet}; use semver::Version; -use std::{ - collections::{HashMap, HashSet}, - path::{Path, PathBuf}, - time::SystemTime, -}; -use warg_protocol::registry; +use wasm_pkg_client::PackageRef; use wit_bindgen_core::Files; use wit_bindgen_rust::Opts; use wit_component::DecodedWasm; @@ -24,6 +18,8 @@ use wit_parser::{ World, WorldId, WorldItem, WorldKey, }; +use crate::{metadata::Ownership, registry::PackageDependencyResolution}; + // Used to format `unlocked-dep` import names for dependencies on // other components. fn format_dep_import(package: &Package, name: Option<&str>, version: Option<&Version>) -> String { @@ -63,7 +59,6 @@ pub struct BindingsGenerator<'a> { resolution: &'a PackageDependencyResolution<'a>, resolve: Resolve, world: WorldId, - source_files: Vec, } impl<'a> BindingsGenerator<'a> { @@ -71,12 +66,13 @@ impl<'a> BindingsGenerator<'a> { /// and package dependency resolution. /// /// Returns a tuple of the bindings generator and a map of import names. - pub fn new( + pub async fn new( resolution: &'a PackageDependencyResolution<'a>, ) -> Result<(Self, HashMap)> { let mut import_name_map = Default::default(); - let (resolve, world, source_files) = - Self::create_target_world(resolution, &mut import_name_map).with_context(|| { + let (resolve, world, _) = Self::create_target_world(resolution, &mut import_name_map) + .await + .with_context(|| { format!( "failed to create a target world for package `{name}` ({path})", name = resolution.metadata.name, @@ -89,59 +85,11 @@ impl<'a> BindingsGenerator<'a> { resolution, resolve, world, - source_files, }, import_name_map, )) } - /// Gets the cargo metadata for the package that the bindings are for. - pub fn metadata(&self) -> &ComponentMetadata { - self.resolution.metadata - } - - /// Gets the reason for generating the bindings. - /// - /// If this returns `Ok(None)`, then the bindings are up-to-date and - /// do not need to be regenerated. - pub fn reason( - &self, - last_modified_exe: SystemTime, - last_modified_output: Option, - ) -> Result> { - let last_modified_output = match last_modified_output { - Some(time) => time, - None => return Ok(Some("the bindings have not been generated yet")), - }; - - let metadata = self.metadata(); - let exe_modified = last_modified_exe > last_modified_output; - let manifest_modified = metadata.modified_at > last_modified_output; - let target_modified = if let Some(path) = metadata.target_path() { - last_modified_time(&path)? > last_modified_output - } else { - false - }; - - if exe_modified - || manifest_modified - || target_modified - || self.dependencies_are_newer(last_modified_output)? - { - Ok(Some(if manifest_modified { - "the manifest was modified" - } else if target_modified { - "the target WIT package was modified" - } else if exe_modified { - "the cargo-component executable was modified" - } else { - "a dependency was modified" - })) - } else { - Ok(None) - } - } - /// Generates the bindings source for a package. pub fn generate(self) -> Result { let settings = &self.resolution.metadata.section.bindings; @@ -196,32 +144,8 @@ impl<'a> BindingsGenerator<'a> { Ok(sources[0].to_string()) } - fn dependencies_are_newer(&self, last_modified_output: SystemTime) -> Result { - for dep in &self.source_files { - if last_modified_time(dep)? > last_modified_output { - log::debug!( - "target source file `{path}` has been modified", - path = dep.display() - ); - return Ok(true); - } - } - - for (_, dep) in self.resolution.all() { - if last_modified_time(dep.path())? > last_modified_output { - log::debug!( - "dependency `{path}` has been modified", - path = dep.path().display() - ); - return Ok(true); - } - } - - Ok(false) - } - - fn create_target_world( - resolution: &PackageDependencyResolution, + async fn create_target_world( + resolution: &PackageDependencyResolution<'_>, import_name_map: &mut HashMap, ) -> Result<(Resolve, WorldId, Vec)> { log::debug!( @@ -230,22 +154,24 @@ impl<'a> BindingsGenerator<'a> { path = resolution.metadata.manifest_path.display() ); - let (mut merged, world_id, source_files) = - if let Some(name) = resolution.metadata.target_package() { - Self::target_package(resolution, name, resolution.metadata.target_world())? - } else if let Some(path) = resolution.metadata.target_path() { - Self::target_local_path(resolution, &path, resolution.metadata.target_world())? - } else { - let (merged, world) = Self::target_empty_world(resolution); - (merged, world, Vec::new()) - }; + let (mut merged, world_id, source_files) = if let Some(name) = + resolution.metadata.target_package() + { + Self::target_package(resolution, name, resolution.metadata.target_world()).await? + } else if let Some(path) = resolution.metadata.target_path() { + Self::target_local_path(resolution, &path, resolution.metadata.target_world()).await? + } else { + let (merged, world) = Self::target_empty_world(resolution); + (merged, world, Vec::new()) + }; // Merge all component dependencies as interface imports for (id, dependency) in &resolution.resolutions { log::debug!("importing component dependency `{id}`"); let (mut resolve, component_world_id) = dependency - .decode()? + .decode() + .await? .into_component_world() .with_context(|| format!("failed to decode component dependency `{id}`"))?; @@ -274,9 +200,9 @@ impl<'a> BindingsGenerator<'a> { Ok((merged, world_id, source_files)) } - fn target_package( - resolution: &PackageDependencyResolution, - name: ®istry::PackageName, + async fn target_package( + resolution: &PackageDependencyResolution<'_>, + name: &PackageRef, world: Option<&str>, ) -> Result<(Resolve, WorldId, Vec)> { // We must have resolved a target package dependency at this point @@ -284,12 +210,13 @@ impl<'a> BindingsGenerator<'a> { // Decode the target package dependency let dependency = resolution.target_resolutions.values().next().unwrap(); - let (resolve, pkg, source_files) = dependency.decode()?.resolve().with_context(|| { - format!( - "failed to resolve target package `{name}`", - name = dependency.name() - ) - })?; + let (resolve, pkg, source_files) = + dependency.decode().await?.resolve().with_context(|| { + format!( + "failed to resolve target package `{name}`", + name = dependency.name() + ) + })?; let world = resolve .select_world(pkg, world) @@ -298,8 +225,8 @@ impl<'a> BindingsGenerator<'a> { Ok((resolve, world, source_files)) } - fn target_local_path( - resolution: &PackageDependencyResolution, + async fn target_local_path( + resolution: &PackageDependencyResolution<'_>, path: &Path, world: Option<&str>, ) -> Result<(Resolve, WorldId, Vec)> { @@ -308,7 +235,7 @@ impl<'a> BindingsGenerator<'a> { // Start by decoding all of the target dependencies let mut deps = IndexMap::new(); for (id, resolution) in &resolution.target_resolutions { - let decoded = resolution.decode()?; + let decoded = resolution.decode().await?; let name = decoded.package_name(); if let Some(prev) = deps.insert(name.clone(), decoded) { diff --git a/src/commands/add.rs b/src/commands/add.rs index 794866f4..d6b86760 100644 --- a/src/commands/add.rs +++ b/src/commands/add.rs @@ -1,9 +1,9 @@ -use crate::{ - config::CargoPackageSpec, - load_component_metadata, load_metadata, - metadata::{ComponentMetadata, Target}, - Config, PackageComponentMetadata, +use std::{ + fs, + path::{Path, PathBuf}, + sync::Arc, }; + use anyhow::{bail, Context, Result}; use cargo_component_core::{ command::CommonOptions, @@ -13,12 +13,18 @@ use cargo_component_core::{ use cargo_metadata::Package; use clap::Args; use semver::VersionReq; -use std::{ - fs, - path::{Path, PathBuf}, -}; use toml_edit::{value, DocumentMut, InlineTable, Item, Table, Value}; -use warg_protocol::registry::PackageName; +use wasm_pkg_client::{ + caching::{CachingClient, FileCache}, + PackageRef, +}; + +use crate::{ + config::CargoPackageSpec, + load_component_metadata, load_metadata, + metadata::{ComponentMetadata, Target}, + Config, PackageComponentMetadata, +}; /// Add a dependency for a WebAssembly component #[derive(Args)] @@ -46,7 +52,7 @@ pub struct AddCommand { /// The name of the dependency to use; defaults to the package name. #[clap(long, value_name = "NAME")] - pub name: Option, + pub name: Option, /// The name of the package to add a dependency to. #[clap(value_name = "PACKAGE")] @@ -64,9 +70,11 @@ pub struct AddCommand { impl AddCommand { /// Executes the command pub async fn exec(self) -> Result<()> { - let config = Config::new(self.common.new_terminal())?; + let config = Config::new(self.common.new_terminal(), self.common.config.clone())?; let metadata = load_metadata(self.manifest_path.as_deref())?; + let client = config.client(self.common.cache_dir.clone()).await?; + let spec = match &self.spec { Some(spec) => Some(spec.clone()), None => CargoPackageSpec::find_current_package_spec(&metadata), @@ -104,7 +112,7 @@ impl AddCommand { ), )?; } else { - let version = self.resolve_version(&config, &metadata, name, true).await?; + let version = self.resolve_version(client, name).await?; let version = version.trim_start_matches('^'); self.add(package, version)?; @@ -119,18 +127,10 @@ impl AddCommand { async fn resolve_version( &self, - config: &Config, - metadata: &ComponentMetadata, - name: &PackageName, - network_allowed: bool, + client: Arc>, + name: &PackageRef, ) -> Result { - let mut resolver = DependencyResolver::new( - config.warg(), - &metadata.section.registries, - None, - config.terminal(), - network_allowed, - )?; + let mut resolver = DependencyResolver::new_with_client(client, None); let dependency = Dependency::Package(RegistryPackage { name: Some(self.package.name.clone()), version: self @@ -231,13 +231,15 @@ impl AddCommand { self.with_dependencies(pkg, |dependencies| { match self.name.as_ref() { Some(name) => { - dependencies[name.as_ref()] = value(InlineTable::from_iter([ + let str_name = name.to_string(); + dependencies[&str_name] = value(InlineTable::from_iter([ ("package", Value::from(self.package.name.to_string())), ("version", Value::from(version)), ])); } _ => { - dependencies[self.package.name.as_ref()] = value(version); + let str_name = self.package.name.to_string(); + dependencies[&str_name] = value(version); } } Ok(()) @@ -247,11 +249,11 @@ impl AddCommand { fn add_from_path(&self, pkg: &Package, path: &Path) -> Result<()> { self.with_dependencies(pkg, |dependencies| { let key = match self.name.as_ref() { - Some(name) => name.as_ref(), - None => self.package.name.as_ref(), + Some(name) => name.to_string(), + None => self.package.name.to_string(), }; - dependencies[key] = value(InlineTable::from_iter([( + dependencies[&key] = value(InlineTable::from_iter([( "path", Value::from(path.to_str().unwrap()), )])); @@ -260,7 +262,7 @@ impl AddCommand { }) } - fn validate(&self, metadata: &ComponentMetadata, name: &PackageName) -> Result<()> { + fn validate(&self, metadata: &ComponentMetadata, name: &PackageRef) -> Result<()> { if self.target { match &metadata.section.target { Target::Package { .. } => { diff --git a/src/commands/new.rs b/src/commands/new.rs index 0578d9ca..fb08a5ba 100644 --- a/src/commands/new.rs +++ b/src/commands/new.rs @@ -1,4 +1,11 @@ -use crate::{config::Config, generator::SourceGenerator, metadata, metadata::DEFAULT_WIT_DIR}; +use std::{ + borrow::Cow, + fs, + path::{Path, PathBuf}, + process::Command, + sync::Arc, +}; + use anyhow::{bail, Context, Result}; use cargo_component_core::{ command::CommonOptions, @@ -7,15 +14,10 @@ use cargo_component_core::{ use clap::Args; use heck::ToKebabCase; use semver::VersionReq; -use std::{ - borrow::Cow, - collections::HashMap, - fs, - path::{Path, PathBuf}, - process::Command, -}; use toml_edit::{table, value, DocumentMut, Item, Table, Value}; -use url::Url; +use wasm_pkg_client::caching::{CachingClient, FileCache}; + +use crate::{config::Config, generator::SourceGenerator, metadata, metadata::DEFAULT_WIT_DIR}; const WIT_BINDGEN_RT_CRATE: &str = "wit-bindgen-rt"; @@ -143,25 +145,22 @@ impl NewCommand { pub async fn exec(self) -> Result<()> { log::debug!("executing new command"); - let config = Config::new(self.common.new_terminal())?; + let config = Config::new(self.common.new_terminal(), self.common.config.clone())?; let name = PackageName::new(&self.namespace, self.name.as_deref(), &self.path)?; let out_dir = std::env::current_dir() .with_context(|| "couldn't get the current directory of the process")? .join(&self.path); - let registries = self.registries()?; let target: Option = match self.target.as_deref() { Some(s) if s.contains('@') => Some(s.parse()?), Some(s) => Some(format!("{s}@{version}", version = VersionReq::STAR).parse()?), None => None, }; - - let target = self - .resolve_target(&config, ®istries, target, true) - .await?; - let source = self.generate_source(&target)?; + let client = config.client(self.common.cache_dir.clone()).await?; + let target = self.resolve_target(client, target).await?; + let source = self.generate_source(&target).await?; let mut command = self.new_command(); match command.status() { @@ -175,7 +174,15 @@ impl NewCommand { } } - self.update_manifest(&config, &name, &out_dir, ®istries, &target)?; + let target = target.map(|(res, world)| { + match res { + DependencyResolution::Registry(reg) => (reg, world), + // This is unreachable because when we got the initial target, we made sure it was a + // registry target. + _ => unreachable!(), + } + }); + self.update_manifest(&config, &name, &out_dir, &target)?; self.create_source_file(&config, &out_dir, source.as_ref(), &target)?; self.create_targets_file(&name, &out_dir)?; self.create_editor_settings_file(&out_dir)?; @@ -222,7 +229,6 @@ impl NewCommand { config: &Config, name: &PackageName, out_dir: &Path, - registries: &HashMap, target: &Option<(RegistryResolution, Option)>, ) -> Result<()> { let manifest_path = out_dir.join("Cargo.toml"); @@ -287,14 +293,6 @@ impl NewCommand { component["dependencies"] = Item::Table(Table::new()); - if !registries.is_empty() { - let mut table = Table::new(); - for (name, url) in registries { - table[name] = value(url.as_str()); - } - component["registries"] = Item::Table(table); - } - if self.proxy { component["proxy"] = value(true); } @@ -339,15 +337,15 @@ impl NewCommand { self.bin || !self.lib } - fn generate_source( + async fn generate_source( &self, - target: &Option<(RegistryResolution, Option)>, + target: &Option<(DependencyResolution, Option)>, ) -> Result> { match target { Some((resolution, world)) => { let generator = - SourceGenerator::new(&resolution.name, &resolution.path, !self.no_rustfmt); - generator.generate(world.as_deref()).map(Into::into) + SourceGenerator::new(resolution, resolution.name(), !self.no_rustfmt); + generator.generate(world.as_deref()).await.map(Into::into) } None => { if self.is_command() { @@ -523,26 +521,20 @@ world example {{ } } + /// This will always return a registry resolution if it is `Some`, but we return the + /// `DependencyResolution` instead so we can actually resolve the dependency. async fn resolve_target( &self, - config: &Config, - registries: &HashMap, + client: Arc>, target: Option, - network_allowed: bool, - ) -> Result)>> { + ) -> Result)>> { match target { Some(metadata::Target::Package { name, package, world, }) => { - let mut resolver = DependencyResolver::new( - config.warg(), - registries, - None, - config.terminal(), - network_allowed, - )?; + let mut resolver = DependencyResolver::new_with_client(client, None); let dependency = Dependency::Package(package); resolver.add_dependency(&name, &dependency).await?; @@ -550,29 +542,15 @@ world example {{ let dependencies = resolver.resolve().await?; assert_eq!(dependencies.len(), 1); - match dependencies - .into_values() - .next() - .expect("expected a target resolution") - { - DependencyResolution::Registry(resolution) => Ok(Some((resolution, world))), - _ => unreachable!(), - } + Ok(Some(( + dependencies + .into_values() + .next() + .expect("expected a target resolution"), + world, + ))) } _ => Ok(None), } } - - fn registries(&self) -> Result> { - let mut registries = HashMap::new(); - - if let Some(url) = self.registry.as_deref() { - registries.insert( - "default".to_string(), - url.parse().context("failed to parse registry URL")?, - ); - } - - Ok(registries) - } } diff --git a/src/commands/publish.rs b/src/commands/publish.rs index 5e934096..4c8b8841 100644 --- a/src/commands/publish.rs +++ b/src/commands/publish.rs @@ -1,13 +1,16 @@ +use std::path::PathBuf; + +use anyhow::{bail, Context, Result}; +use cargo_component_core::{command::CommonOptions, registry::find_url}; +use clap::Args; +use warg_crypto::signing::PrivateKey; +use warg_protocol::registry::PackageName; + use crate::{ config::{CargoArguments, CargoPackageSpec, Config}, is_wasm_target, load_metadata, publish, run_cargo_command, PackageComponentMetadata, PublishOptions, }; -use anyhow::{bail, Context, Result}; -use cargo_component_core::{command::CommonOptions, registry::find_url}; -use clap::Args; -use std::path::PathBuf; -use warg_crypto::signing::PrivateKey; /// Publish a package to a registry. #[derive(Args)] @@ -79,7 +82,8 @@ impl PublishCommand { pub async fn exec(self) -> Result<()> { log::debug!("executing publish command"); - let config = Config::new(self.common.new_terminal())?; + let config = Config::new(self.common.new_terminal(), self.common.config.clone())?; + let client = config.client(self.common.cache_dir.clone()).await?; if let Some(target) = &self.target { if !is_wasm_target(target) { @@ -153,6 +157,7 @@ impl PublishCommand { let spawn_args = self.build_args()?; let outputs = run_cargo_command( + client, &config, &metadata, &packages, @@ -167,12 +172,13 @@ impl PublishCommand { len = outputs.len() ); } - + // Safe to unwrap here because we already know a PackageRef is valid + let package_name = PackageName::new(name.to_string()).unwrap(); let options = PublishOptions { package, registry_url, init: self.init, - name, + name: &package_name, version: &component_metadata.version, path: &outputs[0], signing_key, diff --git a/src/commands/update.rs b/src/commands/update.rs index 3f890b9c..a4fdf834 100644 --- a/src/commands/update.rs +++ b/src/commands/update.rs @@ -1,9 +1,10 @@ -use crate::{load_component_metadata, load_metadata, Config}; use anyhow::Result; use cargo_component_core::command::CommonOptions; use clap::Args; use std::path::PathBuf; +use crate::{load_component_metadata, load_metadata, Config}; + /// Update dependencies as recorded in the component lock file #[derive(Args)] #[clap(disable_version_flag = true)] @@ -37,17 +38,17 @@ impl UpdateCommand { /// Executes the command. pub async fn exec(self) -> Result<()> { log::debug!("executing update command"); - let config = Config::new(self.common.new_terminal())?; + let config = Config::new(self.common.new_terminal(), self.common.config)?; let metadata = load_metadata(self.manifest_path.as_deref())?; let packages = load_component_metadata(&metadata, [].iter(), true)?; - let network_allowed = !self.frozen && !self.offline; let lock_update_allowed = !self.frozen && !self.locked; + let client = config.client(self.common.cache_dir).await?; crate::update_lockfile( + client, &config, &metadata, &packages, - network_allowed, lock_update_allowed, self.locked, self.dry_run, diff --git a/src/config.rs b/src/config.rs index 3c880c2f..6743b5f1 100644 --- a/src/config.rs +++ b/src/config.rs @@ -19,14 +19,18 @@ //! to function. use anyhow::{anyhow, bail, Context, Result}; +use cargo_component_core::cache_dir; use cargo_component_core::terminal::{Color, Terminal}; use cargo_metadata::Metadata; use parse_arg::{iter_short, match_arg}; use semver::Version; use std::fmt; use std::str::FromStr; +use std::sync::Arc; use std::{collections::BTreeMap, fmt::Display, path::PathBuf}; use toml_edit::DocumentMut; +use wasm_pkg_client::caching::{CachingClient, FileCache}; +use wasm_pkg_client::Client; /// Represents a cargo package specifier. /// @@ -489,15 +493,22 @@ impl CargoArguments { pub struct Config { /// The warg client configuration. pub warg: warg_client::Config, + /// The package configuration to use + pub pkg_config: wasm_pkg_client::Config, /// The terminal to use. terminal: Terminal, } impl Config { /// Create a new `Config` with the given terminal. - pub fn new(terminal: Terminal) -> Result { + pub fn new(terminal: Terminal, config_path: Option) -> Result { + let pkg_config = match config_path { + Some(path) => wasm_pkg_client::Config::from_file(path)?, + None => wasm_pkg_client::Config::global_defaults()?, + }; Ok(Self { warg: warg_client::Config::from_default_file()?.unwrap_or_default(), + pkg_config, terminal, }) } @@ -507,10 +518,26 @@ impl Config { &self.warg } + /// Gets the package configuration. + pub fn pkg_config(&self) -> &wasm_pkg_client::Config { + &self.pkg_config + } + /// Gets a reference to the terminal for writing messages. pub fn terminal(&self) -> &Terminal { &self.terminal } + + /// Creates a [`Client`] from this configuration. + pub async fn client( + &self, + cache: Option, + ) -> anyhow::Result>> { + Ok(Arc::new(CachingClient::new( + Client::new(self.pkg_config.clone()), + FileCache::new(cache_dir(cache)?).await?, + ))) + } } #[cfg(test)] diff --git a/src/generator.rs b/src/generator.rs index 3391b5eb..61088688 100644 --- a/src/generator.rs +++ b/src/generator.rs @@ -1,21 +1,19 @@ //! A module for implementing the Rust source generator used for //! the `--target` option of the `new` command. - -use anyhow::{bail, Context, Result}; -use heck::{AsSnakeCase, ToSnakeCase, ToUpperCamelCase}; -use indexmap::{map::Entry, IndexMap, IndexSet}; use std::{ borrow::Cow, collections::{BTreeMap, BTreeSet}, fmt::{self, Write}, - fs, io::Read, - path::Path, process::{Command, Stdio}, }; -use warg_protocol::registry::PackageName; + +use anyhow::{bail, Context, Result}; +use cargo_component_core::registry::DependencyResolution; +use heck::{AsSnakeCase, ToSnakeCase, ToUpperCamelCase}; +use indexmap::{map::Entry, IndexMap, IndexSet}; +use wasm_pkg_client::PackageRef; use wit_bindgen_rust::to_rust_ident; -use wit_component::DecodedWasm; use wit_parser::{ Function, FunctionKind, Handle, Interface, Resolve, Type, TypeDef, TypeDefKind, TypeId, TypeOwner, World, WorldId, WorldItem, WorldKey, @@ -741,8 +739,8 @@ impl<'a> ImplementationGenerator<'a> { /// The generated source defines a component that will implement the expected /// export traits for the given world. pub struct SourceGenerator<'a> { - name: &'a PackageName, - path: &'a Path, + resolution: &'a DependencyResolution, + name: &'a PackageRef, format: bool, } @@ -751,13 +749,17 @@ impl<'a> SourceGenerator<'a> { /// a binary-encoded target wit package. /// /// If `format` is true, then `cargo fmt` will be run on the generated source. - pub fn new(name: &'a PackageName, path: &'a Path, format: bool) -> Self { - Self { name, path, format } + pub fn new(resolution: &'a DependencyResolution, name: &'a PackageRef, format: bool) -> Self { + Self { + resolution, + name, + format, + } } /// Generates the Rust source code for the given world. - pub fn generate(&self, world: Option<&str>) -> Result { - let (resolve, world) = self.decode(world)?; + pub async fn generate(&self, world: Option<&str>) -> Result { + let (resolve, world) = self.decode(world).await?; let mut names = ReservedNames::default(); let generator = ImplementationGenerator::new(&resolve, &resolve.worlds[world], &mut names); @@ -815,34 +817,14 @@ impl<'a> SourceGenerator<'a> { Ok(source) } - fn decode(&self, world: Option<&str>) -> Result<(Resolve, WorldId)> { - let bytes = fs::read(self.path).with_context(|| { - format!( - "failed to read the content of target package `{name}` path `{path}`", - name = self.name, - path = self.path.display() - ) - })?; - - let decoded = wit_component::decode(&bytes).with_context(|| { + async fn decode(&self, world: Option<&str>) -> Result<(Resolve, WorldId)> { + let (resolve, pkg_id, _) = self.resolution.decode().await?.resolve()?; + let world = resolve.select_world(pkg_id, world).with_context(|| { format!( - "failed to decode the content of target package `{name}` path `{path}`", - name = self.name, - path = self.path.display() + "failed to select world from target package `{name}`", + name = self.name ) })?; - - match decoded { - DecodedWasm::WitPackage(resolve, package) => { - let world = resolve.select_world(package, world).with_context(|| { - format!( - "failed to select world from target package `{name}`", - name = self.name - ) - })?; - Ok((resolve, world)) - } - DecodedWasm::Component(..) => bail!("target is not a WIT package"), - } + Ok((resolve, world)) } } diff --git a/src/lib.rs b/src/lib.rs index 56164c5c..f3e242e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,19 @@ #![deny(missing_docs)] -use crate::target::install_wasm32_wasip1; +use std::{ + borrow::Cow, + collections::HashMap, + env, + fmt::{self, Write}, + fs::{self, File}, + io::{BufRead, BufReader, Read, Seek, SeekFrom}, + path::{Path, PathBuf}, + process::{Command, Stdio}, + sync::Arc, + time::{Duration, SystemTime}, +}; + use anyhow::{bail, Context, Result}; use bindings::BindingsGenerator; use bytes::Bytes; @@ -13,31 +25,24 @@ use cargo_component_core::{ }; use cargo_config2::{PathAndArgs, TargetTripleRef}; use cargo_metadata::{Artifact, Message, Metadata, MetadataCommand, Package}; -use config::{CargoArguments, CargoPackageSpec, Config}; -use lock::{acquire_lock_file_ro, acquire_lock_file_rw}; -use metadata::ComponentMetadata; -use registry::{PackageDependencyResolution, PackageResolutionMap}; use semver::Version; use shell_escape::escape; -use std::{ - borrow::Cow, - collections::HashMap, - env, - fmt::{self, Write}, - fs::{self, File}, - io::{BufRead, BufReader, Read, Seek, SeekFrom}, - path::{Path, PathBuf}, - process::{Command, Stdio}, - time::{Duration, SystemTime}, -}; use tempfile::NamedTempFile; use warg_client::storage::{ContentStorage, PublishEntry, PublishInfo}; use warg_crypto::signing::PrivateKey; use warg_protocol::registry::PackageName; use wasm_metadata::{Link, LinkType, RegistryMetadata}; +use wasm_pkg_client::caching::{CachingClient, FileCache}; use wasmparser::{Parser, Payload}; use wit_component::ComponentEncoder; +use crate::target::install_wasm32_wasip1; + +use config::{CargoArguments, CargoPackageSpec, Config}; +use lock::{acquire_lock_file_ro, acquire_lock_file_rw}; +use metadata::ComponentMetadata; +use registry::{PackageDependencyResolution, PackageResolutionMap}; + mod bindings; pub mod commands; pub mod config; @@ -135,6 +140,7 @@ impl From<&str> for CargoCommand { /// /// Returns any relevant output components. pub async fn run_cargo_command( + client: Arc>, config: &Config, metadata: &Metadata, packages: &[PackageComponentMetadata<'_>], @@ -142,7 +148,7 @@ pub async fn run_cargo_command( cargo_args: &CargoArguments, spawn_args: &[String], ) -> Result> { - let import_name_map = generate_bindings(config, metadata, packages, cargo_args).await?; + let import_name_map = generate_bindings(client, config, metadata, packages, cargo_args).await?; let cargo_path = std::env::var("CARGO") .map(PathBuf::from) @@ -729,12 +735,12 @@ pub fn load_component_metadata<'a>( } async fn generate_bindings( + client: Arc>, config: &Config, metadata: &Metadata, packages: &[PackageComponentMetadata<'_>], cargo_args: &CargoArguments, ) -> Result>> { - let last_modified_exe = last_modified_time(&std::env::current_exe()?)?; let file_lock = acquire_lock_file_ro(config.terminal(), metadata)?; let lock_file = file_lock .as_ref() @@ -752,14 +758,13 @@ async fn generate_bindings( env::current_dir().with_context(|| "couldn't get the current directory of the process")?; let resolver = lock_file.as_ref().map(LockFileResolver::new); - let resolution_map = - create_resolution_map(config, packages, resolver, cargo_args.network_allowed()).await?; + let resolution_map = create_resolution_map(client, packages, resolver).await?; let mut import_name_map = HashMap::new(); for PackageComponentMetadata { package, .. } in packages { let resolution = resolution_map.get(&package.id).expect("missing resolution"); import_name_map.insert( package.name.clone(), - generate_package_bindings(config, resolution, last_modified_exe, &cwd).await?, + generate_package_bindings(config, resolution, &cwd).await?, ); } @@ -789,16 +794,15 @@ async fn generate_bindings( } async fn create_resolution_map<'a>( - config: &Config, + client: Arc>, packages: &'a [PackageComponentMetadata<'_>], lock_file: Option>, - network_allowed: bool, ) -> Result> { let mut map = PackageResolutionMap::default(); for PackageComponentMetadata { package, metadata } in packages { let resolution = - PackageDependencyResolution::new(config, metadata, lock_file, network_allowed).await?; + PackageDependencyResolution::new(client.clone(), metadata, lock_file).await?; map.insert(package.id.clone(), resolution); } @@ -809,7 +813,6 @@ async fn create_resolution_map<'a>( async fn generate_package_bindings( config: &Config, resolution: &PackageDependencyResolution<'_>, - last_modified_exe: SystemTime, cwd: &Path, ) -> Result> { if !resolution.metadata.section_present && resolution.metadata.target_path().is_none() { @@ -829,55 +832,39 @@ async fn generate_package_bindings( .join("src"); let bindings_path = output_dir.join("bindings.rs"); - let last_modified_output = bindings_path - .is_file() - .then(|| last_modified_time(&bindings_path)) - .transpose()?; - - let (generator, import_name_map) = BindingsGenerator::new(resolution)?; - match generator.reason(last_modified_exe, last_modified_output)? { - Some(reason) => { - log::debug!( - "generating bindings for package `{name}` at `{path}` because {reason}", - name = resolution.metadata.name, - path = bindings_path.display(), - ); + let (generator, import_name_map) = BindingsGenerator::new(resolution).await?; + log::debug!( + "generating bindings for package `{name}` at `{path}`", + name = resolution.metadata.name, + path = bindings_path.display(), + ); - config.terminal().status( - "Generating", - format!( - "bindings for {name} ({path})", - name = resolution.metadata.name, - path = bindings_path - .strip_prefix(cwd) - .unwrap_or(&bindings_path) - .display() - ), - )?; + config.terminal().status( + "Generating", + format!( + "bindings for {name} ({path})", + name = resolution.metadata.name, + path = bindings_path + .strip_prefix(cwd) + .unwrap_or(&bindings_path) + .display() + ), + )?; - let bindings = generator.generate()?; - fs::create_dir_all(&output_dir).with_context(|| { - format!( - "failed to create output directory `{path}`", - path = output_dir.display() - ) - })?; + let bindings = generator.generate()?; + fs::create_dir_all(&output_dir).with_context(|| { + format!( + "failed to create output directory `{path}`", + path = output_dir.display() + ) + })?; - fs::write(&bindings_path, bindings).with_context(|| { - format!( - "failed to write bindings file `{path}`", - path = bindings_path.display() - ) - })?; - } - None => { - log::debug!( - "existing bindings for package `{name}` at `{path}` is up-to-date", - name = resolution.metadata.name, - path = bindings_path.display(), - ); - } - } + fs::write(&bindings_path, bindings).with_context(|| { + format!( + "failed to write bindings file `{path}`", + path = bindings_path.display() + ) + })?; Ok(import_name_map) } @@ -1177,16 +1164,16 @@ pub async fn publish(config: &Config, options: &PublishOptions<'_>) -> Result<() /// /// This updates only `Cargo-component.lock`. pub async fn update_lockfile( + client: Arc>, config: &Config, metadata: &Metadata, packages: &[PackageComponentMetadata<'_>], - network_allowed: bool, lock_update_allowed: bool, locked: bool, dry_run: bool, ) -> Result<()> { // Read the current lock file and generate a new one - let map = create_resolution_map(config, packages, None, network_allowed).await?; + let map = create_resolution_map(client, packages, None).await?; let file_lock = acquire_lock_file_ro(config.terminal(), metadata)?; let orig_lock_file = file_lock diff --git a/src/metadata.rs b/src/metadata.rs index 486279bd..4eac2117 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -1,4 +1,11 @@ //! Module for component metadata representation in `Cargo.toml`. +use std::{ + borrow::Cow, + collections::HashMap, + path::{Path, PathBuf}, + str::FromStr, + time::SystemTime, +}; use anyhow::{bail, Context, Result}; use cargo_component_core::registry::{Dependency, RegistryPackage}; @@ -9,15 +16,8 @@ use serde::{ Deserialize, }; use serde_json::from_value; -use std::{ - borrow::Cow, - collections::HashMap, - path::{Path, PathBuf}, - str::FromStr, - time::SystemTime, -}; use url::Url; -use warg_protocol::registry::PackageName; +use wasm_pkg_client::PackageRef; /// The default directory to look for a target WIT file. pub const DEFAULT_WIT_DIR: &str = "wit"; @@ -133,7 +133,7 @@ pub enum Target { /// The target is a world from a registry package. Package { /// The name of the target package (e.g. `wasi:http`). - name: PackageName, + name: PackageRef, /// The registry package being targeted. package: RegistryPackage, /// The name of the world being targeted. @@ -158,13 +158,13 @@ pub enum Target { /// [select-world]: https://docs.rs/wit-parser/latest/wit_parser/struct.Resolve.html#method.select_world world: Option, /// The dependencies of the wit document being targeted. - dependencies: HashMap, + dependencies: HashMap, }, } impl Target { /// Gets the dependencies of the target. - pub fn dependencies(&self) -> Cow> { + pub fn dependencies(&self) -> Cow> { match self { Self::Package { name, package, .. } => Cow::Owned(HashMap::from_iter([( name.clone(), @@ -260,7 +260,7 @@ impl<'de> Deserialize<'de> for Target { world: Option, registry: Option, path: Option, - dependencies: HashMap, + dependencies: HashMap, } let entry = Entry::deserialize(MapAccessDeserializer::new(map))?; @@ -320,13 +320,13 @@ impl<'de> Deserialize<'de> for Target { #[serde(default, deny_unknown_fields)] pub struct ComponentSection { /// The package name of the component, for publishing. - pub package: Option, + pub package: Option, /// The world targeted by the component. pub target: Target, /// The path to the WASI adapter to use. pub adapter: Option, /// The dependencies of the component. - pub dependencies: HashMap, + pub dependencies: HashMap, /// The registries to use for the component. pub registries: HashMap, /// The configuration for bindings generation. @@ -433,7 +433,7 @@ impl ComponentMetadata { /// Gets the target package name. /// /// Returns `None` if the target is not a registry package. - pub fn target_package(&self) -> Option<&PackageName> { + pub fn target_package(&self) -> Option<&PackageRef> { match &self.section.target { Target::Package { name, .. } => Some(name), _ => None, diff --git a/src/registry.rs b/src/registry.rs index 640470ea..fe69a894 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -1,6 +1,6 @@ //! Module for interacting with component registries. +use std::{collections::HashMap, sync::Arc}; -use crate::{config::Config, metadata::ComponentMetadata}; use anyhow::Result; use cargo_component_core::{ lock::{LockFile, LockFileResolver, LockedPackage, LockedPackageVersion}, @@ -8,9 +8,12 @@ use cargo_component_core::{ }; use cargo_metadata::PackageId; use semver::Version; -use std::collections::HashMap; -use warg_crypto::hash::AnyHash; -use warg_protocol::registry::PackageName; +use wasm_pkg_client::{ + caching::{CachingClient, FileCache}, + ContentDigest, PackageRef, +}; + +use crate::metadata::ComponentMetadata; /// Represents a resolution of dependencies for a Cargo package. #[derive(Debug, Clone)] @@ -28,49 +31,36 @@ impl<'a> PackageDependencyResolution<'a> { /// /// Returns `Ok(None)` if the package is not a component package. pub async fn new( - config: &Config, + client: Arc>, metadata: &'a ComponentMetadata, lock_file: Option>, - network_allowed: bool, ) -> Result> { Ok(Self { metadata, - target_resolutions: Self::resolve_target_deps( - config, - metadata, - lock_file, - network_allowed, - ) - .await?, - resolutions: Self::resolve_deps(config, metadata, lock_file, network_allowed).await?, + target_resolutions: Self::resolve_target_deps(client.clone(), metadata, lock_file) + .await?, + resolutions: Self::resolve_deps(client, metadata, lock_file).await?, }) } /// Iterates over all dependency resolutions of the package. - pub fn all(&self) -> impl Iterator { + pub fn all(&self) -> impl Iterator { self.target_resolutions .iter() .chain(self.resolutions.iter()) } async fn resolve_target_deps( - config: &Config, + client: Arc>, metadata: &ComponentMetadata, lock_file: Option>, - network_allowed: bool, ) -> Result { let target_deps = metadata.section.target.dependencies(); if target_deps.is_empty() { return Ok(Default::default()); } - let mut resolver = DependencyResolver::new( - config.warg(), - &metadata.section.registries, - lock_file, - config.terminal(), - network_allowed, - )?; + let mut resolver = DependencyResolver::new_with_client(client, lock_file); for (name, dependency) in target_deps.iter() { resolver.add_dependency(name, dependency).await?; @@ -80,22 +70,15 @@ impl<'a> PackageDependencyResolution<'a> { } async fn resolve_deps( - config: &Config, + client: Arc>, metadata: &ComponentMetadata, lock_file: Option>, - network_allowed: bool, ) -> Result { if metadata.section.dependencies.is_empty() { return Ok(Default::default()); } - let mut resolver = DependencyResolver::new( - config.warg(), - &metadata.section.registries, - lock_file, - config.terminal(), - network_allowed, - )?; + let mut resolver = DependencyResolver::new_with_client(client, lock_file); for (name, dependency) in &metadata.section.dependencies { resolver.add_dependency(name, dependency).await?; @@ -129,8 +112,8 @@ impl<'a> PackageResolutionMap<'a> { /// Converts the resolution map into a lock file. pub fn to_lock_file(&self) -> LockFile { - type PackageKey = (PackageName, Option); - type VersionsMap = HashMap; + type PackageKey = (PackageRef, Option); + type VersionsMap = HashMap; let mut packages: HashMap = HashMap::new(); for resolution in self.0.values() { diff --git a/tests/add.rs b/tests/add.rs index 59ea0c2f..12d917e9 100644 --- a/tests/add.rs +++ b/tests/add.rs @@ -1,17 +1,20 @@ -use crate::support::*; +use std::{fs, rc::Rc}; + use anyhow::{Context, Result}; use assert_cmd::prelude::*; use predicates::{prelude::*, str::contains}; -use std::{fs, rc::Rc}; use tempfile::TempDir; use toml_edit::value; +use wasm_pkg_client::warg::WargRegistryConfig; + +use crate::support::*; mod support; #[test] fn help() { for arg in ["help add", "add -h", "add --help"] { - cargo_component(arg) + cargo_component(arg.split_whitespace()) .assert() .stdout(contains("Add a dependency for a WebAssembly component")) .success(); @@ -20,7 +23,7 @@ fn help() { #[test] fn requires_package() { - cargo_component("add") + cargo_component(["add"]) .assert() .stderr(contains("cargo component add ")) .failure(); @@ -28,16 +31,14 @@ fn requires_package() { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn validate_the_package_exists() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, _, _) = spawn_server(["foo"]).await?; - let project = Project::with_dir(dir.clone(), "foo", "")?; + let project = server.project("foo", true, Vec::::new())?; project - .cargo_component("add foo:bar") + .cargo_component(["add", "foo:bar"]) .assert() - .stderr(contains("package `foo:bar` does not exist")) + .stderr(contains("package `foo:bar` was not found")) .failure(); Ok(()) @@ -45,16 +46,25 @@ async fn validate_the_package_exists() -> Result<()> { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn validate_the_version_exists() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; - - publish_component(&config, "test:bar", "1.1.0", "(component)", true).await?; + let (server, config, registry) = spawn_server(Vec::::new()).await?; + + // NOTE(thomastaylor312): Once we have publishing in wasm_pkg_client, we won't need to get the config directly like this + let warg_config = + WargRegistryConfig::try_from(config.registry_config(®istry).unwrap()).unwrap(); + + publish_component( + &warg_config.client_config, + "test:bar", + "1.1.0", + "(component)", + true, + ) + .await?; - let project = Project::with_dir(dir.clone(), "foo", "")?; + let project = server.project("foo", true, Vec::::new())?; project - .cargo_component("add test:bar") + .cargo_component(["add", "test:bar"]) .assert() .stderr(contains("Added dependency `test:bar` with version `1.1.0`")) .success(); @@ -63,7 +73,7 @@ async fn validate_the_version_exists() -> Result<()> { assert!(contains(r#""test:bar" = "1.1.0""#).eval(&manifest)); project - .cargo_component("add --name test:bar2 test:bar@2.0.0") + .cargo_component(["add", "--name", "test:bar2", "test:bar@2.0.0"]) .assert() .stderr(contains( "component registry package `test:bar` has no release matching version requirement `^2.0.0`", @@ -75,19 +85,27 @@ async fn validate_the_version_exists() -> Result<()> { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn adds_dependencies_to_target_component() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, config, registry) = spawn_server(Vec::::new()).await?; + + let warg_config = + WargRegistryConfig::try_from(config.registry_config(®istry).unwrap()).unwrap(); - publish_component(&config, "test:bar", "1.1.0", "(component)", true).await?; + publish_component( + &warg_config.client_config, + "test:bar", + "1.1.0", + "(component)", + true, + ) + .await?; - let project = Project::with_dir(dir.clone(), "foo_target", "")?; + let project = server.project("foo_target", true, Vec::::new())?; let manifest = fs::read_to_string(project.root().join("Cargo.toml"))?; assert!(!contains("package.metadata.component.target.dependencies").eval(&manifest)); project - .cargo_component("add test:bar --target") + .cargo_component(["add", "test:bar", "--target"]) .assert() .stderr(contains("Added dependency `test:bar` with version `1.1.0`")); @@ -96,7 +114,7 @@ async fn adds_dependencies_to_target_component() -> Result<()> { assert!(contains("package.metadata.component.target.dependencies").eval(&manifest)); project - .cargo_component("add test:bar --target") + .cargo_component(["add", "test:bar", "--target"]) .assert() .stderr(contains( "cannot add dependency `test:bar` as it conflicts with an existing dependency", @@ -107,14 +125,14 @@ async fn adds_dependencies_to_target_component() -> Result<()> { #[test] fn checks_for_duplicate_dependencies() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; project.update_manifest(|mut doc| { doc["package"]["metadata"]["component"]["dependencies"]["foo:bar"] = value("1.2.3"); Ok(doc) })?; project - .cargo_component("add foo:bar") + .cargo_component(["add", "foo:bar"]) .assert() .stderr(contains( "cannot add dependency `foo:bar` as it conflicts with an existing dependency", @@ -126,16 +144,24 @@ fn checks_for_duplicate_dependencies() -> Result<()> { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn prints_modified_manifest_for_dry_run() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, config, registry) = spawn_server(Vec::::new()).await?; + + let warg_config = + WargRegistryConfig::try_from(config.registry_config(®istry).unwrap()).unwrap(); - publish_component(&config, "test:bar", "1.2.3", "(component)", true).await?; + publish_component( + &warg_config.client_config, + "test:bar", + "1.2.3", + "(component)", + true, + ) + .await?; - let project = Project::with_dir(dir.clone(), "foo", "")?; + let project = server.project("foo", true, Vec::::new())?; project - .cargo_component("add --dry-run test:bar") + .cargo_component(["add", "--dry-run", "test:bar"]) .assert() .stderr(contains( r#"Added dependency `test:bar` with version `1.2.3`"#, @@ -152,12 +178,12 @@ async fn prints_modified_manifest_for_dry_run() -> Result<()> { fn validate_add_from_path(project: &Project) -> Result<()> { project - .cargo_component("add --path foo/baz foo:baz") + .cargo_component(["add", "--path", "foo/baz", "foo:baz"]) .assert() .stderr(contains("Added dependency `foo:baz` from path `foo/baz`")); project - .cargo_component("add --target --path foo/qux foo:qux") + .cargo_component(["add", "--target", "--path", "foo/qux", "foo:qux"]) .assert() .stderr(contains("Added dependency `foo:qux` from path `foo/qux`")); @@ -169,7 +195,7 @@ fn validate_add_from_path(project: &Project) -> Result<()> { #[test] fn test_validate_add_from_path() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; validate_add_from_path(&project)?; Ok(()) } @@ -191,8 +217,8 @@ resolver = "2" cargo_workspace = cargo_workspace.display() ) })?; - let p1 = Project::with_dir(temp_dir.clone(), "foo", "")?; - let p2 = Project::with_dir(temp_dir.clone(), "bar", "")?; + let p1 = Project::with_dir(temp_dir.clone(), "foo", true, Vec::::new())?; + let p2 = Project::with_dir(temp_dir.clone(), "bar", true, Vec::::new())?; validate_add_from_path(&p1)?; validate_add_from_path(&p2)?; diff --git a/tests/bench.rs b/tests/bench.rs index 191186a2..72f61e17 100644 --- a/tests/bench.rs +++ b/tests/bench.rs @@ -1,8 +1,10 @@ -use crate::support::*; +use std::fs; + use anyhow::Result; use assert_cmd::prelude::*; use predicates::str::contains; -use std::fs; + +use crate::support::*; mod support; @@ -12,7 +14,7 @@ mod support; ignore = "test is currently failing in ci and needs to be debugged" )] fn it_runs_bench_with_basic_component() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; fs::write( project.root().join("wit/world.wit"), @@ -69,7 +71,7 @@ fn bench_recursive_fibonacci(b: &mut Bencher) { )?; project - .cargo_component("bench") + .cargo_component(["bench"]) .env("RUSTUP_TOOLCHAIN", "nightly") .assert() .stdout(contains("test bench_recursive_fibonacci ...")) diff --git a/tests/build.rs b/tests/build.rs index c1134763..9b622723 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -1,19 +1,21 @@ -use crate::support::*; +use std::{fs, process::Command, rc::Rc}; + use anyhow::{Context, Result}; use assert_cmd::prelude::*; use predicates::{prelude::PredicateBooleanExt, str::contains}; -use std::{fs, process::Command, rc::Rc}; use tempfile::TempDir; use toml_edit::{value, Array, Item, Table}; +use crate::support::*; + mod support; #[test] fn it_builds_debug() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; project - .cargo_component("build") + .cargo_component(["build"]) .assert() .stderr(contains( "Finished `dev` profile [unoptimized + debuginfo] target(s)", @@ -31,10 +33,10 @@ fn it_builds_debug() -> Result<()> { #[test] fn it_builds_a_bin_project_with_snake_case() -> Result<()> { - let project = Project::new_bin("hello_world")?; + let project = Project::new("hello_world", false)?; project - .cargo_component("build --release") + .cargo_component(["build", "--release"]) .assert() .stderr(contains("Finished `release` profile [optimized] target(s)")) .success(); @@ -46,10 +48,10 @@ fn it_builds_a_bin_project_with_snake_case() -> Result<()> { #[test] fn it_builds_a_bin_project() -> Result<()> { - let project = Project::new_bin("foo")?; + let project = Project::new("foo", false)?; project - .cargo_component("build --release") + .cargo_component(["build", "--release"]) .assert() .stderr(contains("Finished `release` profile [optimized] target(s)")) .success(); @@ -62,10 +64,7 @@ fn it_builds_a_bin_project() -> Result<()> { #[test] fn it_builds_a_workspace() -> Result<()> { let dir = Rc::new(TempDir::new()?); - let project = Project { - dir: dir.clone(), - root: dir.path().to_owned(), - }; + let project = Project::new_uninitialized(dir.clone(), dir.path().to_owned()); project.file( "baz/Cargo.toml", @@ -81,13 +80,13 @@ edition = "2021" project.file("baz/src/lib.rs", "")?; project - .cargo_component("new --lib foo") + .cargo_component(["new", "--lib", "foo"]) .assert() .stderr(contains("Updated manifest of package `foo`")) .success(); project - .cargo_component("new --lib bar") + .cargo_component(["new", "--lib", "bar"]) .assert() .stderr(contains("Updated manifest of package `bar`")) .success(); @@ -101,7 +100,7 @@ edition = "2021" )?; project - .cargo_component("build") + .cargo_component(["build"]) .assert() .stderr(contains( "Finished `dev` profile [unoptimized + debuginfo] target(s)", @@ -116,10 +115,10 @@ edition = "2021" #[test] fn it_supports_wit_keywords() -> Result<()> { - let project = Project::new("interface")?; + let project = Project::new("interface", true)?; project - .cargo_component("build --release") + .cargo_component(["build", "--release"]) .assert() .stderr(contains("Finished `release` profile [optimized] target(s)")) .success(); @@ -131,10 +130,10 @@ fn it_supports_wit_keywords() -> Result<()> { #[test] fn it_adds_a_producers_field() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; project - .cargo_component("build --release") + .cargo_component(["build", "--release"]) .assert() .stderr(contains("Finished `release` profile [optimized] target(s)")) .success(); @@ -161,10 +160,10 @@ fn it_adds_a_producers_field() -> Result<()> { #[test] fn it_builds_wasm32_unknown_unknown_from_cli() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; project - .cargo_component("build --target wasm32-unknown-unknown") + .cargo_component(["build", "--target", "wasm32-unknown-unknown"]) .assert() .stderr(contains( "Finished `dev` profile [unoptimized + debuginfo] target(s)", @@ -184,7 +183,7 @@ fn it_builds_wasm32_unknown_unknown_from_cli() -> Result<()> { #[test] fn it_builds_wasm32_unknown_unknown_from_config() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; project.file( ".cargo/config.toml", @@ -194,7 +193,7 @@ target = "wasm32-unknown-unknown" )?; project - .cargo_component("build") + .cargo_component(["build"]) .assert() .stderr(contains( "Finished `dev` profile [unoptimized + debuginfo] target(s)", @@ -214,10 +213,10 @@ target = "wasm32-unknown-unknown" #[test] fn it_builds_wasm32_unknown_unknown_from_env() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; project - .cargo_component("build") + .cargo_component(["build"]) .env("CARGO_BUILD_TARGET", "wasm32-unknown-unknown") .assert() .stderr(contains( @@ -238,14 +237,14 @@ fn it_builds_wasm32_unknown_unknown_from_env() -> Result<()> { #[test] fn it_regenerates_target_if_wit_changed() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; project.update_manifest(|mut doc| { doc["package"]["metadata"]["component"]["target"]["world"] = value("example"); Ok(doc) })?; project - .cargo_component("build") + .cargo_component(["build"]) .assert() .stderr(contains( "Finished `dev` profile [unoptimized + debuginfo] target(s)", @@ -254,16 +253,10 @@ fn it_regenerates_target_if_wit_changed() -> Result<()> { validate_component(&project.debug_wasm("foo"))?; - project - .cargo_component("build") - .assert() - .stderr(contains("Generating bindings").not()) - .success(); - fs::write(project.root().join("wit/other.wit"), "world foo {}")?; project - .cargo_component("build") + .cargo_component(["build"]) .assert() .stderr(contains("Generating bindings")) .success(); @@ -273,7 +266,7 @@ fn it_regenerates_target_if_wit_changed() -> Result<()> { #[test] fn it_builds_with_local_wit_deps() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; project.update_manifest(|mut doc| { let mut dependencies = Table::new(); dependencies["foo:bar"]["path"] = value("wit/deps/foo-bar"); @@ -353,7 +346,7 @@ bindings::export!(Component with_types_in bindings); )?; project - .cargo_component("build") + .cargo_component(["build"]) .assert() .stderr(contains( "Finished `dev` profile [unoptimized + debuginfo] target(s)", @@ -367,7 +360,7 @@ bindings::export!(Component with_types_in bindings); #[test] fn empty_world_with_dep_valid() -> Result<()> { - let project = Project::new("dep")?; + let project = Project::new("dep", true)?; fs::write( project.root().join("wit/world.wit"), @@ -402,12 +395,12 @@ fn empty_world_with_dep_valid() -> Result<()> { ", )?; - project.cargo_component("build").assert().success(); + project.cargo_component(["build"]).assert().success(); let dep = project.debug_wasm("dep"); validate_component(&dep)?; - let project = Project::with_dir(project.dir().clone(), "main", "")?; + let project = Project::with_dir(project.dir().clone(), "main", true, Vec::::new())?; project.update_manifest(|mut doc| { let table = doc["package"]["metadata"]["component"] .as_table_mut() @@ -435,7 +428,7 @@ fn empty_world_with_dep_valid() -> Result<()> { ", )?; - project.cargo_component("build").assert().success(); + project.cargo_component(["build"]).assert().success(); validate_component(&project.debug_wasm("main"))?; Ok(()) @@ -443,7 +436,7 @@ fn empty_world_with_dep_valid() -> Result<()> { #[test] fn it_builds_with_resources() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; fs::write( project.root().join("wit/world.wit"), @@ -501,7 +494,7 @@ fn it_builds_with_resources() -> Result<()> { "#, )?; - project.cargo_component("build").assert().success(); + project.cargo_component(["build"]).assert().success(); let dep = project.debug_wasm("foo"); validate_component(&dep)?; @@ -511,7 +504,7 @@ fn it_builds_with_resources() -> Result<()> { #[test] fn it_builds_resources_with_specified_ownership_model() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; project.update_manifest(|mut doc| { doc["package"]["metadata"]["component"]["bindings"]["ownership"] = value("borrowing-duplicate-if-necessary"); @@ -574,7 +567,7 @@ fn it_builds_resources_with_specified_ownership_model() -> Result<()> { "#, )?; - project.cargo_component("build").assert().success(); + project.cargo_component(["build"]).assert().success(); let dep = project.debug_wasm("foo"); validate_component(&dep)?; @@ -584,8 +577,7 @@ fn it_builds_resources_with_specified_ownership_model() -> Result<()> { #[test] fn it_builds_with_a_component_dependency() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let comp1 = Project::with_dir(dir.clone(), "comp1", "")?; + let comp1 = Project::new("comp1", true)?; fs::write( comp1.root().join("wit/world.wit"), @@ -642,7 +634,7 @@ bindings::export!(Component with_types_in bindings); )?; comp1 - .cargo_component("build --release") + .cargo_component(["build", "--release"]) .assert() .stderr(contains("Finished `release` profile [optimized] target(s)")) .success(); @@ -650,7 +642,7 @@ bindings::export!(Component with_types_in bindings); let dep = comp1.release_wasm("comp1"); validate_component(&dep)?; - let comp2 = Project::with_dir(dir.clone(), "comp2", "")?; + let comp2 = Project::with_dir(comp1.dir.clone(), "comp2", true, Vec::::new())?; comp2.update_manifest(|mut doc| { doc["package"]["metadata"]["component"]["dependencies"]["my:comp1"]["path"] = value(dep.display().to_string()); @@ -689,7 +681,7 @@ bindings::export!(Component with_types_in bindings); )?; comp2 - .cargo_component("build --release") + .cargo_component(["build", "--release"]) .assert() .stderr(contains("Finished `release` profile [optimized] target(s)")) .success(); @@ -702,19 +694,19 @@ bindings::export!(Component with_types_in bindings); #[test] fn it_builds_with_adapter() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; project.update_manifest(|mut doc| { doc["package"]["metadata"]["component"]["adapter"] = value("not-a-valid-path"); Ok(doc) })?; project - .cargo_component("build") + .cargo_component(["build"]) .assert() .stderr(contains("error: failed to read module adapter")) .failure(); - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; project.update_manifest(|mut doc| { doc["package"]["metadata"]["component"]["adapter"] = value(adapter_path().to_str().unwrap()); @@ -722,7 +714,7 @@ fn it_builds_with_adapter() -> Result<()> { })?; project - .cargo_component("build") + .cargo_component(["build"]) .assert() .stderr(contains( "Finished `dev` profile [unoptimized + debuginfo] target(s)", @@ -736,7 +728,7 @@ fn it_builds_with_adapter() -> Result<()> { #[test] fn it_errors_if_adapter_is_not_wasm() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; project.update_manifest(|mut doc| { doc["package"]["metadata"]["component"]["adapter"] = value("foo.wasm"); Ok(doc) @@ -745,7 +737,7 @@ fn it_errors_if_adapter_is_not_wasm() -> Result<()> { fs::write(project.root().join("foo.wasm"), "not wasm")?; project - .cargo_component("build") + .cargo_component(["build"]) .assert() .stderr(contains("error: failed to load adapter module")) .failure(); @@ -755,7 +747,7 @@ fn it_errors_if_adapter_is_not_wasm() -> Result<()> { #[test] fn it_adds_additional_derives() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; project.update_manifest(|mut doc| { doc["package"]["metadata"]["component"]["bindings"]["derives"] = value(Array::from_iter(["serde::Serialize", "serde::Deserialize"])); @@ -815,7 +807,7 @@ bindings::export!(Component with_types_in bindings); )?; project - .cargo_component("build") + .cargo_component(["build"]) .assert() .stderr(contains( "Finished `dev` profile [unoptimized + debuginfo] target(s)", @@ -829,7 +821,7 @@ bindings::export!(Component with_types_in bindings); #[test] fn it_builds_with_versioned_wit() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; fs::write( project.root().join("wit/world.wit"), @@ -862,7 +854,7 @@ fn it_builds_with_versioned_wit() -> Result<()> { "#, )?; - project.cargo_component("build").assert().success(); + project.cargo_component(["build"]).assert().success(); let dep = project.debug_wasm("foo"); validate_component(&dep)?; @@ -872,14 +864,14 @@ fn it_builds_with_versioned_wit() -> Result<()> { #[test] fn it_warns_on_proxy_setting_for_command() -> Result<()> { - let project = Project::new_bin("foo")?; + let project = Project::new("foo", false)?; project.update_manifest(|mut doc| { doc["package"]["metadata"]["component"]["proxy"] = value(true); Ok(doc) })?; project - .cargo_component("build") + .cargo_component(["build"]) .assert() .stderr(contains( "warning: ignoring `proxy` setting in `Cargo.toml` for command component", @@ -893,7 +885,7 @@ fn it_warns_on_proxy_setting_for_command() -> Result<()> { #[test] fn it_warns_with_proxy_and_adapter_settings() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; project.update_manifest(|mut doc| { doc["package"]["metadata"]["component"]["proxy"] = value(true); doc["package"]["metadata"]["component"]["adapter"] = @@ -902,7 +894,7 @@ fn it_warns_with_proxy_and_adapter_settings() -> Result<()> { })?; project - .cargo_component("build") + .cargo_component(["build"]) .assert() .stderr(contains("warning: ignoring `proxy` setting due to `adapter` setting being present in `Cargo.toml`")) .success(); @@ -914,11 +906,10 @@ fn it_warns_with_proxy_and_adapter_settings() -> Result<()> { #[test] fn it_builds_with_proxy_adapter() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let project = Project::with_dir(dir.clone(), "foo", "--proxy")?; + let project = Project::new_with_args("foo", true, ["--proxy"])?; project - .cargo_component("build") + .cargo_component(["build"]) .assert() .stderr(contains( "Finished `dev` profile [unoptimized + debuginfo] target(s)", @@ -947,7 +938,7 @@ fn it_does_not_generate_bindings_for_cargo_projects() -> Result<()> { cmd.arg(name); cmd.assert().stderr(contains("Creating")).success(); - let mut cmd = cargo_component("build"); + let mut cmd = cargo_component(["build"]); cmd.current_dir(dir.path().join(name)); cmd.assert() .stderr(contains("Generating bindings").not()) diff --git a/tests/check.rs b/tests/check.rs index 4cd9ee61..72bfb2cd 100644 --- a/tests/check.rs +++ b/tests/check.rs @@ -1,18 +1,20 @@ -use crate::support::*; +use std::{fmt::Write, fs, rc::Rc}; + use anyhow::Result; use assert_cmd::prelude::*; use predicates::{boolean::PredicateBooleanExt, str::contains}; -use std::{fmt::Write, fs, rc::Rc}; use tempfile::TempDir; +use crate::support::*; + mod support; #[test] fn it_checks_a_new_project() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; project - .cargo_component("check") + .cargo_component(["check"]) .assert() .stderr(contains("Checking foo v0.1.0")) .success(); @@ -22,7 +24,7 @@ fn it_checks_a_new_project() -> Result<()> { #[test] fn it_finds_errors() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; let mut src = fs::read_to_string(project.root().join("src/lib.rs"))?; write!(&mut src, "\n\nfn foo() -> String {{\n \"foo\"\n}}\n")?; @@ -30,7 +32,7 @@ fn it_finds_errors() -> Result<()> { fs::write(project.root().join("src/lib.rs"), src)?; project - .cargo_component("check") + .cargo_component(["check"]) .assert() .stderr(contains("Checking foo v0.1.0").and(contains("expected `String`, found `&str`"))) .failure(); @@ -41,10 +43,8 @@ fn it_finds_errors() -> Result<()> { #[test] fn it_checks_a_workspace() -> Result<()> { let dir = Rc::new(TempDir::new()?); - let project = Project { - dir: dir.clone(), - root: dir.path().to_owned(), - }; + let root = dir.path().to_owned(); + let project = Project::new_uninitialized(dir, root); project.file( "baz/Cargo.toml", @@ -60,13 +60,13 @@ edition = "2021" project.file("baz/src/lib.rs", "")?; project - .cargo_component("new --lib foo") + .cargo_component(["new", "--lib", "foo"]) .assert() .stderr(contains("Updated manifest of package `foo`")) .success(); project - .cargo_component("new --lib bar") + .cargo_component(["new", "--lib", "bar"]) .assert() .stderr(contains("Updated manifest of package `bar`")) .success(); @@ -80,7 +80,7 @@ edition = "2021" )?; project - .cargo_component("check") + .cargo_component(["check"]) .assert() .stderr(contains( "Finished `dev` profile [unoptimized + debuginfo] target(s)", diff --git a/tests/clippy.rs b/tests/clippy.rs index 75f77330..8b40296e 100644 --- a/tests/clippy.rs +++ b/tests/clippy.rs @@ -1,18 +1,20 @@ -use crate::support::*; +use std::{fmt::Write, fs, rc::Rc}; + use anyhow::Result; use assert_cmd::prelude::*; use predicates::{boolean::PredicateBooleanExt, str::contains}; -use std::{fmt::Write, fs, rc::Rc}; use tempfile::TempDir; +use crate::support::*; + mod support; #[test] fn it_checks_a_new_project() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; project - .cargo_component("clippy") + .cargo_component(["clippy"]) .assert() .stderr(contains("Checking foo v0.1.0")) .success(); @@ -22,7 +24,7 @@ fn it_checks_a_new_project() -> Result<()> { #[test] fn it_finds_errors() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; let mut src = fs::read_to_string(project.root().join("src/lib.rs"))?; write!(&mut src, "\n\nfn foo() -> String {{\n \"foo\"\n}}\n")?; @@ -30,7 +32,7 @@ fn it_finds_errors() -> Result<()> { fs::write(project.root().join("src/lib.rs"), src)?; project - .cargo_component("clippy") + .cargo_component(["clippy"]) .assert() .stderr(contains("Checking foo v0.1.0").and(contains("expected `String`, found `&str`"))) .failure(); @@ -40,7 +42,7 @@ fn it_finds_errors() -> Result<()> { #[test] fn it_finds_clippy_warnings() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; let mut src = fs::read_to_string(project.root().join("src/lib.rs"))?; write!( @@ -51,7 +53,7 @@ fn it_finds_clippy_warnings() -> Result<()> { fs::write(project.root().join("src/lib.rs"), src)?; project - .cargo_component("clippy") + .cargo_component(["clippy"]) .assert() .stderr(contains("Checking foo v0.1.0").and(contains("clippy::needless_return"))) .success(); @@ -62,10 +64,8 @@ fn it_finds_clippy_warnings() -> Result<()> { #[test] fn it_checks_a_workspace() -> Result<()> { let dir = Rc::new(TempDir::new()?); - let project = Project { - dir: dir.clone(), - root: dir.path().to_owned(), - }; + let root = dir.path().to_owned(); + let project = Project::new_uninitialized(dir, root); project.file( "baz/Cargo.toml", @@ -81,13 +81,13 @@ edition = "2021" project.file("baz/src/lib.rs", "")?; project - .cargo_component("new --lib foo") + .cargo_component(["new", "--lib", "foo"]) .assert() .stderr(contains("Updated manifest of package `foo`")) .success(); project - .cargo_component("new --lib bar") + .cargo_component(["new", "--lib", "bar"]) .assert() .stderr(contains("Updated manifest of package `bar`")) .success(); @@ -101,7 +101,7 @@ members = ["foo", "bar", "baz"] )?; project - .cargo_component("clippy") + .cargo_component(["clippy"]) .assert() .stderr(contains("Checking foo v0.1.0").and(contains("Checking bar v0.1.0"))) .success(); diff --git a/tests/doc.rs b/tests/doc.rs index 777d91a6..f4e1f989 100644 --- a/tests/doc.rs +++ b/tests/doc.rs @@ -1,17 +1,19 @@ -use crate::support::*; +use std::fs; + use anyhow::{Context, Result}; use assert_cmd::prelude::*; use predicates::str::contains; -use std::fs; + +use crate::support::*; mod support; #[test] fn it_documents() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; project - .cargo_component("doc") + .cargo_component(["doc"]) .assert() .stderr(contains( "Finished `dev` profile [unoptimized + debuginfo] target(s)", diff --git a/tests/metadata.rs b/tests/metadata.rs index f0837ba3..cad6fbc6 100644 --- a/tests/metadata.rs +++ b/tests/metadata.rs @@ -1,19 +1,20 @@ use std::rc::Rc; -use crate::support::*; use anyhow::Result; use assert_cmd::prelude::*; use predicates::{prelude::PredicateBooleanExt, str::contains}; use tempfile::TempDir; +use crate::support::*; + mod support; #[test] fn it_prints_metadata() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; project - .cargo_component("metadata --format-version 1") + .cargo_component(["metadata", "--format-version", "1"]) .assert() .stdout(contains(r#""name":"foo","version":"0.1.0""#)) .success(); @@ -23,11 +24,11 @@ fn it_prints_metadata() -> Result<()> { #[test] fn it_rejects_invalid_format_versions() -> Result<()> { - let project = Project::new("foo")?; + let project = Project::new("foo", true)?; for arg in ["7", "0", "42"] { project - .cargo_component(&format!("metadata --format-version {arg}")) + .cargo_component(["metadata", "--format-version", arg]) .assert() .stderr(contains("invalid value")) .failure(); @@ -39,10 +40,8 @@ fn it_rejects_invalid_format_versions() -> Result<()> { #[test] fn it_prints_workspace_metadata() -> Result<()> { let dir = Rc::new(TempDir::new()?); - let project = Project { - dir: dir.clone(), - root: dir.path().to_owned(), - }; + let root = dir.path().to_owned(); + let project = Project::new_uninitialized(dir, root); project.file( "baz/Cargo.toml", @@ -58,13 +57,13 @@ edition = "2021" project.file("baz/src/lib.rs", "")?; project - .cargo_component("new --lib foo") + .cargo_component(["new", "--lib", "foo"]) .assert() .stderr(contains("Updated manifest of package `foo`")) .success(); project - .cargo_component("new --lib bar") + .cargo_component(["new", "--lib", "bar"]) .assert() .stderr(contains("Updated manifest of package `bar`")) .success(); @@ -78,7 +77,7 @@ members = ["foo", "bar", "baz"] )?; project - .cargo_component("metadata --format-version 1") + .cargo_component(["metadata", "--format-version", "1"]) .assert() .stdout( contains(r#"name":"foo","version":"0.1.0""#).and( diff --git a/tests/new.rs b/tests/new.rs index d53d0dcd..95edfddb 100644 --- a/tests/new.rs +++ b/tests/new.rs @@ -1,16 +1,19 @@ -use crate::support::*; +use std::fs; + use anyhow::Result; use assert_cmd::prelude::*; use predicates::{str::contains, Predicate}; -use std::{fs, rc::Rc}; use tempfile::TempDir; +use wasm_pkg_client::warg::WargRegistryConfig; + +use crate::support::*; mod support; #[test] fn help() { for arg in ["help new", "new -h", "new --help"] { - cargo_component(arg) + cargo_component(arg.split_whitespace()) .assert() .stdout(contains( "Create a new WebAssembly component package at ", @@ -23,7 +26,7 @@ fn help() { fn it_creates_the_expected_files_for_bin() -> Result<()> { let dir = TempDir::new()?; - cargo_component("new --bin foo") + cargo_component(["new", "--bin", "foo"]) .current_dir(dir.path()) .assert() .stderr(contains("Updated manifest of package `foo")) @@ -44,7 +47,7 @@ fn it_creates_the_expected_files_for_bin() -> Result<()> { fn it_creates_the_expected_files() -> Result<()> { let dir = TempDir::new()?; - cargo_component("new --lib foo") + cargo_component(["new", "--lib", "foo"]) .current_dir(dir.path()) .assert() .stderr(contains("Updated manifest of package `foo`")) @@ -65,7 +68,7 @@ fn it_creates_the_expected_files() -> Result<()> { fn it_supports_editor_option() -> Result<()> { let dir = TempDir::new()?; - cargo_component("new --lib foo --editor none") + cargo_component(["new", "--lib", "foo", "--editor", "none"]) .current_dir(dir.path()) .assert() .stderr(contains("Updated manifest of package `foo")) @@ -85,7 +88,7 @@ fn it_supports_editor_option() -> Result<()> { fn it_supports_edition_option() -> Result<()> { let dir = TempDir::new()?; - cargo_component("new --lib foo --edition 2018") + cargo_component(["new", "--lib", "foo", "--edition", "2018"]) .current_dir(dir.path()) .assert() .stderr(contains("Updated manifest of package `foo")) @@ -102,7 +105,7 @@ fn it_supports_edition_option() -> Result<()> { fn it_supports_name_option() -> Result<()> { let dir = TempDir::new()?; - cargo_component("new --lib foo --name bar") + cargo_component(["new", "--lib", "foo", "--name", "bar"]) .current_dir(dir.path()) .assert() .stderr(contains("Updated manifest of package `bar`")) @@ -119,7 +122,7 @@ fn it_supports_name_option() -> Result<()> { fn it_rejects_rust_keywords() -> Result<()> { let dir = TempDir::new()?; - cargo_component("new --lib foo --name fn") + cargo_component(["new", "--lib", "foo", "--name", "fn"]) .current_dir(dir.path()) .assert() .stderr(contains( @@ -132,12 +135,13 @@ fn it_rejects_rust_keywords() -> Result<()> { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn it_targets_a_world() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, config, registry) = spawn_server(Vec::::new()).await?; + + let warg_config = + WargRegistryConfig::try_from(config.registry_config(®istry).unwrap()).unwrap(); publish_wit( - &config, + &warg_config.client_config, "test:bar", "1.2.3", r#"package test:bar@1.2.3; @@ -241,9 +245,9 @@ world foo { ) .await?; - let project = Project::with_dir(dir.clone(), "component", "--target test:bar/foo@1.0.0")?; + let project = server.project("component", true, ["--target", "test:bar/foo@1.0.0"])?; project - .cargo_component("build") + .cargo_component(["build"]) .assert() .stderr(contains( "Finished `dev` profile [unoptimized + debuginfo] target(s)", @@ -256,13 +260,14 @@ world foo { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn it_errors_if_target_does_not_exist() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, _, _) = spawn_server(["foo"]).await?; - match Project::with_dir(dir.clone(), "component", "--target foo:bar@1.0.0") { + match server.project("component", true, ["--target", "foo:bar@1.0.0"]) { Ok(_) => panic!("expected error"), - Err(e) => assert!(contains("package `foo:bar` does not exist").eval(&e.to_string())), + Err(e) => assert!( + contains("package `foo:bar` was not found").eval(&e.to_string()), + "Should contain error message {e:?}" + ), } Ok(()) @@ -272,7 +277,7 @@ async fn it_errors_if_target_does_not_exist() -> Result<()> { fn it_supports_the_command_option() -> Result<()> { let dir = TempDir::new()?; - cargo_component("new --command foo") + cargo_component(["new", "--command", "foo"]) .current_dir(dir.path()) .assert() .try_success()?; @@ -284,7 +289,7 @@ fn it_supports_the_command_option() -> Result<()> { fn it_supports_the_reactor_option() -> Result<()> { let dir = TempDir::new()?; - cargo_component("new --reactor foo") + cargo_component(["new", "--reactor", "foo"]) .current_dir(dir.path()) .assert() .try_success()?; @@ -296,7 +301,7 @@ fn it_supports_the_reactor_option() -> Result<()> { fn it_supports_the_proxy_option() -> Result<()> { let dir: TempDir = TempDir::new()?; - cargo_component("new --lib --proxy foo") + cargo_component(["new", "--lib", "--proxy", "foo"]) .current_dir(dir.path()) .assert() .try_success()?; diff --git a/tests/publish.rs b/tests/publish.rs index 0513dbb9..4ddd875b 100644 --- a/tests/publish.rs +++ b/tests/publish.rs @@ -1,21 +1,23 @@ -use crate::support::*; +use std::fs; + use anyhow::{Context, Result}; use assert_cmd::prelude::*; use predicates::str::contains; use semver::Version; -use std::{fs, rc::Rc}; -use tempfile::TempDir; use toml_edit::{value, Array}; use warg_client::Client; use warg_protocol::registry::PackageName; use wasm_metadata::LinkType; +use wasm_pkg_client::warg::WargRegistryConfig; + +use crate::support::*; mod support; #[test] fn help() { for arg in ["help publish", "publish -h", "publish --help"] { - cargo_component(arg) + cargo_component(arg.split_whitespace()) .assert() .stdout(contains("Publish a package to a registry")) .success(); @@ -24,12 +26,13 @@ fn help() { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn it_publishes_a_component() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, config, registry) = spawn_server(Vec::::new()).await?; + + let warg_config = + WargRegistryConfig::try_from(config.registry_config(®istry).unwrap()).unwrap(); publish_wit( - &config, + &warg_config.client_config, "test:world", "1.0.0", r#"package test:%world@1.0.0; @@ -41,14 +44,18 @@ world foo { ) .await?; - let project = Project::with_dir(dir.clone(), "foo", "--namespace test --target test:world")?; + let project = server.project( + "foo", + true, + ["--namespace", "test", "--target", "test:world"], + )?; // Ensure there's a using declaration in the generated source let source = fs::read_to_string(project.root().join("src/lib.rs"))?; assert!(source.contains("use bindings::Guest;")); project - .cargo_component("publish --init") + .cargo_component(["publish", "--init"]) .env("CARGO_COMPONENT_PUBLISH_KEY", test_signing_key()) .assert() .stderr(contains("Published package `test:foo` v0.1.0")) @@ -67,12 +74,13 @@ world foo { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn it_fails_if_package_does_not_exist() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, config, registry) = spawn_server(Vec::::new()).await?; + + let warg_config = + WargRegistryConfig::try_from(config.registry_config(®istry).unwrap()).unwrap(); publish_wit( - &config, + &warg_config.client_config, "test:world", "1.0.0", r#"package test:%world@1.0.0; @@ -84,10 +92,13 @@ world foo { ) .await?; - let project = Project::with_dir(dir.clone(), "foo", "--namespace test --target test:world")?; - + let project = server.project( + "foo", + true, + ["--namespace", "test", "--target", "test:world"], + )?; project - .cargo_component("publish") + .cargo_component(["publish"]) .env("CARGO_COMPONENT_PUBLISH_KEY", test_signing_key()) .assert() .stderr(contains( @@ -100,12 +111,13 @@ world foo { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn it_publishes_a_dependency() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, config, registry) = spawn_server(Vec::::new()).await?; + + let warg_config = + WargRegistryConfig::try_from(config.registry_config(®istry).unwrap()).unwrap(); publish_wit( - &config, + &warg_config.client_config, "test:world", "1.0.0", r#"package test:%world@1.0.0; @@ -116,14 +128,14 @@ world foo { ) .await?; - let project = Project::with_dir( - dir.clone(), + let project = server.project( "foo", - "--namespace test --target test:world/foo", + true, + ["--namespace", "test", "--target", "test:world/foo"], )?; project - .cargo_component("publish --init") + .cargo_component(["publish", "--init"]) .env("CARGO_COMPONENT_PUBLISH_KEY", test_signing_key()) .assert() .stderr(contains("Published package `test:foo` v0.1.0")) @@ -131,10 +143,13 @@ world foo { validate_component(&project.release_wasm("foo"))?; - let project = Project::with_dir(dir.clone(), "bar", "--namespace test --target test:world")?; - + let project = server.project( + "bar", + true, + ["--namespace", "test", "--target", "test:world"], + )?; project - .cargo_component("add test:foo") + .cargo_component(["add", "test:foo"]) .assert() .stderr(contains("Added dependency `test:foo` with version `0.1.0`")) .success(); @@ -156,7 +171,7 @@ bindings::export!(Component with_types_in bindings); fs::write(project.root().join("src/lib.rs"), source)?; project - .cargo_component("publish --init") + .cargo_component(["publish", "--init"]) .env("CARGO_COMPONENT_PUBLISH_KEY", test_signing_key()) .assert() .stderr(contains("Published package `test:bar` v0.1.0")) @@ -169,9 +184,10 @@ bindings::export!(Component with_types_in bindings); #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn it_publishes_with_registry_metadata() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, config, registry) = spawn_server(Vec::::new()).await?; + + let warg_config = + WargRegistryConfig::try_from(config.registry_config(®istry).unwrap()).unwrap(); let authors = ["Jane Doe "]; let categories = ["wasm"]; @@ -181,7 +197,7 @@ async fn it_publishes_with_registry_metadata() -> Result<()> { let homepage = "https://example.com/home"; let repository = "https://example.com/repo"; - let project = Project::with_dir(dir.clone(), "foo", "--namespace test")?; + let project = server.project("foo", true, ["--namespace", "test"])?; project.update_manifest(|mut doc| { let package = &mut doc["package"]; package["authors"] = value(Array::from_iter(authors)); @@ -195,7 +211,7 @@ async fn it_publishes_with_registry_metadata() -> Result<()> { })?; project - .cargo_component("publish --init") + .cargo_component(["publish", "--init"]) .env("CARGO_COMPONENT_PUBLISH_KEY", test_signing_key()) .assert() .stderr(contains("Published package `test:foo` v0.1.0")) @@ -203,7 +219,7 @@ async fn it_publishes_with_registry_metadata() -> Result<()> { validate_component(&project.release_wasm("foo"))?; - let client = Client::new_with_config(None, &config, None).await?; + let client = Client::new_with_config(None, &warg_config.client_config, None).await?; let download = client .download_exact(&PackageName::new("test:foo")?, &Version::parse("0.1.0")?) .await?; diff --git a/tests/run.rs b/tests/run.rs index b5bb6c98..70ddcaa4 100644 --- a/tests/run.rs +++ b/tests/run.rs @@ -1,15 +1,17 @@ -use crate::support::*; +use std::fs; + use anyhow::Result; use assert_cmd::prelude::*; use predicates::str::contains; -use std::fs; use toml_edit::{value, Item, Table}; +use crate::support::*; + mod support; #[test] fn it_runs_with_command_component() -> Result<()> { - let project = Project::new_bin("bar")?; + let project = Project::new("bar", false)?; fs::write( project.root().join("src/main.rs"), @@ -25,7 +27,7 @@ fn main() { )?; project - .cargo_component("run") + .cargo_component(["run"]) .arg("--") .arg("--verbose") .assert() @@ -39,7 +41,7 @@ fn main() { #[test] fn it_runs_with_reactor_component() -> Result<()> { - let project = Project::new("baz")?; + let project = Project::new("baz", true)?; project.update_manifest(|mut doc| { let mut dependencies = Table::new(); dependencies["wasi:cli"]["path"] = value("wit/deps/cli"); @@ -97,7 +99,7 @@ bindings::export!(Component with_types_in bindings); )?; project - .cargo_component("run") + .cargo_component(["run"]) .env( "CARGO_TARGET_WASM32_WASIP1_RUNNER", "wasmtime --env APP_NAME=CargoComponent -C cache=no -W component-model -S preview2 -S cli", diff --git a/tests/support/mod.rs b/tests/support/mod.rs index 86a0f325..65832a22 100644 --- a/tests/support/mod.rs +++ b/tests/support/mod.rs @@ -1,15 +1,17 @@ #![allow(dead_code)] - -use anyhow::{bail, Context, Result}; -use assert_cmd::prelude::OutputAssertExt; -use indexmap::IndexSet; use std::{ + ffi::OsStr, fs, path::{Path, PathBuf}, process::Command, rc::Rc, time::Duration, }; + +use anyhow::{bail, Context, Result}; +use assert_cmd::prelude::OutputAssertExt; +use cargo_component_core::command::{CACHE_DIR_ENV_VAR, CONFIG_FILE_ENV_VAR}; +use indexmap::IndexSet; use tempfile::TempDir; use tokio::task::JoinHandle; use tokio_util::sync::CancellationToken; @@ -21,9 +23,13 @@ use warg_client::{ use warg_crypto::signing::PrivateKey; use warg_protocol::{operator::NamespaceState, registry::PackageName}; use warg_server::{policy::content::WasmContentPolicy, Config, Server}; +use wasm_pkg_client::Registry; use wasmparser::{Chunk, Encoding, Parser, Payload, Validator}; use wit_parser::{Resolve, UnresolvedPackage}; +const WARG_CONFIG_NAME: &str = "warg-config.json"; +const WASM_PKG_CONFIG_NAME: &str = "wasm-pkg-config.json"; + pub fn test_operator_key() -> &'static str { "ecdsa-p256:I+UlDo0HxyBBFeelhPPWmD+LnklOpqZDkrFP5VduASk=" } @@ -44,7 +50,11 @@ pub fn adapter_path() -> PathBuf { path } -pub fn cargo_component(args: &str) -> Command { +pub fn cargo_component(args: I) -> Command +where + I: IntoIterator, + S: AsRef, +{ let mut exe = std::env::current_exe().unwrap(); exe.pop(); // remove test exe name exe.pop(); // remove `deps` @@ -53,9 +63,7 @@ pub fn cargo_component(args: &str) -> Command { let mut cmd = Command::new(&exe); cmd.arg("component"); - for arg in args.split_whitespace() { - cmd.arg(arg); - } + cmd.args(args); cmd } @@ -147,6 +155,25 @@ pub async fn publish_wit( pub struct ServerInstance { task: Option>, shutdown: CancellationToken, + root: Rc, +} + +impl ServerInstance { + /// Returns a `Project` that is configured to use the server instance with the correct config. + pub fn project(&self, name: &str, lib: bool, additional_args: I) -> Result + where + I: IntoIterator, + S: Into, + { + let proj = Project { + dir: self.root.clone(), + root: self.root.path().join(name), + config_file: Some(self.root.path().join(WASM_PKG_CONFIG_NAME)), + }; + + proj.new_inner(name, lib, additional_args)?; + Ok(proj) + } } impl Drop for ServerInstance { @@ -158,17 +185,20 @@ impl Drop for ServerInstance { } } -/// Spawns a server as a background task. -pub async fn spawn_server(root: &Path) -> Result<(ServerInstance, warg_client::Config)> { +/// Spawns a server as a background task. This will start a +pub async fn spawn_server( + additional_namespaces: I, +) -> Result<(ServerInstance, wasm_pkg_client::Config, Registry)> +where + I: IntoIterator, + S: AsRef, +{ + let root = Rc::new(TempDir::new().context("failed to create temp dir")?); let shutdown = CancellationToken::new(); let config = Config::new( PrivateKey::decode(test_operator_key().to_string())?, - Some( - [("test".to_string(), NamespaceState::Defined)] - .into_iter() - .collect(), - ), - root.join("server"), + Some(vec![("test".to_string(), NamespaceState::Defined)]), + root.path().join("server"), ) .with_addr(([127, 0, 0, 1], 0)) .with_shutdown(shutdown.clone().cancelled_owned()) @@ -185,13 +215,14 @@ pub async fn spawn_server(root: &Path) -> Result<(ServerInstance, warg_client::C let instance = ServerInstance { task: Some(task), shutdown, + root: root.to_owned(), }; - let config = warg_client::Config { + let warg_config = warg_client::Config { home_url: Some(format!("http://{addr}")), - registries_dir: Some(root.join("registries")), - content_dir: Some(root.join("content")), - namespace_map_path: Some(root.join("namespaces")), + registries_dir: Some(root.path().join("registries")), + content_dir: Some(root.path().join("content")), + namespace_map_path: Some(root.path().join("namespaces")), keys: IndexSet::new(), keyring_auth: false, keyring_backend: None, @@ -200,57 +231,125 @@ pub async fn spawn_server(root: &Path) -> Result<(ServerInstance, warg_client::C disable_interactive: true, }; - Ok((instance, config)) + let config_file = root.path().join(WARG_CONFIG_NAME); + warg_config.write_to_file(&config_file)?; + + let mut config = wasm_pkg_client::Config::default(); + // We should probably update wasm-pkg-tools to use http for "localhost" or "127.0.0.1" + let registry: Registry = format!("localhost:{}", addr.port()).parse().unwrap(); + config.set_namespace_registry("test".parse().unwrap(), registry.clone()); + for ns in additional_namespaces { + config.set_namespace_registry(ns.as_ref().parse().unwrap(), registry.clone()); + } + let reg_conf = config.get_or_insert_registry_config_mut(®istry); + reg_conf.set_backend_type(Some("warg".to_string())); + reg_conf + .set_backend_config( + "warg", + wasm_pkg_client::warg::WargRegistryConfig { + client_config: warg_config, + auth_token: None, + config_file: Some(config_file), + }, + ) + .expect("Should be able to set backend config"); + + config.to_file(root.path().join(WASM_PKG_CONFIG_NAME))?; + + Ok((instance, config, registry)) } #[derive(Debug)] pub struct Project { pub dir: Rc, pub root: PathBuf, + config_file: Option, } impl Project { - pub fn new(name: &str) -> Result { + /// Creates a new project with the given name and whether or not to create a library instead of + /// a binary. This should only be used if you want an "empty" project that doesn't have things + /// like warg config or wasm pkg tools config configured. If you want a project with a warg + /// config and wasm pkg tools config, use the `project` method of `ServerInstance`. + pub fn new(name: &str, lib: bool) -> Result { let dir = TempDir::new()?; - - cargo_component(&format!("new --lib {name}")) - .current_dir(dir.path()) - .assert() - .try_success()?; - let root = dir.path().join(name); - - Ok(Self { + let proj = Self { dir: Rc::new(dir), root, - }) - } + config_file: None, + }; - pub fn new_bin(name: &str) -> Result { - let dir = TempDir::new()?; + proj.new_inner(name, lib, Vec::::new())?; - cargo_component(&format!("new {name}")) - .current_dir(dir.path()) - .assert() - .try_success()?; + Ok(proj) + } + /// Same as `new` but allows you to specify additional arguments to pass to `cargo component + /// new` + pub fn new_with_args(name: &str, lib: bool, additional_args: I) -> Result + where + I: IntoIterator, + S: Into, + { + let dir = TempDir::new()?; let root = dir.path().join(name); - - Ok(Self { + let proj = Self { dir: Rc::new(dir), root, - }) + config_file: None, + }; + + proj.new_inner(name, lib, additional_args)?; + + Ok(proj) } - pub fn with_dir(dir: Rc, name: &str, args: &str) -> Result { - cargo_component(&format!("new --lib {name} {args}")) - .current_dir(dir.path()) + fn new_inner(&self, name: &str, lib: bool, additional_args: I) -> Result<()> + where + I: IntoIterator, + S: Into, + { + let mut args = vec!["new".to_string(), name.to_string()]; + if lib { + args.push("--lib".to_string()); + } + args.extend(additional_args.into_iter().map(|arg| arg.into())); + + self.cargo_component(args) + .current_dir(self.dir.path()) .assert() .try_success()?; + Ok(()) + } + + /// Same as `new` but uses the given temp directory instead of creating a new one. + pub fn with_dir(dir: Rc, name: &str, lib: bool, args: I) -> Result + where + I: IntoIterator, + S: Into, + { let root = dir.path().join(name); + let proj = Self { + dir, + root, + config_file: None, + }; + + proj.new_inner(name, lib, args)?; - Ok(Self { dir, root }) + Ok(proj) + } + + /// Creates a new project that hasn't been initialized yet. This is useful for testing workflows + /// of `cargo component new` + pub fn new_uninitialized(dir: Rc, root: PathBuf) -> Self { + Self { + dir, + root, + config_file: None, + } } pub fn root(&self) -> &Path { @@ -302,8 +401,25 @@ impl Project { .join(format!("{name}.wasm")) } - pub fn cargo_component(&self, cmd: &str) -> Command { - let mut cmd = cargo_component(cmd); + pub fn cache_dir(&self) -> PathBuf { + self.dir.path().join("cache") + } + + pub fn config_file(&self) -> Option<&Path> { + self.config_file.as_deref() + } + + pub fn cargo_component(&self, args: I) -> Command + where + I: IntoIterator, + S: AsRef, + { + let mut cmd = cargo_component(args); + // Set the cache dir and the config file env var for every command + if let Some(config_file) = self.config_file() { + cmd.env(CONFIG_FILE_ENV_VAR, config_file); + } + cmd.env(CACHE_DIR_ENV_VAR, self.cache_dir()); cmd.current_dir(&self.root); cmd } diff --git a/tests/test.rs b/tests/test.rs index dfd63525..1a4002b6 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1,14 +1,16 @@ -use crate::support::*; +use std::fs; + use anyhow::Result; use assert_cmd::prelude::*; use predicates::str::contains; -use std::fs; + +use crate::support::*; mod support; #[test] fn it_runs_test_with_command_component() -> Result<()> { - let project = Project::new_bin("foo-bar")?; + let project = Project::new("foo-bar", false)?; fs::create_dir_all(project.root().join(".cargo"))?; fs::write( @@ -70,7 +72,7 @@ pub fn test_random_component() { )?; project - .cargo_component("test") + .cargo_component(["test"]) .assert() .stdout(contains("test test_random_component ... ok")) .stdout(contains("test result: ok.")) @@ -81,7 +83,7 @@ pub fn test_random_component() { #[test] fn it_runs_test_with_reactor_component() -> Result<()> { - let project = Project::new("foo-bar")?; + let project = Project::new("foo-bar", true)?; fs::write( project.root().join("wit/world.wit"), @@ -120,7 +122,7 @@ pub fn test_random_component() { )?; project - .cargo_component("test") + .cargo_component(["test"]) .assert() .stdout(contains("test test_random_component ... ok")) .stdout(contains("test result: ok.")) diff --git a/tests/update.rs b/tests/update.rs index 4d7a95f1..e439009c 100644 --- a/tests/update.rs +++ b/tests/update.rs @@ -1,17 +1,19 @@ -use crate::support::*; +use std::fs; + use anyhow::{Context, Result}; use assert_cmd::prelude::*; use predicates::{prelude::PredicateBooleanExt, str::contains}; -use std::{fs, rc::Rc}; -use tempfile::TempDir; use toml_edit::value; +use wasm_pkg_client::warg::WargRegistryConfig; + +use crate::support::*; mod support; #[test] fn help() { for arg in ["help update", "update -h", "update --help"] { - cargo_component(arg) + cargo_component(arg.split_whitespace()) .assert() .stdout(contains( "Update dependencies as recorded in the component lock file", @@ -22,12 +24,13 @@ fn help() { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn update_without_changes_is_a_noop() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, config, registry) = spawn_server(Vec::::new()).await?; + + let warg_config = + WargRegistryConfig::try_from(config.registry_config(®istry).unwrap()).unwrap(); publish_wit( - &config, + &warg_config.client_config, "test:bar", "1.0.0", r#"package test:bar@1.0.0; @@ -39,10 +42,9 @@ world foo { ) .await?; - let project = Project::with_dir(dir.clone(), "component", "--target test:bar@1.0.0")?; - + let project = server.project("component", true, ["--target", "test:bar@1.0.0"])?; project - .cargo_component("build") + .cargo_component(["build"]) .assert() .stderr(contains( "Finished `dev` profile [unoptimized + debuginfo] target(s)", @@ -51,7 +53,7 @@ world foo { validate_component(&project.debug_wasm("component"))?; project - .cargo_component("update") + .cargo_component(["update"]) .assert() .success() .stderr(contains("test:bar").not()); @@ -61,12 +63,13 @@ world foo { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn update_without_compatible_changes_is_a_noop() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, config, registry) = spawn_server(Vec::::new()).await?; + + let warg_config = + WargRegistryConfig::try_from(config.registry_config(®istry).unwrap()).unwrap(); publish_wit( - &config, + &warg_config.client_config, "test:bar", "1.0.0", r#"package test:bar@1.0.0; @@ -78,10 +81,9 @@ world foo { ) .await?; - let project = Project::with_dir(dir.clone(), "component", "--target test:bar@1.0.0")?; - + let project = server.project("component", true, ["--target", "test:bar@1.0.0"])?; project - .cargo_component("build") + .cargo_component(["build"]) .assert() .stderr(contains( "Finished `dev` profile [unoptimized + debuginfo] target(s)", @@ -90,7 +92,7 @@ world foo { validate_component(&project.debug_wasm("component"))?; publish_wit( - &config, + &warg_config.client_config, "test:bar", "2.0.0", r#"package test:bar@2.0.0; @@ -102,13 +104,13 @@ world foo { .await?; project - .cargo_component("update") + .cargo_component(["update"]) .assert() .success() .stderr(contains("test:bar").not()); project - .cargo_component("build") + .cargo_component(["build"]) .assert() .stderr(contains( "Finished `dev` profile [unoptimized + debuginfo] target(s)", @@ -121,12 +123,13 @@ world foo { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn update_with_compatible_changes() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, config, registry) = spawn_server(Vec::::new()).await?; + + let warg_config = + WargRegistryConfig::try_from(config.registry_config(®istry).unwrap()).unwrap(); publish_wit( - &config, + &warg_config.client_config, "test:bar", "1.0.0", r#"package test:bar@1.0.0; @@ -138,10 +141,9 @@ world foo { ) .await?; - let project = Project::with_dir(dir.clone(), "component", "--target test:bar@1.0.0")?; - + let project = server.project("component", true, ["--target", "test:bar@1.0.0"])?; project - .cargo_component("build") + .cargo_component(["build"]) .assert() .stderr(contains( "Finished `dev` profile [unoptimized + debuginfo] target(s)", @@ -150,7 +152,7 @@ world foo { validate_component(&project.debug_wasm("component"))?; publish_wit( - &config, + &warg_config.client_config, "test:bar", "1.1.0", r#"package test:bar@1.1.0; @@ -164,7 +166,7 @@ world foo { .await?; project - .cargo_component("update") + .cargo_component(["update"]) .assert() .success() .stderr(contains("`test:bar` v1.0.0 -> v1.1.0")); @@ -186,7 +188,7 @@ bindings::export!(Component with_types_in bindings); fs::write(project.root().join("src/lib.rs"), source)?; project - .cargo_component("build") + .cargo_component(["build"]) .assert() .stderr(contains( "Finished `dev` profile [unoptimized + debuginfo] target(s)", @@ -199,12 +201,13 @@ bindings::export!(Component with_types_in bindings); #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn update_with_compatible_changes_is_noop_for_dryrun() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, config, registry) = spawn_server(Vec::::new()).await?; + + let warg_config = + WargRegistryConfig::try_from(config.registry_config(®istry).unwrap()).unwrap(); publish_wit( - &config, + &warg_config.client_config, "test:bar", "1.0.0", r#"package test:bar@1.0.0; @@ -216,10 +219,9 @@ world foo { ) .await?; - let project = Project::with_dir(dir.clone(), "component", "--target test:bar@1.0.0")?; - + let project = server.project("component", true, ["--target", "test:bar@1.0.0"])?; project - .cargo_component("build") + .cargo_component(["build"]) .assert() .stderr(contains( "Finished `dev` profile [unoptimized + debuginfo] target(s)", @@ -228,7 +230,7 @@ world foo { validate_component(&project.debug_wasm("component"))?; publish_wit( - &config, + &warg_config.client_config, "test:bar", "1.1.0", r#"package test:bar@1.1.0; @@ -242,7 +244,7 @@ world foo { .await?; project - .cargo_component("update --dry-run") + .cargo_component(["update", "--dry-run"]) .assert() .success() .stderr(contains( @@ -250,7 +252,7 @@ world foo { )); project - .cargo_component("build") + .cargo_component(["build"]) .assert() .stderr(contains( "Finished `dev` profile [unoptimized + debuginfo] target(s)", @@ -264,17 +266,32 @@ world foo { #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn update_with_changed_dependencies() -> Result<()> { - let dir = Rc::new(TempDir::new()?); - let (_server, config) = spawn_server(dir.path()).await?; - config.write_to_file(&dir.path().join("warg-config.json"))?; + let (server, config, registry) = spawn_server(Vec::::new()).await?; + + let warg_config = + WargRegistryConfig::try_from(config.registry_config(®istry).unwrap()).unwrap(); - publish_component(&config, "test:bar", "1.0.0", "(component)", true).await?; - publish_component(&config, "test:baz", "1.0.0", "(component)", true).await?; + publish_component( + &warg_config.client_config, + "test:bar", + "1.0.0", + "(component)", + true, + ) + .await?; + publish_component( + &warg_config.client_config, + "test:baz", + "1.0.0", + "(component)", + true, + ) + .await?; - let project = Project::with_dir(dir.clone(), "foo", "")?; + let project = server.project("foo", true, Vec::::new())?; project - .cargo_component("build") + .cargo_component(["build"]) .assert() .stderr(contains( "Finished `dev` profile [unoptimized + debuginfo] target(s)", @@ -284,13 +301,13 @@ async fn update_with_changed_dependencies() -> Result<()> { validate_component(&project.debug_wasm("foo"))?; project - .cargo_component("add test:bar") + .cargo_component(["add", "test:bar"]) .assert() .stderr(contains("Added dependency `test:bar` with version `1.0.0`")) .success(); project - .cargo_component("build") + .cargo_component(["build"]) .assert() .stderr(contains( "Finished `dev` profile [unoptimized + debuginfo] target(s)", @@ -307,7 +324,7 @@ async fn update_with_changed_dependencies() -> Result<()> { })?; project - .cargo_component("update") + .cargo_component(["update"]) .assert() .stderr( contains("Removing dependency `test:bar` v1.0.0") @@ -316,7 +333,7 @@ async fn update_with_changed_dependencies() -> Result<()> { .success(); project - .cargo_component("build") + .cargo_component(["build"]) .assert() .stderr(contains( "Finished `dev` profile [unoptimized + debuginfo] target(s)", diff --git a/tests/version.rs b/tests/version.rs index 8ec2c542..420b23fd 100644 --- a/tests/version.rs +++ b/tests/version.rs @@ -7,7 +7,7 @@ mod support; #[test] fn help() { for arg in ["-V", "--version"] { - cargo_component(arg) + cargo_component([arg]) .assert() .stdout(contains(env!("CARGO_PKG_VERSION"))) .success();