diff --git a/.github/cross-linux-aarch64/Dockerfile b/.github/cross-linux-aarch64/Dockerfile index 0d09008b..b18d612c 100644 --- a/.github/cross-linux-aarch64/Dockerfile +++ b/.github/cross-linux-aarch64/Dockerfile @@ -3,7 +3,7 @@ FROM rust:1 # set CROSS_DOCKER_IN_DOCKER to inform `cross` that it is executed from within a container ENV CROSS_DOCKER_IN_DOCKER=true - +ENV CARGO_NET_GIT_FETCH_WITH_CLI=true RUN cargo install cross RUN dpkg --add-architecture arm64 && \ apt-get update && \ diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 0a15c0b5..2fc68212 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -77,13 +77,22 @@ jobs: toolchain: ${{ matrix.rust }} target: ${{ matrix.target }} override: true - - name: Configure cargo data directory + - name: Configure cargo data directory + private access tokens # After this point, all cargo registry and crate data is stored in # $GITHUB_WORKSPACE/.cargo_home. This allows us to cache only the files # that are needed during the build process. Additionally, this works # around a bug in the 'cache' action that causes directories outside of # the workspace dir to be saved/restored incorrectly. - run: echo "CARGO_HOME=$(pwd)/.cargo_home" >> $GITHUB_ENV + run: | + echo "CARGO_HOME=$(pwd)/.cargo_home" >> $GITHUB_ENV + echo https://wasmer:${{ secrets.GH_PAT }}@github.com > creds.txt + git config --global credential.helper "store --file creds.txt" + - name: Configure git credentials on Windows + if: matrix.os == 'windows-latest' + shell: bash + run: | + test="git = \"https:\/\/wasmer:${{ secrets.GH_PAT }}@github.com\/wasmerio\/pirita.git\"" + sed -i "s/git = \"https:\/\/github.com\/wasmerio\/pirita.git\"/$test/g" Cargo.toml # - name: Install sccache # run: | # echo "::add-path::${{ runner.tool_cache }}/cargo-sccache/bin" @@ -189,6 +198,13 @@ jobs: tar -xzf `pwd`/artifacts/wapm-linux-amd64/wapm-cli.tar.gz cp ./bin/wapm /home/runner/.wasmer/bin/wapm chmod +x /home/runner/.wasmer/bin/wapm + - name: Configure cargo data directory + private access tokens + run: | + export CARGO_NET_GIT_FETCH_WITH_CLI=true + echo "CARGO_NET_GIT_FETCH_WITH_CLI=true" >> $GITHUB_ENV + echo "CARGO_HOME=$(pwd)/.cargo_home" >> $GITHUB_ENV + echo https://wasmer:${{ secrets.GH_PAT }}@github.com > creds.txt + git config --global credential.helper "store --file creds.txt" - name: 'Regression test: direct execution works' shell: bash run: | @@ -224,39 +240,40 @@ jobs: run: | chmod +x end-to-end-tests/ci/init-and-add.sh ./end-to-end-tests/ci/init-and-add.sh - linux_aarch64: - name: Linux aarch64 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: dtolnay/rust-toolchain@stable - with: - toolchain: 1.59 - target: aarch64-unknown-linux-gnu - - name: Build cross image - run: | - docker build -t wasmer/aarch64 ${GITHUB_WORKSPACE}/.github/cross-linux-aarch64/ - env: - CROSS_DOCKER_IN_DOCKER: true - - name: Build wapm binary - run: | - make release - env: - CARGO_BINARY: docker run -v /var/run/docker.sock:/var/run/docker.sock -v ${GITHUB_WORKSPACE}:/project -w /project wasmer/aarch64 cross - CROSS_DOCKER_IN_DOCKER: true - CARGO_TARGET: --target aarch64-unknown-linux-gnu - PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig - PKG_CONFIG_ALLOW_CROSS: true - TARGET: aarch64-unknown-linux-gnu - TARGET_DIR: target/aarch64-unknown-linux-gnu/release - - name: Upload Artifacts - uses: actions/upload-artifact@v2 - with: - name: 'wapm-linux-aarch64' - path: dist/wapm-cli.tar.gz - if-no-files-found: error - retention-days: 2 + name: Linux aarch64 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.59 + target: aarch64-unknown-linux-gnu + - name: Build cross image + run: | + docker build -t wasmer/aarch64 ${GITHUB_WORKSPACE}/.github/cross-linux-aarch64/ + env: + CROSS_DOCKER_IN_DOCKER: true + CARGO_NET_GIT_FETCH_WITH_CLI: true + - name: Build wapm binary + run: | + make release + env: + CARGO_BINARY: docker run -v /var/run/docker.sock:/var/run/docker.sock -v ${GITHUB_WORKSPACE}:/project -w /project wasmer/aarch64 cross + CROSS_DOCKER_IN_DOCKER: true + CARGO_NET_GIT_FETCH_WITH_CLI: true + CARGO_TARGET: --target aarch64-unknown-linux-gnu + PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig + PKG_CONFIG_ALLOW_CROSS: true + TARGET: aarch64-unknown-linux-gnu + TARGET_DIR: target/aarch64-unknown-linux-gnu/release + - name: Upload Artifacts + uses: actions/upload-artifact@v2 + with: + name: 'wapm-linux-aarch64' + path: dist/wapm-cli.tar.gz + if-no-files-found: error + retention-days: 2 release: needs: [setup, test, linux_aarch64] #, regression_tests] runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 4387660c..d779fa4f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,6 @@ package dist wax +wapm.lock \.idea/ \.vscode/ \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 560f70ef..21e76eda 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,9 +34,9 @@ dependencies = [ [[package]] name = "android_system_properties" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7ed72e1635e121ca3e79420540282af22da58be50de153d36f81ddc6b83aa9e" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ "libc", ] @@ -50,6 +50,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "any_ascii" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70033777eb8b5124a81a1889416543dddef2de240019b674c81285a2635a7e1e" + [[package]] name = "anyhow" version = "1.0.62" @@ -201,7 +207,7 @@ dependencies = [ "cfg-if 0.1.10", "constant_time_eq", "crypto-mac 0.8.0", - "digest", + "digest 0.9.0", ] [[package]] @@ -213,6 +219,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] + [[package]] name = "bstr" version = "0.2.17" @@ -435,6 +450,16 @@ dependencies = [ "once_cell", ] +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "crypto-mac" version = "0.8.0" @@ -500,13 +525,13 @@ dependencies = [ [[package]] name = "dialoguer" -version = "0.4.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "116f66c4e7b19af0d52857aa4ff710cc3b4781d9c16616e31540bc55ec57ba8c" +checksum = "a92e7e37ecef6857fdc0c0c5d42fd5b0938e46590c2183cc92dd310a6d078eb1" dependencies = [ "console 0.15.1", - "lazy_static", "tempfile", + "zeroize", ] [[package]] @@ -518,6 +543,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer 0.10.2", + "crypto-common", +] + [[package]] name = "dirs" version = "1.0.5" @@ -775,30 +810,30 @@ checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" [[package]] name = "futures-channel" -version = "0.3.23" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bfc52cbddcfd745bf1740338492bb0bd83d76c67b445f91c5fb29fae29ecaa1" +checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.23" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2acedae88d38235936c3922476b10fced7b2b68136f5e3c03c2d5be348a1115" +checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf" [[package]] name = "futures-io" -version = "0.3.23" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93a66fc6d035a26a3ae255a6d2bca35eda63ae4c5512bef54449113f7a1228e5" +checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68" [[package]] name = "futures-macro" -version = "0.3.23" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0db9cce532b0eae2ccf2766ab246f114b56b9cf6d445e00c2549fbc100ca045d" +checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17" dependencies = [ "proc-macro2", "quote", @@ -807,21 +842,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.23" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0bae1fe9752cf7fd9b0064c674ae63f97b37bc714d745cbde0afb7ec4e6765" +checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56" [[package]] name = "futures-task" -version = "0.3.23" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "842fc63b931f4056a24d59de13fb1272134ce261816e063e634ad0c15cdc5306" +checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1" [[package]] name = "futures-util" -version = "0.3.23" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0828a5471e340229c11c77ca80017937ce3c58cb788a17e5f1c2d5c485a9577" +checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90" dependencies = [ "futures-core", "futures-io", @@ -1012,7 +1047,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" dependencies = [ "crypto-mac 0.10.1", - "digest", + "digest 0.9.0", ] [[package]] @@ -1109,6 +1144,19 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" +dependencies = [ + "http", + "hyper 0.14.20", + "rustls", + "tokio", + "tokio-rustls", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -1165,6 +1213,19 @@ checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indicatif" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d207dc617c7a380ab07ff572a6e52fa202a2a8f355860ac9c38e23f8196be1b" +dependencies = [ + "console 0.15.1", + "lazy_static", + "number_prefix", + "regex", ] [[package]] @@ -1203,6 +1264,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json5" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" +dependencies = [ + "pest", + "pest_derive", + "serde", +] + [[package]] name = "language-tags" version = "0.2.2" @@ -1234,6 +1306,15 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "lexical-sort" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c09e4591611e231daf4d4c685a66cb0410cc1e502027a20ae55f2bb9e997207a" +dependencies = [ + "any_ascii", +] + [[package]] name = "libc" version = "0.2.132" @@ -1263,6 +1344,16 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "lock_api" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f80bf5aacaf25cbfc8210d1cfb718f2bf3b11c4c54e5afe36c236853a8ec390" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.3.9" @@ -1305,6 +1396,15 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "memmap2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95af15f345b17af2efc8ead6080fb8bc376f8cec1b35277b935637595fe77498" +dependencies = [ + "libc", +] + [[package]] name = "mime" version = "0.2.6" @@ -1436,6 +1536,12 @@ dependencies = [ "libc", ] +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + [[package]] name = "object" version = "0.29.0" @@ -1489,15 +1595,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" -[[package]] -name = "openssl-src" -version = "111.22.0+1.1.1q" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f31f0d509d1c1ae9cada2f9539ff8f37933831fd5098879e482aa687d659853" -dependencies = [ - "cc", -] - [[package]] name = "openssl-sys" version = "0.9.75" @@ -1507,17 +1604,45 @@ dependencies = [ "autocfg", "cc", "libc", - "openssl-src", "pkg-config", "vcpkg", ] +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "windows-sys", +] + [[package]] name = "paste" version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9423e2b32f7a043629287a536f21951e8c6a82482d0acb1eeebfc90bc2225b22" +[[package]] +name = "path-clean" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecba01bf2678719532c5e3059e0b5f0811273d94b397088b82e3bd0a78c78fdd" + [[package]] name = "pbkdf2" version = "0.6.0" @@ -1549,6 +1674,40 @@ dependencies = [ "ucd-trie", ] +[[package]] +name = "pest_derive" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "905708f7f674518498c1f8d644481440f476d39ca6ecae83319bba7c6c12da91" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5803d8284a629cc999094ecd630f55e91b561a1d1ba75e233b00ae13b91a69ad" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1538eb784f07615c6d9a8ab061089c6c54a344c5b4301db51990ca1c241e8c04" +dependencies = [ + "once_cell", + "pest", + "sha-1", +] + [[package]] name = "pin-project-lite" version = "0.2.9" @@ -1561,6 +1720,16 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pirita" +version = "0.1.0" +source = "git+https://github.com/wasmerio/pirita.git?rev=048e21ea3649008c11eb66a1e6919534182ded2b#048e21ea3649008c11eb66a1e6919534182ded2b" +dependencies = [ + "anyhow", + "wapm-targz-to-pirita", + "webc", +] + [[package]] name = "pkg-config" version = "0.3.25" @@ -1822,6 +1991,7 @@ dependencies = [ "http", "http-body", "hyper 0.14.20", + "hyper-rustls", "hyper-tls", "ipnet", "js-sys", @@ -1832,11 +2002,14 @@ dependencies = [ "native-tls", "percent-encoding 2.1.0", "pin-project-lite", + "rustls", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "tokio", "tokio-native-tls", + "tokio-rustls", "tokio-socks", "tokio-util", "tower-service", @@ -1844,9 +2017,25 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "webpki-roots", "winreg", ] +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + [[package]] name = "rmp" version = "0.8.11" @@ -1933,6 +2122,27 @@ dependencies = [ "semver 0.11.0", ] +[[package]] +name = "rustls" +version = "0.20.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033" +dependencies = [ + "log 0.4.17", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" +dependencies = [ + "base64 0.13.0", +] + [[package]] name = "ryu" version = "1.0.11" @@ -1954,6 +2164,15 @@ dependencies = [ "cipher", ] +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.20" @@ -1964,6 +2183,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "scrypt" version = "0.5.0" @@ -1973,7 +2198,17 @@ dependencies = [ "hmac", "pbkdf2", "salsa20", - "sha2", + "sha2 0.9.9", +] + +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", ] [[package]] @@ -2193,19 +2428,60 @@ dependencies = [ "yaml-rust", ] +[[package]] +name = "sha-1" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.3", +] + [[package]] name = "sha2" version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ - "block-buffer", + "block-buffer 0.9.0", "cfg-if 1.0.0", "cpufeatures", - "digest", + "digest 0.9.0", "opaque-debug", ] +[[package]] +name = "sha2" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.3", +] + +[[package]] +name = "shellwords" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e515aa4699a88148ed5ef96413ceef0048ce95b43fbc955a33bde0a70fcae6" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + [[package]] name = "slab" version = "0.4.7" @@ -2223,14 +2499,20 @@ checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" [[package]] name = "socket2" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +checksum = "10c98bba371b9b22a71a9414e420f92ddeb2369239af08200816169d5e2dd7aa" dependencies = [ "libc", "winapi", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "static_assertions" version = "1.1.0" @@ -2307,6 +2589,16 @@ dependencies = [ "xattr", ] +[[package]] +name = "tar" +version = "0.4.38" +source = "git+https://github.com/fschutt/tar-rs?rev=04ded46840bb195f6c14ca85c5a6d25b61ca349c#04ded46840bb195f6c14ca85c5a6d25b61ca349c" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "tar-wasi" version = "0.4.38" @@ -2460,7 +2752,9 @@ dependencies = [ "mio", "num_cpus", "once_cell", + "parking_lot", "pin-project-lite", + "signal-hook-registry", "socket2", "tokio-macros", "winapi", @@ -2487,6 +2781,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls", + "tokio", + "webpki", +] + [[package]] name = "tokio-socks" version = "0.5.1" @@ -2666,6 +2971,12 @@ dependencies = [ "void", ] +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "url" version = "1.7.2" @@ -2706,6 +3017,21 @@ dependencies = [ "serde", ] +[[package]] +name = "validator" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f07b0a1390e01c0fc35ebb26b28ced33c9a3808f7f9fbe94d3cc01e233bfeed5" +dependencies = [ + "idna 0.2.3", + "lazy_static", + "regex", + "serde", + "serde_derive", + "serde_json", + "url 2.2.2", +] + [[package]] name = "vcpkg" version = "0.2.15" @@ -2736,6 +3062,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + [[package]] name = "want" version = "0.3.0" @@ -2763,11 +3100,13 @@ dependencies = [ "getrandom 0.2.7", "graphql_client", "hex", + "indicatif", "lazy_static", "license-exprs", "log 0.4.17", "maplit", "minisign", + "pirita", "prettytable-rs", "regex", "reqwest", @@ -2779,21 +3118,57 @@ dependencies = [ "serde_derive", "serde_json", "serde_yaml", + "shellwords", "structopt", - "tar", + "tar 0.4.38 (registry+https://github.com/rust-lang/crates.io-index)", "tar-wasi", "tempfile", "thiserror", "time", + "tokio", "toml", "url 2.2.2", + "wapm-resolve-url", "wapm-toml", "wasm-bus-process", "wasm-bus-reqwest", "wasmer-wasm-interface", "wasmparser", - "whoami 0.5.3", - "whoami 1.2.1", + "whoami", +] + +[[package]] +name = "wapm-resolve-url" +version = "0.1.0" +dependencies = [ + "anyhow", + "graphql_client", + "reqwest", + "serde", + "serde_json", + "thiserror", + "url 2.2.2", + "whoami", +] + +[[package]] +name = "wapm-targz-to-pirita" +version = "0.1.0" +source = "git+https://github.com/wasmerio/pirita.git?rev=048e21ea3649008c11eb66a1e6919534182ded2b#048e21ea3649008c11eb66a1e6919534182ded2b" +dependencies = [ + "anyhow", + "base64 0.13.0", + "flate2", + "json5", + "rand 0.8.5", + "serde", + "serde_cbor", + "serde_derive", + "serde_json", + "sha2 0.10.2", + "tar 0.4.38 (git+https://github.com/fschutt/tar-rs?rev=04ded46840bb195f6c14ca85c5a6d25b61ca349c)", + "validator", + "webc", ] [[package]] @@ -2801,6 +3176,7 @@ name = "wapm-toml" version = "0.1.0" dependencies = [ "anyhow", + "indexmap", "semver 1.0.13", "serde", "serde_cbor", @@ -2810,6 +3186,8 @@ dependencies = [ "tempfile", "thiserror", "toml", + "validator", + "wapm-resolve-url", ] [[package]] @@ -3041,10 +3419,45 @@ dependencies = [ ] [[package]] -name = "whoami" -version = "0.5.3" +name = "webc" +version = "0.1.0" +source = "git+https://github.com/wasmerio/pirita.git?rev=048e21ea3649008c11eb66a1e6919534182ded2b#048e21ea3649008c11eb66a1e6919534182ded2b" +dependencies = [ + "anyhow", + "base64 0.13.0", + "indexmap", + "leb128", + "lexical-sort", + "memchr", + "memmap2", + "path-clean", + "rand 0.8.5", + "serde", + "serde_cbor", + "serde_json", + "sha2 0.10.2", + "url 2.2.2", + "walkdir", +] + +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7154f3f4488071a38189dfd63633df444e7be43b731cc12c41505308fc4972f3" +checksum = "f1c760f0d366a6c24a02ed7816e23e691f5d92291f94d15e836006fd11b04daf" +dependencies = [ + "webpki", +] [[package]] name = "whoami" @@ -3072,6 +3485,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -3153,3 +3575,9 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" dependencies = [ "linked-hash-map", ] + +[[package]] +name = "zeroize" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" diff --git a/Cargo.toml b/Cargo.toml index 4ad80fd2..fba726b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,24 +39,35 @@ url = "2" wapm-toml = { version = "0.1.0", path = "./wapm-toml" } wasmer-wasm-interface = { version = "0.1.0", path = "lib/wasm-interface" } wasmparser = "0.51.4" -dialoguer = "0.4.0" hex = { version = "0.4", optional = true } blake3 = { version = "0.3.1", optional = true } +indicatif = "0.16.2" +dialoguer = "0.10.1" +shellwords = "1.1.0" +whoami = "1.2.1" +wapm-resolve-url = { version = "0.1.0", path = "./wapm-resolve-url" } [target.'cfg(not(target_os = "wasi"))'.dependencies] -whoami = "1.1.5" atty = "0.2" -reqwest = { version = "0.11.0", features = ["native-tls-vendored", "blocking", "json", "gzip","socks","multipart"], optional = true } +reqwest = { version = "0.11.0", default-features = false, features = ["rustls-tls", "blocking"], optional = true } tar = { version = "0.4" } +tokio = { version = "1.19.2", features = ["full"] } [target.'cfg(target_os = "wasi")'.dependencies] -whoami = "0.5" wasm-bus-reqwest = "1.0" wasm-bus-process = "1.0" getrandom = "0.2.3" tar = { package = "tar-wasi", version = "0.4" } serde_yaml = { version = "^0.8" } +# Due to issues with SSH, the URL has to be in HTTPS format +[dependencies.pirita] +git = "https://github.com/wasmerio/pirita.git" +rev = "048e21ea3649008c11eb66a1e6919534182ded2b" +default-features = false +features = ["autoconvert", "mmap"] +optional = true + [dev-dependencies] tempfile = "3" @@ -70,6 +81,7 @@ members = [ default = ["full","packagesigning", "sqlite-bundled"] sqlite-bundled = ["rusqlite/bundled"] telemetry = ["sentry"] +pirita_file = ["pirita"] update-notifications= ["billboard", "colored"] prehash-module = ["hex", "blake3"] packagesigning = []#[cfg(feature = "full")] diff --git a/end-to-end-tests/ci/direct-execution.sh b/end-to-end-tests/ci/direct-execution.sh index 2435b9be..c7ef699c 100755 --- a/end-to-end-tests/ci/direct-execution.sh +++ b/end-to-end-tests/ci/direct-execution.sh @@ -5,12 +5,15 @@ rm -f $WASMER_DIR/.wax_index.toml # TODO force clear cache rm -f wapm.toml rm -f wapm.lock +wapm uninstall --global --all chmod +x end-to-end-tests/direct_execute.sh echo "RUNNING SCRIPT..." ./end-to-end-tests/direct_execute.sh &> /tmp/direct_execute.txt -echo "GENERATED OUTPUT:" +echo "GENERATED OUTPUT: ----" cat /tmp/direct_execute.txt -echo "COMPARING..." +echo "EXPECTED OUTPUT: ----" +cat end-to-end-tests/direct_execute.txt +echo "COMPARING... ----" diff -Bba end-to-end-tests/direct_execute.txt /tmp/direct_execute.txt export OUT=$? if ( [ -d globals ] || [ -f wapm.log ] ) then diff --git a/end-to-end-tests/ci/init-and-add.sh b/end-to-end-tests/ci/init-and-add.sh index 54e2cd31..3e915dc8 100755 --- a/end-to-end-tests/ci/init-and-add.sh +++ b/end-to-end-tests/ci/init-and-add.sh @@ -6,11 +6,14 @@ rm -f $WASMER_DIR/globals/wapm.lock rm -rf wapm_packages rm -f wapm.toml rm -f wapm.lock +wapm uninstall --global --all chmod +x end-to-end-tests/init-and-add.sh echo "RUNNING SCRIPT..." ./end-to-end-tests/init-and-add.sh &> /tmp/init-and-add-out.txt echo "GENERATED OUTPUT:" cat /tmp/init-and-add-out.txt +echo "EXPECTED OUTPUT:" +cat end-to-end-tests/init-and-add.txt echo "ADJUSTING OUTPUT" # removes the absolute path tail -n +3 /tmp/init-and-add-out.txt > /tmp/init-and-add-out2.txt diff --git a/end-to-end-tests/ci/install.sh b/end-to-end-tests/ci/install.sh old mode 100644 new mode 100755 index 04915604..a82033eb --- a/end-to-end-tests/ci/install.sh +++ b/end-to-end-tests/ci/install.sh @@ -7,10 +7,13 @@ rm -rf wapm_packages rm -f wapm.toml rm -f wapm.lock chmod +x end-to-end-tests/install.sh +wapm uninstall --global --all echo "RUNNING SCRIPT..." ./end-to-end-tests/install.sh &> /tmp/install-out.txt echo "GENERATED OUTPUT:" cat /tmp/install-out.txt +echo "EXPECTED OUTPUT:" +cat end-to-end-tests/install.txt echo "COMPARING..." diff -Bba end-to-end-tests/install.txt /tmp/install-out.txt export OUT=$? diff --git a/end-to-end-tests/ci/manifest-validation.sh b/end-to-end-tests/ci/manifest-validation.sh old mode 100644 new mode 100755 index b9691083..a3d62a85 --- a/end-to-end-tests/ci/manifest-validation.sh +++ b/end-to-end-tests/ci/manifest-validation.sh @@ -7,10 +7,13 @@ rm -f wapm.lock rm -f wapm.toml rm -rf wapm_packages chmod +x end-to-end-tests/manifest-validation.sh +wapm uninstall --global --all echo "RUNNING SCRIPT..." ./end-to-end-tests/manifest-validation.sh &> /tmp/manifest-validation-out.txt echo "GENERATED OUTPUT:" cat /tmp/manifest-validation-out.txt +echo "EXPECTED OUTPUT:" +cat end-to-end-tests/manifest-validation.txt echo "COMPARING..." diff -Bba end-to-end-tests/manifest-validation.txt /tmp/manifest-validation-out.txt export OUT=$? diff --git a/end-to-end-tests/ci/package-fs-mapping.sh b/end-to-end-tests/ci/package-fs-mapping.sh old mode 100644 new mode 100755 index 55eee398..716d0841 --- a/end-to-end-tests/ci/package-fs-mapping.sh +++ b/end-to-end-tests/ci/package-fs-mapping.sh @@ -7,10 +7,13 @@ rm -rf wapm_packages rm -f wapm.toml rm -f wapm.lock chmod +x end-to-end-tests/package-fs-mapping.sh +wapm uninstall --global --all echo "RUNNING SCRIPT..." ./end-to-end-tests/package-fs-mapping.sh &> /tmp/package-fs-mapping-out.txt echo "GENERATED OUTPUT:" cat /tmp/package-fs-mapping-out.txt +echo "EXPECTED OUTPUT:" +cat end-to-end-tests/end-to-end-tests/package-fs-mapping.txt echo "COMPARING..." ## hack to get the current directory in the expected output #sed -i.bak "s/{{CURRENT_DIR}}/$(pwd | sed 's/\//\\\//g')/g" end-to-end-tests/package-fs-mapping.txt diff --git a/end-to-end-tests/ci/validate-global.sh b/end-to-end-tests/ci/validate-global.sh old mode 100644 new mode 100755 index f0cc1cbb..1d9d470a --- a/end-to-end-tests/ci/validate-global.sh +++ b/end-to-end-tests/ci/validate-global.sh @@ -7,10 +7,13 @@ rm -f wapm.lock rm -f wapm.toml rm -rf wapm_packages chmod +x end-to-end-tests/validate-global.sh +wapm uninstall --global --all echo "RUNNING SCRIPT..." ./end-to-end-tests/validate-global.sh &> /tmp/validate-global-out.txt echo "GENERATED OUTPUT:" cat /tmp/validate-global-out.txt +echo "EXPECTED OUTPUT:" +cat end-to-end-tests/validate-global.txt echo "COMPARING..." diff -Bba end-to-end-tests/validate-global.txt /tmp/validate-global-out.txt export OUT=$? diff --git a/end-to-end-tests/ci/verification.sh b/end-to-end-tests/ci/verification.sh old mode 100644 new mode 100755 index de334331..996b97f6 --- a/end-to-end-tests/ci/verification.sh +++ b/end-to-end-tests/ci/verification.sh @@ -7,10 +7,13 @@ rm -rf wapm_packages rm -f wapm.toml rm -f wapm.lock chmod +x end-to-end-tests/verification.sh +wapm uninstall --global --all echo "RUNNING SCRIPT..." ./end-to-end-tests/verification.sh &> /tmp/verification-out.txt echo "GENERATED OUTPUT:" cat /tmp/verification-out.txt +echo "EXPECTED OUTPUT:" +cat end-to-end-tests/verification.txt echo "COMPARING..." diff -Bba end-to-end-tests/verification.txt /tmp/verification-out.txt export OUT=$? diff --git a/end-to-end-tests/direct_execute.sh b/end-to-end-tests/direct_execute.sh index 81cc3f99..e57678c6 100755 --- a/end-to-end-tests/direct_execute.sh +++ b/end-to-end-tests/direct_execute.sh @@ -2,20 +2,21 @@ export RUST_BACKTRACE=1 ln -sf `which wapm` wax +WAX=$(echo wapm execute) wapm config set registry.url "https://registry.wapm.dev" echo "hello" | wapm execute base64 -./wax echo "hello" +$WAX echo "hello" wapm install namespace-example/cowsay -./wax --emscripten cowsay "hello" +$WAX --emscripten cowsay "hello" wapm uninstall namespace-example/cowsay wapm install lolcat wapm run lolcat -V -./wax lolcat -V +$WAX lolcat -V wapm uninstall lolcat -./wax lolcat -V +$WAX lolcat -V wapm list -a rm -rf $(./wax --which lolcat)/wapm_packages/_/lolcat@0.1.1/* -./wax lolcat -V -./wax --offline lolcat -V -WAPM_RUNTIME=echo ./wax ls | grep "\-\-command-name" || echo "Success: command-name not found" +$WAX lolcat -V +$WAX --offline lolcat -V +WAPM_RUNTIME=echo $WAX ls | grep "\-\-command-name" || echo "Success: command-name not found" diff --git a/end-to-end-tests/direct_execute.txt b/end-to-end-tests/direct_execute.txt index a07d29da..d79a7cf2 100644 --- a/end-to-end-tests/direct_execute.txt +++ b/end-to-end-tests/direct_execute.txt @@ -17,7 +17,7 @@ Package installed successfully to wapm_packages! Package installed successfully to wapm_packages! lolcat 1.0.1 lolcat 1.0.1 -[INFO] Package "lolcat" is not installed. +[INFO] Package "lolcat" uninstalled. lolcat 1.0.1 LOCAL PACKAGES: PACKAGE | VERSION | MODULE | ABI diff --git a/end-to-end-tests/init-and-add.sh b/end-to-end-tests/init-and-add.sh index 80b4a523..eaa7a9db 100755 --- a/end-to-end-tests/init-and-add.sh +++ b/end-to-end-tests/init-and-add.sh @@ -2,6 +2,7 @@ mkdir test-package cd test-package +WAX=$(echo wapm execute) wapm config set registry.url "https://registry.wapm.dev" wapm init -y wapm add this-package-does-not-exist diff --git a/end-to-end-tests/manifest-validation.sh b/end-to-end-tests/manifest-validation.sh old mode 100644 new mode 100755 diff --git a/graphql/queries/get_package.graphql b/graphql/queries/get_package.graphql index 43a953d2..a2665b15 100644 --- a/graphql/queries/get_package.graphql +++ b/graphql/queries/get_package.graphql @@ -10,4 +10,4 @@ query GetPackageQuery ($name: String!) { manifest } } -} +} \ No newline at end of file diff --git a/graphql/queries/get_packages.graphql b/graphql/queries/get_packages.graphql index 1c2df347..a3b75b8c 100644 --- a/graphql/queries/get_packages.graphql +++ b/graphql/queries/get_packages.graphql @@ -3,6 +3,7 @@ query GetPackagesQuery ($names: [String!]!) { name versions { version + isLastVersion distribution { downloadUrl } diff --git a/graphql/queries/wax_get_command-pirita.graphql b/graphql/queries/wax_get_command-pirita.graphql new file mode 100644 index 00000000..7190e865 --- /dev/null +++ b/graphql/queries/wax_get_command-pirita.graphql @@ -0,0 +1,15 @@ +query WaxGetCommandQueryPirita($command: String!) { + command: getCommand(name: $command) { + command + packageVersion { + version + package { + name + displayName + } + distribution { + piritaDownloadUrl + } + } + } +} diff --git a/graphql/schema.graphql b/graphql/schema.graphql index 9a63e9a0..689fc77c 100644 --- a/graphql/schema.graphql +++ b/graphql/schema.graphql @@ -645,6 +645,8 @@ type PackageConnection { type PackageDistribution { downloadUrl: String! size: Int! + piritaDownloadUrl: String + piritaSize: Int } # A Relay edge containing a `Package` and its cursor. diff --git a/src/commands/execute.rs b/src/commands/execute.rs index e050ea07..d1676776 100644 --- a/src/commands/execute.rs +++ b/src/commands/execute.rs @@ -143,7 +143,15 @@ enum ExecuteArgParsingError { query_path = "graphql/queries/wax_get_command.graphql", response_derives = "Debug" )] -struct WaxGetCommandQuery; +pub struct WaxGetCommandQuery; + +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "graphql/schema.graphql", + query_path = "graphql/queries/wax_get_command-pirita.graphql", + response_derives = "Debug" +)] +struct WaxGetCommandQueryPirita; /// Do the real argument parsing into [`ExecuteOptInner`]. fn transform_args(arg_stream: &[String]) -> Result { @@ -266,6 +274,11 @@ pub fn execute(opt: ExecuteOpt) -> anyhow::Result<()> { // first search for locally installed command match FindCommandResult::find_command_in_directory(¤t_dir, &command_name) { + FindCommandResult::CommandFoundPirita(cmd) => { + crate::commands::run::try_run_pirita_cmd(&cmd, command_name, &opt.args.as_ref()) + .map_err(|e| anyhow::anyhow!("Error running PiritaFile command: {e}"))?; + return Ok(()); + }, FindCommandResult::CommandNotFound(_) => { // go to normal wax flow debug!( @@ -360,6 +373,57 @@ pub fn execute(opt: ExecuteOpt) -> anyhow::Result<()> { } } + // if not found, try querying the server for a PiritaFile first + // (before continuing to query for a regular .tar.gz file) + #[cfg(feature = "pirita_file")] + let q = WaxGetCommandQueryPirita::build_query(wax_get_command_query_pirita::Variables { + command: command_name.to_string(), + }); + + // Try to download and execute the PiritaFile before falling back to .tar. + #[cfg(feature = "pirita_file")] + loop { + use crate::commands::run::PiritaRunError; + + if opt.offline || std::env::var("USE_PIRITA") != Ok("1".to_string()) { + break; + } + + debug!("Querying server for package info"); + let response: Result = execute_query(&q); + if response.is_err() { + info!("Failed to connect to the wapm registry. Continuning."); + break; + } + let response: wax_get_command_query_pirita::ResponseData = response?; + let command = match response.command { + Some(s) => s, + None => { break; }, + }; + + let package = command.package_version.package.name; + let version = command.package_version.version; + + // run wapm install [package] && wapm run [package] + let install_opts = crate::commands::install::InstallOpt { + packages: vec![format!("{package}@{version}")], + global: false, + nocache: true, + force_yes: true, + }; + crate::commands::install::install_pirita(&install_opts)?; + let run_opts = crate::commands::run::RunOpt { + command: command.command.clone(), + pre_opened_directories: Vec::new(), + args: opt.args.clone(), + }; + match crate::commands::run::try_run_pirita(&run_opts) { + Ok(()) => return Ok(()), + Err(PiritaRunError::Run(e)) => { return Err(e); }, + Err(PiritaRunError::Initialize(_)) => { break; }, + } + } + // if not found, query the server and check if we already have it installed let q = WaxGetCommandQuery::build_query(wax_get_command_query::Variables { command: command_name.to_string(), @@ -549,6 +613,11 @@ fn run( prehashed_cache_key, ); } + FindCommandResult::CommandFoundPirita(cmd) => { + crate::commands::run::try_run_pirita_cmd(&cmd, command_name, args) + .map_err(|e| anyhow::anyhow!("Error running PiritaFile command: {e}"))?; + return Ok(()); + }, FindCommandResult::Error(e) => return Err(e), }; } diff --git a/src/commands/install.rs b/src/commands/install.rs index 713a20c7..2df799bb 100644 --- a/src/commands/install.rs +++ b/src/commands/install.rs @@ -2,11 +2,12 @@ use crate::{ commands::install::get_package_query::GetPackageQueryPackageLastVersion, - dataflow::bindings::Language, graphql::execute_query, + dataflow::{WapmDistribution, bindings::Language}, graphql::execute_query, }; use anyhow::Context; use graphql_client::*; +use wapm_resolve_url::get_pirita_url_of_package; use crate::config::Config; use crate::dataflow; @@ -24,13 +25,18 @@ use thiserror::Error; /// Options for the `install` subcommand #[derive(StructOpt, Debug)] pub struct InstallOpt { - packages: Vec, + pub(crate) packages: Vec, /// Install the package(s) globally #[structopt(short = "g", long = "global")] - global: bool, + pub(crate) global: bool, + /// If packages already exist, the CLI will throw a prompt whether you'd like to + /// re-download the package. This flag disables the prompt and will re-download + /// the file even if it already exists. + #[structopt(long = "nocache")] + pub(crate) nocache: bool, /// Agree to all prompts. Useful for non-interactive uses. (WARNING: this may cause undesired behavior) #[structopt(long = "force-yes", short = "y")] - force_yes: bool, + pub(crate) force_yes: bool, /// Add the JavaScript bindings using "yarn add". #[structopt(long, groups = &["bindings", "js"], conflicts_with = "global")] yarn: bool, @@ -54,9 +60,6 @@ enum InstallError { #[error("Package not found in the registry: {name}")] PackageNotFound { name: String }, - #[error("No package versions available for package {name}")] - NoVersionsAvailable { name: String }, - #[error("Failed to install packages. {0}")] CannotRegenLockFile(dataflow::Error), @@ -73,6 +76,18 @@ enum InstallError { InvalidPackageIdentifier { name: String }, #[error("Must supply package names to install command when using --global/-g flag.")] MustSupplyPackagesWithGlobalFlag, + #[cfg(feature = "pirita_file")] + #[error( + "Could not find PiritaFile download url for package {0}@{1}", + name, + version + )] + NoPiritaFileForPackage { name: String, version: String }, + #[error( + "No versions available for package {0}", + name + )] + NoVersionsAvailable { name: String }, } #[derive(GraphQLQuery)] @@ -96,6 +111,10 @@ mod package_args { /// Run the install command pub fn install(options: InstallOpt) -> anyhow::Result<()> { + #[cfg(feature = "pirita_file")] + if std::env::var("USE_PIRITA").ok() == Some("1".to_string()) { + return install_pirita(&options); + } let current_directory = crate::config::Config::get_current_dir()?; let _value = util::set_wapm_should_accept_all_prompts(options.force_yes); debug_assert!( @@ -178,9 +197,18 @@ fn install_packages( packages.push(parse_package_and_version(name)?); } - let installed_packages: Vec<(&str, &str)> = packages + let installed_packages: Vec = packages .iter() - .map(|(name, version)| (name.as_str(), version.as_str())) + .map(|(name, version)| { + // TODO: correct? + WapmDistribution { + name: name.clone(), + version: version.clone(), + download_url: String::new(), + pirita_download_url: None, + is_last_version: true, + } + }) .collect(); // the install directory will determine which wapm.lock we are updating. For now, we @@ -332,3 +360,332 @@ impl Target { } } } + +#[cfg(target_feature = "pirita_file")] +fn get_packages_with_versions(package_args: &[String]) -> anyhow::Result> { + + use wapm_resolve_url::get_tar_gz_url_of_package; + use url::Url; + + let config = Config::from_file()?; + let registry_url = Url::parse(&config.registry.get_graphql_url())?; + + let mut result = vec![]; + for name in package_args { + + let name_with_version: Vec<&str> = name.split("@").collect(); + + let mut package_name = match &name_with_version[..] { + [package_name, _] => Some(package_name.to_string()), + [package_name] => Some(package_name.to_string()), + _ => None, + } + .ok_or(InstallError::InvalidPackageIdentifier { name: name.clone() })?; + + let mut package_version = match &name_with_version[..] { + [_, version] => Some(version.to_string()), + _ => None, + }; + + use crate::commands::execute::{WaxGetCommandQuery, wax_get_command_query}; + let get_wax_package_name = |name: String| { + let q = WaxGetCommandQuery::build_query(wax_get_command_query::Variables { + command: name, + }); + debug!("Querying server for package info"); + let response: Result = execute_query(&q); + match response { + Ok(o) => Some(( + o.command.as_ref()?.package_version.package.name.to_string(), + o.command.as_ref()?.package_version.version.to_string(), + )), + Err(_) => None, + } + }; + + let pv = package_version.clone(); + let pv = pv.as_ref().map(|s| s.as_str()); + let targz_info = match get_tar_gz_url_of_package(®istry_url, &package_name, pv) { + Some(s) => s, + None => { + if let Some((wax_package_name, wax_package_version)) = get_wax_package_name(package_name) { + package_name = wax_package_name.clone(); + package_version = Some(wax_package_version.clone()); + get_tar_gz_url_of_package(®istry_url, &wax_package_name, Some(&wax_package_version)) + .ok_or(InstallError::PackageNotFound { + name: name.to_string(), + })? + } else { + return Err(InstallError::PackageNotFound { + name: name.to_string(), + }.into()); + } + } + }; + + let pirita_info = get_pirita_url_of_package(®istry_url, &package_name, Some(&targz_info.resolved_version)); + + let package_to_download = WapmDistribution { + name: targz_info.resolved_name.to_string(), + version: targz_info.resolved_version.to_string(), + download_url: format!("{}", targz_info.url), + pirita_download_url: pirita_info.map(|i| format!("{}", i.url)), + is_last_version: package_version.is_none(), + }; + + result.push(package_to_download.clone()); + } + + Ok(result) +} + +/// Run the install command with --pirita flags +#[cfg(feature = "pirita_file")] +pub fn install_pirita(options: &InstallOpt) -> anyhow::Result<()> { + + let current_directory = crate::config::Config::get_current_dir()?; + let _value = util::set_wapm_should_accept_all_prompts(options.force_yes); + debug_assert!( + _value.is_some(), + "this function should only be called once!" + ); + + let installed_packages = get_packages_with_versions(&options.packages); + let installed_packages = installed_packages?; + let install_directory = Path::new(¤t_directory); + + let rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + + rt.block_on(async { + for p in installed_packages { + + match p.pirita_download_url.as_ref() { + Some(pirita_url) => { + println!("downloading {pirita_url}"); + if let Err(_) = download_pirita( + &p.name, + &p.version, + &pirita_url, + false, + &install_directory, + options.nocache || options.force_yes, + ) + .await { + println!("downloading with autoconvert!"); + download_pirita( + &p.name, + &p.version, + &p.download_url, + true, // autoconvert .tar.gz -> .pirita + &install_directory, + options.nocache || options.force_yes, + ) + .await?; + } + }, + None => { + download_pirita( + &p.name, + &p.version, + &p.download_url, + true, // autoconvert .tar.gz -> .pirita + &install_directory, + options.nocache || options.force_yes, + ) + .await?; + } + } + } + Ok(()) + }) +} + +#[cfg(feature = "pirita_file")] +async fn download_pirita( + name: &str, + version: &str, + download_url: &str, + autoconvert: bool, + directory: &Path, + nocache: bool, +) -> Result<(String, PathBuf, String), anyhow::Error> { + use crate::dataflow::installed_packages::Error; + use crate::graphql::VERSION; + #[cfg(not(target_os = "wasi"))] + use crate::proxy; + use crate::util::{ + create_package_dir, create_temp_dir, fully_qualified_package_display_name, + get_package_namespace_and_name, whoami_distro, + }; + use dialoguer::Confirm; + use indicatif::{ProgressBar, ProgressStyle}; + use reqwest::{header, ClientBuilder}; + use std::fs::OpenOptions; + use std::io::Write; + + let version = semver::Version::parse(version) + .map_err(|e| anyhow!("Invalid version for package {name:?}: {version:?}: {e}"))?; + + let key = format!("{name}@{version}"); + let (namespace, pkg_name) = get_package_namespace_and_name(name) + .map_err(|e| Error::FailedToParsePackageName(name.to_string(), e.to_string()))?; + + let fully_qualified_package_name: String = + fully_qualified_package_display_name(pkg_name, &version); + let package_dir = create_package_dir(&directory, namespace, &fully_qualified_package_name) + .map_err(|err| Error::IoErrorCreatingDirectory(key.to_string(), err.to_string()))?; + let target_file_path = package_dir.join("package.pirita"); + + let client = { + let builder = ClientBuilder::new().gzip(true); + #[cfg(not(target_os = "wasi"))] + let builder = if let Some(proxy) = + proxy::maybe_set_up_proxy().map_err(|e| Error::IoConnectionError(format!("{}", e)))? + { + builder.proxy(proxy) + } else { + builder + }; + + builder.build().unwrap() + }; + let user_agent = format!( + "wapm/{} {} {}", + VERSION, + whoami::platform(), + whoami_distro(), + ); + + let mut response = client + .get(download_url) + .header(header::USER_AGENT, user_agent) + .send() + .await + .map_err(|e| { + let error_message = e.to_string(); + #[cfg(feature = "telemetry")] + { + let e = e.into(); + sentry::integrations::anyhow::capture_anyhow(&e); + } + Error::DownloadError(key.to_string(), error_message) + })?; + + let total_size: u64 = response + .headers() + .get("Content-Length") + .and_then(|c| c.to_str().ok()?.parse().ok()) + .unwrap_or(u64::MAX); + + let temp_dir = + create_temp_dir() + .map_err(|e| Error::DownloadError(key.to_string(), e.to_string()))?; + + let tmp_dir_path: &std::path::Path = temp_dir.as_ref(); + + std::fs::create_dir_all(tmp_dir_path.join("wapm_package_install")) + .map_err(|e| Error::IoErrorCreatingDirectory(key.to_string(), e.to_string()))?; + + let temp_tar_gz_path = tmp_dir_path + .join("wapm_package_install") + .join("package.pirita"); + + if nocache || autoconvert || ( + target_file_path.exists() && + target_file_path.metadata()?.len() == total_size && + Confirm::new() + .with_prompt(format!("The package {key:?} seems to already have been downloaded. Download again? (no)")) + .default(false) + .interact()? + ) { + + let mut dest = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(&temp_tar_gz_path) + .map_err(|e| Error::IoCopyError(key.to_string(), e.to_string()))?; + + let pb = ProgressBar::new(total_size); + pb.set_style( + ProgressStyle::default_bar() + .template("{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta})") + .progress_chars("#>-") + ); + + let mut downloaded = 0_u64; + + if let Some(first_chunk) = response.chunk().await? { + let new = (downloaded + first_chunk.len() as u64).min(total_size); + downloaded = new; + if !autoconvert && !pirita::Pirita::check_is_pirita_file(&first_chunk) { + pb.finish_and_clear(); + return Err(anyhow!("Error: remote package is not a PiritaFile")); + } + dest.write_all(&first_chunk)?; + pb.set_position(new); + } + + while let Some(chunk) = response.chunk().await? { + let new = (downloaded + chunk.len() as u64).min(total_size); + downloaded = new; + dest.write_all(&chunk)?; + pb.set_position(new); + } + + pb.finish_and_clear(); + println!("downloaded: {download_url} to {}", temp_tar_gz_path.display()); + + std::fs::copy(&temp_tar_gz_path, &target_file_path)?; + } + + println!("file downloaded: {autoconvert}, {}", pirita::Pirita::load_mmap(temp_tar_gz_path.clone()).is_none()); + + if autoconvert && pirita::Pirita::load_mmap(temp_tar_gz_path.clone()).is_none() { + + std::fs::remove_file(&target_file_path)?; + + // autoconvert .tar.gz => .pirita after download + let e = pirita::convert_targz_to_pirita( + &temp_tar_gz_path, + &target_file_path, + None, + &pirita::TransformManifestFunctions { + get_atoms_wapm_toml: wapm_toml::get_wapm_atom_file_paths, + get_dependencies: wapm_toml::get_dependencies, + get_package_annotations: wapm_toml::get_package_annotations, + get_modules: wapm_toml::get_modules, + get_commands: wapm_toml::get_commands, + get_bindings: wapm_toml::get_bindings, + get_manifest_file_names: wapm_toml::get_manifest_file_names, + get_metadata_paths: wapm_toml::get_metadata_paths, + get_wapm_manifest_file_name: wapm_toml::get_wapm_manifest_file_name, + }, + ); + + if let Err(e) = e { + println!("{e}"); + } + } + + let parsed_file = pirita::Pirita::load_mmap(target_file_path.clone()).ok_or(anyhow!( + "Could not parse {key:?} ({target_file_path:?}): not a PiritaFile" + ))?; + + std::fs::create_dir_all(directory.join("wapm_packages").join(".bin"))?; + + for (command_name, _) in parsed_file.get_manifest().commands.iter() { + let command = + format!("wasmer run {target_file_path:?} --invoke {command_name:?}"); + let command_path = directory + .join("wapm_packages") + .join(".bin") + .join(&command_name); + std::fs::write(&command_path, command.as_bytes())?; + } + + Ok((key, package_dir, download_url.to_string())) +} diff --git a/src/commands/run.rs b/src/commands/run.rs index 0bb0bea4..30a80c44 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -7,6 +7,7 @@ use crate::dataflow::find_command_result::get_command_from_anywhere; use crate::dataflow::manifest_packages::ManifestResult; use crate::util::get_runtime_with_args; use std::ffi::OsString; +use std::fmt; use std::path::{Path, PathBuf}; #[cfg(not(target_os = "wasi"))] use std::process::Command; @@ -18,16 +19,121 @@ use wasm_bus_process::prelude::Command; #[derive(StructOpt, Debug)] pub struct RunOpt { /// Command name - command: String, + pub(crate) command: String, /// WASI pre-opened directory #[structopt(long = "dir", multiple = true, group = "wasi")] - pre_opened_directories: Vec, + pub(crate) pre_opened_directories: Vec, /// Application arguments #[structopt(multiple = true, parse(from_os_str))] - args: Vec, + pub(crate) args: Vec, +} + +#[derive(Debug)] +pub enum PiritaRunError { + Initialize(PiritaInitializeError), + Run(anyhow::Error), +} +impl fmt::Display for PiritaRunError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::PiritaRunError::*; + match self { + Initialize(i) => write!(f, "initialize: {i}"), + Run(r) => write!(f, "run: {r}"), + } + } +} + +#[derive(Debug)] +pub enum PiritaInitializeError { + NotAWasmerRunCommand, + InvalidCommand(anyhow::Error), + CannotGetCurrentDir(std::io::Error), + CouldNotFindCommandInDotBin(std::io::Error), +} + +impl fmt::Display for PiritaInitializeError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::PiritaInitializeError::*; + match self { + NotAWasmerRunCommand => write!(f, "not a wasmer run command"), + InvalidCommand(e) => write!(f, "invalid command: {e}"), + CannotGetCurrentDir(e) => write!(f, "cannot get current dir: {e}"), + CouldNotFindCommandInDotBin(e) => write!(f, "could not find command in .bin directory: {e}"), + } + } +} + +pub fn try_run_pirita(run_options: &RunOpt) -> Result<(), PiritaRunError> { + + let command_name = run_options.command.as_str(); + let args = &run_options.args; + let current_dir = crate::config::Config::get_current_dir() + .map_err(|e| PiritaRunError::Initialize(PiritaInitializeError::CannotGetCurrentDir(e)))?; + + let cmd = std::fs::read_to_string(current_dir.join("wapm_packages").join(".bin").join(command_name)) + .map_err(|e| PiritaRunError::Initialize(PiritaInitializeError::CouldNotFindCommandInDotBin(e)))?; + + try_run_pirita_cmd(&cmd, command_name, args.as_ref()) +} + +pub(crate) fn try_run_pirita_cmd(cmd: &str, command_name: &str, args: &[OsString]) -> Result<(), PiritaRunError> { + + let mut sw = shellwords::split(&cmd) + .map_err(|e| PiritaRunError::Initialize(PiritaInitializeError::InvalidCommand(e.into())))?; + + if sw.get(0).map(|s| s.as_str()) != Some("wasmer") || sw.get(1).map(|s| s.as_str()) != Some("run") { + return Err(PiritaRunError::Initialize(PiritaInitializeError::NotAWasmerRunCommand)); + } + + sw.remove(0); + sw.remove(0); + + run_pirita(&sw, args) + .map_err(|e| PiritaRunError::Run(e)) +} + +fn run_pirita(args: &[String], rt_args: &[OsString]) -> Result<(), anyhow::Error> { + + let (runtime, runtime_args) = get_runtime_with_args(); + let mut command = std::process::Command::new(runtime); + + for arg in runtime_args { + command.arg(arg); + } + + command.arg("run"); + + for arg in args { + command.arg(arg); + } + + for arg in rt_args { + command.arg(arg); + } + + let output = command.spawn()?; + + let output = output + .wait_with_output() + .expect("failed to wait on child"); + + if !output.stderr.is_empty() { + Err(anyhow!("{}", String::from_utf8_lossy(&output.stderr))) + } else if !output.stdout.is_empty() { + println!("{}", String::from_utf8_lossy(&output.stderr)); + Ok(()) + } else { + Ok(()) + } } pub fn run(run_options: RunOpt) -> anyhow::Result<()> { + + if std::env::var("USE_PIRITA") == Ok("1".to_string()) { + return try_run_pirita(&run_options) + .map_err(|e| anyhow::anyhow!("{e}")); + } + let command_name = run_options.command.as_str(); let args = &run_options.args; let current_dir = crate::config::Config::get_current_dir()?; @@ -40,14 +146,9 @@ pub fn run(run_options: RunOpt) -> anyhow::Result<()> { .map_err(|e| RunError::CannotRegenLockfile(command_name.to_string(), e))?, } - let find_command_result::Command { - source: source_path_buf, - manifest_dir, - args: _, - module_name, - is_global, - prehashed_cache_key, - } = match get_command_from_anywhere(command_name) { + let found_command = get_command_from_anywhere(command_name); + + let command = match found_command { Err(find_command_result::Error::CommandNotFound(command)) => { let package_info = find_command_result::PackageInfoFromCommand::get(command)?; return Err(anyhow!("Command {} not found, but package {} version {} has this command. You can install it with `wapm install {}@{}`", @@ -57,28 +158,46 @@ pub fn run(run_options: RunOpt) -> anyhow::Result<()> { &package_info.namespaced_package_name, &package_info.version, )); - } - otherwise => otherwise?, + }, + Err(e) => { return Err(e.into()); }, + Ok(o) => o, }; - - let run_dir = if is_global { - Config::get_globals_directory().unwrap() - } else { - current_dir.clone() - }; - - let manifest_dir = run_dir.join(manifest_dir); - - do_run( - run_dir, - source_path_buf, - manifest_dir, - command_name, - &module_name, - &run_options.pre_opened_directories, - &args, - prehashed_cache_key, - ) + + match command { + find_command_result::Command::TarGz(find_command_result::TarGzCommand { + source: source_path_buf, + manifest_dir, + args: _, + module_name, + is_global, + prehashed_cache_key, + }) => { + let run_dir = if is_global { + Config::get_globals_directory().unwrap() + } else { + current_dir.clone() + }; + + let manifest_dir = run_dir.join(manifest_dir); + + do_run( + run_dir, + source_path_buf, + manifest_dir, + command_name, + &module_name, + &run_options.pre_opened_directories, + &args, + prehashed_cache_key, + ) + }, + find_command_result::Command::Pirita(find_command_result::PiritaCommand { + cmd + }) => { + crate::commands::run::try_run_pirita_cmd(&cmd, command_name, args) + .map_err(|e| anyhow::anyhow!("Error running PiritaFile command: {e}")) + } + } } pub(crate) fn do_run( diff --git a/src/commands/uninstall.rs b/src/commands/uninstall.rs index 341fd69b..3425f37d 100644 --- a/src/commands/uninstall.rs +++ b/src/commands/uninstall.rs @@ -1,4 +1,6 @@ use crate::config::Config; +use crate::data::wax_index; +use crate::data::manifest::PACKAGES_DIR_NAME; use crate::dataflow; use structopt::StructOpt; use thiserror::Error; @@ -11,10 +13,13 @@ pub enum Error { #[derive(StructOpt, Debug)] pub struct UninstallOpt { - pub package: String, + pub package: Option, /// Uninstall the package(s) globally #[structopt(short = "g", long = "global")] pub global: bool, + /// Uninstall all packages (useful for running in CI) + #[structopt(short = "a", long = "all")] + pub all: bool, } pub fn uninstall(options: UninstallOpt) -> anyhow::Result<()> { @@ -22,22 +27,83 @@ pub fn uninstall(options: UninstallOpt) -> anyhow::Result<()> { true => Config::get_globals_directory()?, false => Config::get_current_dir()?, }; - let uninstalled_package_names = vec![options.package.as_str()]; - // do not allow the "@" symbol to prevent mis-use of this command - if options.package.contains('@') { - return Err(Error::NoAtSignAllowed.into()); - } + let package_names = match options.package.as_ref() { + Some(s) => s.split_whitespace().map(|s| s.to_string()).collect::>(), + None => { + if options.all { + use crate::dataflow::lockfile_packages::{LockfilePackages, LockfileResult}; + + let wax_index = wax_index::WaxIndex::open()?; + let mut entries = wax_index.get_all_entries(); + + // get local packages from lockfile + let lockfile_result = LockfileResult::find_in_directory(&Config::get_current_dir()?); + let lockfile_packages = LockfilePackages::new_from_result(lockfile_result) + .map(|k| k.package_keys()) + .unwrap_or_default(); + for key in lockfile_packages.iter() { + println!("uninstalling lockfile package {}", key.get_name()); + entries.push(key.get_name().to_string()); + } + + if options.global { + // get local packages from lockfile + let lockfile_result = LockfileResult::find_in_directory(&Config::get_globals_directory()?); + let lockfile_packages = LockfilePackages::new_from_result(lockfile_result) + .map(|k| k.package_keys()) + .unwrap_or_default(); + for key in lockfile_packages.iter() { + println!("uninstalling lockfile package {}", key.get_name()); + entries.push(key.get_name().to_string()); + } + } + + if entries.is_empty() { + return Ok(()); + } + entries + } else { + return Err(anyhow!("No packages specified to uninstall.")); + } + } + }; + + for package in package_names.iter() { - // returned bool indicates if there was any to the lockfile. If this pacakge is uninstalled, - // there will be a diff created, which causes update to return true. Because no other change - // is made, we can assume any change resulted in successfully uninstalled package. - let result = dataflow::update(vec![], uninstalled_package_names, dir)?; + let uninstalled_package_names = vec![package.as_str()]; - if !result { - info!("Package \"{}\" is not installed.", options.package); - } else { - info!("Package \"{}\" uninstalled.", options.package); + // do not allow the "@" symbol to prevent mis-use of this command + if package.contains('@') { + return Err(Error::NoAtSignAllowed.into()); + } + + // returned bool indicates if there was any to the lockfile. If this pacakge is uninstalled, + // there will be a diff created, which causes update to return true. Because no other change + // is made, we can assume any change resulted in successfully uninstalled package. + let result = dataflow::update(vec![], uninstalled_package_names, dir.clone())?; + + // Uninstall the package from /tmp/wax/... + let mut wax_uninstalled = false; + let mut wax_index = wax_index::WaxIndex::open()?; + if wax_index.search_for_entry(package.clone()).is_ok() { + wax_index.remove_entry(package.as_str())?; + wax_index.save()?; + wax_uninstalled = true; + } + + let mut pirita_uninstalled = false; + let path = dir.join(PACKAGES_DIR_NAME).join(".bin").join(package.as_str()); + if path.exists() { + std::fs::remove_file(&path)?; + pirita_uninstalled = true; + } + + if !result && !wax_uninstalled && !pirita_uninstalled { + info!("Package \"{}\" is not installed.", package); + } else { + info!("Package \"{}\" uninstalled.", package); + } } Ok(()) diff --git a/src/config.rs b/src/config.rs index aca0d066..c8a06ff4 100644 --- a/src/config.rs +++ b/src/config.rs @@ -200,7 +200,7 @@ struct TestIfRegistryPresent; fn test_if_registry_present(registry: &str) -> Result<(), String> { let q = TestIfRegistryPresent::build_query(test_if_registry_present::Variables {}); - let response: test_if_registry_present::ResponseData = + let _response: test_if_registry_present::ResponseData = crate::graphql::execute_query_custom_registry(registry, &q) .map_err(|e| format!("{e}"))?; Ok(()) diff --git a/src/data/wax_index.rs b/src/data/wax_index.rs index 0aad14b8..74da876f 100644 --- a/src/data/wax_index.rs +++ b/src/data/wax_index.rs @@ -134,6 +134,18 @@ impl WaxIndex { .into()); } + pub fn remove_entry(&mut self, entry: &str) -> Result<(), WaxIndexError>{ + let (package_name, version, _) = self.search_for_entry(entry.to_string())?; + let path = self.base_path().join(&format!("{package_name}@{version}")); + if path.exists() && path.is_dir() { + nuke_dir(path) + .map_err(|_| WaxIndexError::EntryCorrupt { entry: entry.to_string() })?; + self.index.remove(entry) + .ok_or(WaxIndexError::EntryNotFound { entry: entry.to_string() })?; + } + Ok(()) + } + /// Package installed, add it to the index. /// /// Returns true if an existing entry was updated. @@ -149,6 +161,35 @@ impl WaxIndex { pub fn base_path(&self) -> &Path { &self.base_dir } + + /// Returns a list of all currently installed packages + pub fn get_all_entries(&self) -> Vec { + self.index.keys().cloned().collect() + } +} + +pub fn nuke_dir>(path: P) -> Result<(), String> { + let path = path.as_ref(); + for entry in fs::read_dir(path) + .map_err(|e| format!("{}: {}", path.display(), e))? { + let entry = entry + .map_err(|e| format!("{}: {}", path.display(), e))?; + let path = entry.path(); + + let file_type = entry.file_type() + .map_err(|e| format!("{}: {}", path.display(), e))?; + + if file_type.is_dir() { + nuke_dir(&path)?; + std::fs::remove_dir(&path) + .map_err(|e| format!("{}: {}", path.display(), e))?; + } else { + std::fs::remove_file(&path) + .map_err(|e| format!("{}: {}", path.display(), e))?; + } + } + + Ok(()) } #[derive(Debug, Error)] diff --git a/src/dataflow/added_packages.rs b/src/dataflow/added_packages.rs index b2be7956..b184309f 100644 --- a/src/dataflow/added_packages.rs +++ b/src/dataflow/added_packages.rs @@ -3,6 +3,8 @@ use semver::Version; use std::collections::HashSet; use thiserror::Error; +use super::WapmDistribution; + #[derive(Clone, Debug, Error)] pub enum Error { #[error("Package must have version that follows semantic versioning. {0}")] @@ -18,9 +20,10 @@ pub struct AddedPackages<'a> { impl<'a> AddedPackages<'a> { /// Extract name and version, parse version as semver, construct registry key, and finally /// normalize the global namespace if using the shorthand e.g. "_/pkg" == pkg - pub fn new_from_str_pairs(added_packages: Vec<(&'a str, &'a str)>) -> Result { + pub fn new_from_str_pairs(added_packages: &'a Vec) -> Result { let added_packages = added_packages - .into_iter() + .iter() + .map(|w| (w.name.as_str(), w.version.as_str())) .map(Self::extract_name_and_version) .collect::, Error>>()?; let packages = added_packages diff --git a/src/dataflow/find_command_result.rs b/src/dataflow/find_command_result.rs index bb122030..8a37f008 100644 --- a/src/dataflow/find_command_result.rs +++ b/src/dataflow/find_command_result.rs @@ -3,6 +3,7 @@ use crate::data::lock::lockfile::{Lockfile, LockfileError}; use crate::data::manifest::Manifest; use crate::dataflow::lockfile_packages::LockfileResult; use crate::dataflow::manifest_packages::ManifestResult; +use crate::dataflow::pirita_packages::PiritaResult; use std::path::{Path, PathBuf}; use thiserror::Error; @@ -81,6 +82,7 @@ pub enum FindCommandResult { module_name: String, prehashed_cache_key: Option, }, + CommandFoundPirita(String), Error(anyhow::Error), } @@ -197,8 +199,17 @@ impl FindCommandResult { } pub fn find_command_in_directory>(directory: &Path, command_name: S) -> Self { + + let command_name = command_name.as_ref(); + + let pirita_result = PiritaResult::find_in_directory(&directory, command_name); + if let PiritaResult::Ok(o) = pirita_result { + return FindCommandResult::CommandFoundPirita(o); + } + let manifest_result = ManifestResult::find_in_directory(&directory); let lockfile_result = LockfileResult::find_in_directory(&directory); + match (manifest_result, lockfile_result) { (ManifestResult::ManifestError(e), _) => return FindCommandResult::Error(e.into()), (_, LockfileResult::LockfileError(e)) => return FindCommandResult::Error(e.into()), @@ -219,12 +230,23 @@ impl FindCommandResult { return Self::find_command_in_manifest_and_lockfile(command_name, m, l, directory); } }; - FindCommandResult::CommandNotFound(command_name.as_ref().to_string()) + FindCommandResult::CommandNotFound(command_name.to_string()) } } #[derive(Debug)] -pub struct Command { +pub enum Command { + Pirita(PiritaCommand), + TarGz(TarGzCommand) +} + +#[derive(Debug)] +pub struct PiritaCommand { + pub cmd: String, +} + +#[derive(Debug)] +pub struct TarGzCommand { // PathBuf, Option, String, bool pub source: PathBuf, pub manifest_dir: PathBuf, @@ -253,15 +275,18 @@ pub fn get_command_from_anywhere>(command_name: S) -> Result { - return Ok(Command { + return Ok(Command::TarGz(TarGzCommand { source, manifest_dir, args, module_name, is_global: false, prehashed_cache_key, - }); - } + })); + }, + FindCommandResult::CommandFoundPirita(cmd) => { + return Ok(Command::Pirita(PiritaCommand { cmd })); + }, FindCommandResult::Error(e) => { return Err(Error::ErrorReadingLocalDirectory( command_name.as_ref().to_string(), @@ -287,15 +312,18 @@ pub fn get_command_from_anywhere>(command_name: S) -> Result { - return Ok(Command { + return Ok(Command::TarGz(TarGzCommand { source, manifest_dir, args, module_name, is_global: true, prehashed_cache_key, - }); - } + })); + }, + FindCommandResult::CommandFoundPirita(cmd) => { + return Ok(Command::Pirita(PiritaCommand { cmd })); + }, FindCommandResult::Error(e) => { return Err( Error::CommandNotFoundInLocalDirectoryAndErrorReadingGlobalDirectory( diff --git a/src/dataflow/interfaces.rs b/src/dataflow/interfaces.rs index 93d2b6f9..14470b15 100644 --- a/src/dataflow/interfaces.rs +++ b/src/dataflow/interfaces.rs @@ -33,10 +33,10 @@ impl InterfaceFromServer { } pub fn get(name: String, version: String) -> anyhow::Result { - let response = Self::get_response(name, version)?; + let response = Self::get_response(name.clone(), version.clone())?; let response_val = response .interface - .ok_or_else(|| anyhow!("Error downloading Interface from the server"))?; + .ok_or_else(|| anyhow!("Error downloading Interface from the server: {name}@{version}"))?; Ok(Self { name: response_val.interface.name, version: response_val.version, diff --git a/src/dataflow/mod.rs b/src/dataflow/mod.rs index 15006daa..e809d574 100644 --- a/src/dataflow/mod.rs +++ b/src/dataflow/mod.rs @@ -27,6 +27,7 @@ pub mod local_package; pub mod lockfile_packages; pub mod manifest_packages; pub mod merged_lockfile_packages; +pub mod pirita_packages; pub mod removed_lockfile_packages; pub mod removed_packages; pub mod resolved_packages; @@ -65,6 +66,15 @@ pub struct WapmPackageKey<'a> { pub version: Version, } +#[derive(Clone, Debug, Eq, Hash, PartialOrd, PartialEq)] +pub struct WapmDistribution { + pub name: String, + pub version: String, + pub download_url: String, + pub pirita_download_url: Option, + pub is_last_version: bool, +} + /// A range of versions for a package in the wapm.io registry. #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct WapmPackageRange<'a> { @@ -113,6 +123,14 @@ pub enum PackageKey<'a> { } impl<'a> PackageKey<'a> { + + pub fn get_name(&'a self) -> &'a str { + match self { + PackageKey::WapmPackage(a) => a.name.as_ref(), + PackageKey::WapmPackageRange(a) => a.name.as_ref(), + } + } + /// Convenience constructor for wapm.io registry keys. pub fn new_registry_package(name: S, version: Version) -> Self where @@ -338,13 +356,13 @@ pub fn update_with_manifest>( /// The function that starts lockfile dataflow. This function finds a manifest and a lockfile, /// calculates differences, installs missing dependencies, and finally generates a new lockfile. pub fn update>( - added_packages: Vec<(&str, &str)>, + added_packages: Vec, removed_packages: Vec<&str>, directory: P, ) -> Result { let directory = directory.as_ref(); let added_packages = - AddedPackages::new_from_str_pairs(added_packages).map_err(Error::AddError)?; + AddedPackages::new_from_str_pairs(&added_packages).map_err(Error::AddError)?; let removed_packages = RemovedPackages::new_from_package_names(removed_packages); let manifest_result = ManifestResult::find_in_directory(&directory); match manifest_result { diff --git a/src/dataflow/pirita_packages.rs b/src/dataflow/pirita_packages.rs new file mode 100644 index 00000000..7abfc284 --- /dev/null +++ b/src/dataflow/pirita_packages.rs @@ -0,0 +1,26 @@ +use std::path::Path; +use std::io::Error as IoError; +use std::io::ErrorKind as IoErrorKind; + +/// A ternary for a manifest: Some, None, Error. +#[derive(Debug)] +pub enum PiritaResult { + Ok(String), + Error(IoError) +} + +impl PiritaResult { + pub fn find_in_directory>(directory: P, command: &str) -> Self { + let directory = directory.as_ref(); + match std::fs::read_to_string(directory.join("wapm_packages").join(".bin").join(command)) { + Ok(o) =>{ + if o.starts_with("wasmer run") { + Self::Ok(o) + } else { + Self::Error(IoError::new(IoErrorKind::Other, format!("Command {command:?} does not start with \"wasmer run\""))) + } + }, + Err(e) => Self::Error(e), + } + } +} \ No newline at end of file diff --git a/src/dataflow/resolved_packages.rs b/src/dataflow/resolved_packages.rs index 0ba0f244..338940c9 100644 --- a/src/dataflow/resolved_packages.rs +++ b/src/dataflow/resolved_packages.rs @@ -16,7 +16,7 @@ use thiserror::Error; query_path = "graphql/queries/get_packages.graphql", response_derives = "Debug" )] -struct GetPackagesQuery; +pub struct GetPackagesQuery; #[derive(Clone, Debug, Error)] pub enum Error { diff --git a/src/graphql.rs b/src/graphql.rs index d54bba4d..72e08ea4 100644 --- a/src/graphql.rs +++ b/src/graphql.rs @@ -45,7 +45,8 @@ where F: FnOnce(Form) -> Form, { let client = { - let builder = Client::builder(); + let builder = Client::builder() + .timeout(std::time::Duration::from_secs(500)); #[cfg(not(target_os = "wasi"))] let builder = if let Some(proxy) = proxy::maybe_set_up_proxy()? { diff --git a/src/init.rs b/src/init.rs index 797f2579..fed1a132 100644 --- a/src/init.rs +++ b/src/init.rs @@ -5,7 +5,7 @@ use crate::data::manifest::MANIFEST_FILE_NAME; use crate::data::manifest::{Command, CommandV2, Manifest, Module, Package}; use crate::util; -use dialoguer::{Confirmation, Input, Select}; +use dialoguer::{Confirm, Input, Select}; use semver::Version; use std::{ any::Any, @@ -268,7 +268,7 @@ Press ^C at any time to quit." Command::V2(CommandV2 { name: command_string, runner: runner_for_modules.clone(), - module: module.name.clone(), + module: Some(module.name.clone()), annotations: None, }) }); @@ -276,8 +276,8 @@ Press ^C at any time to quit." all_commands.extend(module_commands); } - let continue_loop = Confirmation::new() - .with_text("Add more commands? (no)") + let continue_loop = Confirm::new() + .with_prompt("Add more modules with a different runner? (no)") .default(false) .interact()?; @@ -314,8 +314,8 @@ Press ^C at any time to quit." ); if force_yes - || Confirmation::new() - .with_text("Is this OK? (yes)") + || Confirm::new() + .with_prompt("Is this OK? (yes)") .default(true) .interact()? { diff --git a/src/util.rs b/src/util.rs index 7fa6f8d6..20b9dc53 100644 --- a/src/util.rs +++ b/src/util.rs @@ -313,18 +313,13 @@ pub fn create_temp_dir() -> Result { #[cfg(target_os = "wasi")] pub fn create_temp_dir() -> Result { let mut buf = [0u8; 4]; - getrandom::getrandom(&mut buf)?; + getrandom::getrandom(&mut buf) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("{e}")))?; let path = format!("/tmp/{:#10x}", u32::from_be_bytes(buf)); let ret: std::path::PathBuf = path.into(); Ok(ret) } -#[cfg(target_os = "wasi")] -pub fn whoami_distro() -> String { - whoami::os().to_lowercase() -} - -#[cfg(not(target_os = "wasi"))] pub fn whoami_distro() -> String { whoami::distro().to_lowercase() } diff --git a/wapm-resolve-url/.gitignore b/wapm-resolve-url/.gitignore new file mode 100644 index 00000000..9f970225 --- /dev/null +++ b/wapm-resolve-url/.gitignore @@ -0,0 +1 @@ +target/ \ No newline at end of file diff --git a/wapm-resolve-url/Cargo.lock b/wapm-resolve-url/Cargo.lock new file mode 100644 index 00000000..12ac15c6 --- /dev/null +++ b/wapm-resolve-url/Cargo.lock @@ -0,0 +1,2116 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "anyhow" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" + +[[package]] +name = "ascii" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" + +[[package]] +name = "async-compression" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "345fd392ab01f746c717b1357165b76f0b67a60192007b234058c9045fdcf695" +dependencies = [ + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "async-trait" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" +dependencies = [ + "byteorder", + "safemem", +] + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] + +[[package]] +name = "buf-read-ext" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e2c71c44e5bbc64de4ecfac946e05f9bba5cc296ea7bab4d3eda242a3ffa73c" + +[[package]] +name = "bumpalo" +version = "3.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "combine" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" +dependencies = [ + "ascii", + "byteorder", + "either", + "memchr", + "unreachable", +] + +[[package]] +name = "convert_case" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb4a24b1aaf0fd0ce8b45161144d6f42cd91677fd5940fd431183eb023b3a2b8" + +[[package]] +name = "cooked-waker" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f" + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ccfd8c0ee4cce11e45b3fd6f9d5e69e0cc62912aa6a0cb1bf4617b0eba5a12f" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "dummy-waker" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea6672d73216c05740850c789368d371ca226dc8104d5f2e30c74252d5d6e5e" + +[[package]] +name = "either" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" + +[[package]] +name = "encoding" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec" +dependencies = [ + "encoding-index-japanese", + "encoding-index-korean", + "encoding-index-simpchinese", + "encoding-index-singlebyte", + "encoding-index-tradchinese", +] + +[[package]] +name = "encoding-index-japanese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-korean" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-simpchinese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87a7194909b9118fc707194baa434a4e3b0fb6a5a757c73c3adb07aa25031f7" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-singlebyte" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-tradchinese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding_index_tests" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" + +[[package]] +name = "encoding_rs" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "failure" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" +dependencies = [ + "backtrace", + "failure_derive", +] + +[[package]] +name = "failure_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + +[[package]] +name = "flate2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding 2.1.0", +] + +[[package]] +name = "formdata" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b2e172b694029467db935166c398f911adce5373d63bb1149740cd9182a3eee" +dependencies = [ + "encoding", + "httparse", + "hyper 0.10.16", + "log 0.4.17", + "mime 0.2.6", + "mime_multipart", + "textnonce", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "futures-channel" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-io" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" + +[[package]] +name = "futures-macro" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" + +[[package]] +name = "futures-task" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-util" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check 0.9.4", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "gimli" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" + +[[package]] +name = "graphql-introspection-query" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "610aac641dbd2a457ad4cef34aa2827dae3f035fd214cb38c2d62d8543f3973f" +dependencies = [ + "serde", +] + +[[package]] +name = "graphql-parser" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5613c31f18676f164112732202124f373bb2103ff017b3b85ca954ea6a66ada" +dependencies = [ + "combine", + "failure", +] + +[[package]] +name = "graphql_client" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0bb4f09181e4f80018d01c612125b07e0156f3753bfac37055fe2a25e031ca8" +dependencies = [ + "doc-comment", + "graphql_query_derive", + "serde", + "serde_json", +] + +[[package]] +name = "graphql_client_codegen" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e304c223c809b3bff4614018f8e6d9edb176b31d64ed9ea48b6ae8b1a03abb9" +dependencies = [ + "failure", + "graphql-introspection-query", + "graphql-parser", + "heck", + "lazy_static", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn", +] + +[[package]] +name = "graphql_query_derive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1f6b14d5ce549227aa9e649cd9d36d008b91021275a8e0a67d71cef815adc2f" +dependencies = [ + "failure", + "graphql_client_codegen", + "proc-macro2", + "syn", +] + +[[package]] +name = "h2" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "607c8a29735385251a339424dd462993c0fed8fa09d378f259377df08c126022" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "http" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.10.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273" +dependencies = [ + "base64 0.9.3", + "httparse", + "language-tags", + "log 0.3.9", + "mime 0.2.6", + "num_cpus", + "time", + "traitobject", + "typeable", + "unicase 1.4.2", + "url 1.7.2", +] + +[[package]] +name = "hyper" +version = "0.14.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" +dependencies = [ + "http", + "hyper 0.14.20", + "rustls", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper 0.14.20", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "idna" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ipnet" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "js-sys" +version = "0.3.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "language-tags" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "log" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" +dependencies = [ + "log 0.4.17", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "mime" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" +dependencies = [ + "log 0.3.9", +] + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime 0.3.16", + "unicase 2.6.0", +] + +[[package]] +name = "mime_multipart" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ce67bf6bb7fd272b2b6dad85be2ad1dadeb717e3336beda9470b44feb978c1" +dependencies = [ + "buf-read-ext", + "encoding", + "httparse", + "hyper 0.10.16", + "log 0.4.17", + "mime 0.2.6", + "tempdir", + "textnonce", +] + +[[package]] +name = "miniz_oxide" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +dependencies = [ + "libc", + "log 0.4.17", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys", +] + +[[package]] +name = "native-tls" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd7e2f3618557f980e0b17e8856252eee3c97fa12c54dff0ca290fb6266ca4a9" +dependencies = [ + "lazy_static", + "libc", + "log 0.4.17", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + +[[package]] +name = "openssl" +version = "0.10.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "618febf65336490dfcf20b73f885f5651a0c89c64c2d4a8c3662585a70bf5bd0" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5f9bd0c2710541a3cda73d6f9ac4f1b240de4ae261065d309dbe73d9dceb42f" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "paste" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" + +[[package]] +name = "percent-encoding" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro2" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom", + "libc", + "rand_chacha", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "reqwest" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75aa69a3f06bbcc66ede33af2af253c6f7a86b1ca0033f60c580a27074fbf92" +dependencies = [ + "async-compression", + "base64 0.13.0", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper 0.14.20", + "hyper-rustls", + "hyper-tls", + "ipnet", + "js-sys", + "lazy_static", + "log 0.4.17", + "mime 0.3.16", + "mime_guess", + "native-tls", + "percent-encoding 2.1.0", + "pin-project-lite", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "tokio-rustls", + "tokio-socks", + "tokio-util", + "tower-service", + "url 2.2.2", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "winreg", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "rmp" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44519172358fd6d58656c86ab8e7fbc9e1490c3e8f14d35ed78ca0dd07403c9f" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "723ecff9ad04f4ad92fe1c8ca6c20d2196d9286e9c60727c4cb5511629260e9d" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + +[[package]] +name = "rustls" +version = "0.20.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033" +dependencies = [ + "log 0.4.17", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7522c9de787ff061458fe9a829dc790a3f5b22dc571694fc5883f448b94d9a9" +dependencies = [ + "base64 0.13.0", +] + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "safemem" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" + +[[package]] +name = "schannel" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +dependencies = [ + "lazy_static", + "windows-sys", +] + +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "security-framework" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0171ebb889e45aa68b44aee0859b3eede84c6f5f5c228e6f140c0b2a0a46cad6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-xml-rs" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65162e9059be2f6a3421ebbb4fef3e74b7d9e7c60c50a0e292c6239f19f1edfa" +dependencies = [ + "log 0.4.17", + "serde", + "thiserror", + "xml-rs", +] + +[[package]] +name = "serde_derive" +version = "1.0.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1d3230c1de7932af58ad8ffbe1d784bd55efd5a9d84ac24f69c72d83543dfb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec0091e1f5aa338283ce049bd9dfefd55e1f168ac233e85c1ffe0038fb48cbe" +dependencies = [ + "indexmap", + "ryu", + "serde", + "yaml-rust", +] + +[[package]] +name = "sha2" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "slab" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "syn" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "tempdir" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" +dependencies = [ + "rand 0.4.6", + "remove_dir_all", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "textnonce" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7743f8d70cd784ed1dc33106a18998d77758d281dc40dc3e6d050cf0f5286683" +dependencies = [ + "base64 0.12.3", + "rand 0.7.3", +] + +[[package]] +name = "thiserror" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57aec3cfa4c296db7255446efb4928a6be304b431a806216105542a67b6ca82e" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "pin-project-lite", + "socket2", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-socks" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51165dfa029d2a65969413a6cc96f354b86b464498702f174a4efa13608fd8c0" +dependencies = [ + "either", + "futures-util", + "thiserror", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" +dependencies = [ + "cfg-if", + "log 0.4.17", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" +dependencies = [ + "once_cell", +] + +[[package]] +name = "traitobject" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "typeable" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicase" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" +dependencies = [ + "version_check 0.1.5", +] + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check 0.9.4", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" + +[[package]] +name = "unicode-normalization" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" + +[[package]] +name = "unicode-xid" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" + +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +dependencies = [ + "void", +] + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "url" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" +dependencies = [ + "idna 0.1.5", + "matches", + "percent-encoding 1.0.1", +] + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna 0.2.3", + "matches", + "percent-encoding 2.1.0", +] + +[[package]] +name = "urlencoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b90931029ab9b034b300b797048cf23723400aa757e8a2bfb9d748102f9821" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log 0.4.17", + "try-lock", +] + +[[package]] +name = "wapm-resolve-url" +version = "0.1.0" +dependencies = [ + "anyhow", + "graphql_client", + "reqwest", + "serde", + "serde_json", + "thiserror", + "url 2.2.2", + "wasm-bus-process", + "wasm-bus-reqwest", + "whoami 0.5.3", + "whoami 1.2.1", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasix" +version = "0.11.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3fb76de32c72156fd25fa56776b4ed3d02fcafddfa36d24fac6b135bc7e9bca" + +[[package]] +name = "wasm-bindgen" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" +dependencies = [ + "bumpalo", + "lazy_static", + "log 0.4.17", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de9a9cec1733468a8c657e57fa2413d2ae2c0129b95e87c5b72b8ace4d13f31f" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" + +[[package]] +name = "wasm-bus" +version = "1.1.0" +source = "git+https://github.com/tokera-com/ate?rev=77b2bca4264e1fcb3d977650c09bb228a782b6f2#77b2bca4264e1fcb3d977650c09bb228a782b6f2" +dependencies = [ + "async-trait", + "base64 0.13.0", + "cooked-waker", + "derivative", + "once_cell", + "serde", + "sha2", + "tokio", + "tracing", + "wasix", + "wasm-bus-macros", + "wasm-bus-types", +] + +[[package]] +name = "wasm-bus-macros" +version = "1.1.0" +source = "git+https://github.com/tokera-com/ate?rev=77b2bca4264e1fcb3d977650c09bb228a782b6f2#77b2bca4264e1fcb3d977650c09bb228a782b6f2" +dependencies = [ + "convert_case", + "derivative", + "proc-macro2", + "quote", + "syn", + "wasm-bus-types", +] + +[[package]] +name = "wasm-bus-process" +version = "1.1.0" +source = "git+https://github.com/tokera-com/ate?rev=77b2bca4264e1fcb3d977650c09bb228a782b6f2#77b2bca4264e1fcb3d977650c09bb228a782b6f2" +dependencies = [ + "async-trait", + "bytes", + "dummy-waker", + "serde", + "tokio", + "tracing", + "wasm-bus", +] + +[[package]] +name = "wasm-bus-reqwest" +version = "1.2.0" +source = "git+https://github.com/tokera-com/ate?rev=77b2bca4264e1fcb3d977650c09bb228a782b6f2#77b2bca4264e1fcb3d977650c09bb228a782b6f2" +dependencies = [ + "async-trait", + "bytes", + "formdata", + "futures-core", + "futures-util", + "http", + "http-body", + "mime_guess", + "pin-project-lite", + "serde", + "serde_json", + "tokio", + "tracing", + "url 2.2.2", + "urlencoding", + "wasm-bus", +] + +[[package]] +name = "wasm-bus-types" +version = "1.1.0" +source = "git+https://github.com/tokera-com/ate?rev=77b2bca4264e1fcb3d977650c09bb228a782b6f2#77b2bca4264e1fcb3d977650c09bb228a782b6f2" +dependencies = [ + "bincode", + "rmp-serde", + "serde", + "serde-xml-rs", + "serde_json", + "serde_yaml", +] + +[[package]] +name = "web-sys" +version = "0.3.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1c760f0d366a6c24a02ed7816e23e691f5d92291f94d15e836006fd11b04daf" +dependencies = [ + "webpki", +] + +[[package]] +name = "whoami" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7154f3f4488071a38189dfd63633df444e7be43b731cc12c41505308fc4972f3" + +[[package]] +name = "whoami" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524b58fa5a20a2fb3014dd6358b70e6579692a56ef6fce928834e488f42f65e8" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + +[[package]] +name = "xml-rs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] diff --git a/wapm-resolve-url/Cargo.toml b/wapm-resolve-url/Cargo.toml new file mode 100644 index 00000000..7068ef4e --- /dev/null +++ b/wapm-resolve-url/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "wapm-resolve-url" +version = "0.1.0" +edition = "2021" + +[dependencies] +url = "2" +graphql_client = "0.9" +serde = { version = "1.0", default-features = false, features = ["derive"] } +thiserror = "1.0" +anyhow = "1.0" +serde_json = "1.0.81" +whoami = "1.2.1" + +[target.'cfg(not(target_os = "wasi"))'.dependencies] +reqwest = { version = "0.11.0", default-features = false, features = ["rustls-tls", "blocking", "json", "gzip","socks", "multipart"] } + +# [target.'cfg(target_os = "wasi")'.dependencies] +# wasm-bus-reqwest = "0.1.0" +# wasm-bus-process = "0.1.0" diff --git a/wapm-resolve-url/graphql/query-url-of-file-pirita.graphql b/wapm-resolve-url/graphql/query-url-of-file-pirita.graphql new file mode 100644 index 00000000..419e78c1 --- /dev/null +++ b/wapm-resolve-url/graphql/query-url-of-file-pirita.graphql @@ -0,0 +1,19 @@ +# Given a package id (namespace/package), returns all the .webc URLs +# - may fail on older registries +query GetPackageQueryPirita ($name: String!) { + package: getPackage(name:$name) { + name + versions { + version + distribution { + piritaDownloadUrl + } + } + lastVersion { + version + distribution { + piritaDownloadUrl + } + } + } +} \ No newline at end of file diff --git a/wapm-resolve-url/graphql/query-url-of-file-targz.graphql b/wapm-resolve-url/graphql/query-url-of-file-targz.graphql new file mode 100644 index 00000000..159efeb9 --- /dev/null +++ b/wapm-resolve-url/graphql/query-url-of-file-targz.graphql @@ -0,0 +1,19 @@ +# Given a package id (namespace/package), returns all the .tar.gz URLs +# - may fail on older registries +query GetPackageQueryTarGz ($name: String!) { + package: getPackage(name:$name) { + name + versions { + version + distribution { + downloadUrl + } + } + lastVersion { + version + distribution { + downloadUrl + } + } + } +} \ No newline at end of file diff --git a/wapm-resolve-url/graphql/schema.graphql b/wapm-resolve-url/graphql/schema.graphql new file mode 100644 index 00000000..f8213c13 --- /dev/null +++ b/wapm-resolve-url/graphql/schema.graphql @@ -0,0 +1,1384 @@ +type APIToken { + createdAt: DateTime! + id: ID! + identifier: String + lastUsedAt: DateTime + revokedAt: DateTime + user: User! +} + +type APITokenConnection { + # Contains the nodes in this connection. + edges: [APITokenEdge]! + + # Pagination data for this connection. + pageInfo: PageInfo! +} + +# A Relay edge containing a `APIToken` and its cursor. +type APITokenEdge { + # A cursor for use in pagination + cursor: String! + + # The item at the end of the edge + node: APIToken +} + +input AcceptNamespaceCollaboratorInviteInput { + clientMutationId: String + inviteId: ID! +} + +type AcceptNamespaceCollaboratorInvitePayload { + clientMutationId: String + namespaceCollaboratorInvite: NamespaceCollaboratorInvite! +} + +input AcceptPackageCollaboratorInviteInput { + clientMutationId: String + inviteId: ID! +} + +type AcceptPackageCollaboratorInvitePayload { + clientMutationId: String + packageCollaboratorInvite: PackageCollaboratorInvite! +} + +input AcceptPackageTransferRequestInput { + clientMutationId: String + packageTransferRequestId: ID! +} + +type AcceptPackageTransferRequestPayload { + clientMutationId: String + package: Package! + packageTransferRequest: PackageTransferRequest! +} + +type ActivityEvent implements Node { + actorIcon: String! + body: ActivityEventBody! + createdAt: DateTime! + + # The ID of the object + id: ID! +} + +type ActivityEventBody { + ranges: [NodeBodyRange!]! + text: String! +} + +type ActivityEventConnection { + # Contains the nodes in this connection. + edges: [ActivityEventEdge]! + + # Pagination data for this connection. + pageInfo: PageInfo! +} + +# A Relay edge containing a `ActivityEvent` and its cursor. +type ActivityEventEdge { + # A cursor for use in pagination + cursor: String! + + # The item at the end of the edge + node: ActivityEvent +} + +input ArchivePackageInput { + clientMutationId: String + packageId: ID! +} + +type ArchivePackagePayload { + clientMutationId: String + package: Package! +} + +input ChangePackageVersionArchivedStatusInput { + clientMutationId: String + isArchived: Boolean + packageVersionId: ID! +} + +type ChangePackageVersionArchivedStatusPayload { + clientMutationId: String + packageVersion: PackageVersion! +} + +input ChangeUserEmailInput { + clientMutationId: String + newEmail: String! +} + +type ChangeUserEmailPayload { + clientMutationId: String + user: User! +} + +input ChangeUserPasswordInput { + clientMutationId: String + password: String! + + # The token associated to change the password. If not existing it will use the request user by default + token: String +} + +type ChangeUserPasswordPayload { + clientMutationId: String + token: String +} + +input ChangeUserUsernameInput { + clientMutationId: String + + # The new user username + username: String! +} + +type ChangeUserUsernamePayload { + clientMutationId: String + token: String + user: User +} + +input CheckUserExistsInput { + clientMutationId: String + + # The user + user: String! +} + +type CheckUserExistsPayload { + clientMutationId: String + exists: Boolean! + + # The user is only returned if the user input was the username + user: User +} + +type Command { + command: String! + module: PackageVersionModule! + packageVersion: PackageVersion! +} + +input CreateNamespaceInput { + # The namespace avatar + avatar: String + clientMutationId: String + + # The namespace description + description: String + + # The namespace display name + displayName: String + name: String! +} + +type CreateNamespacePayload { + clientMutationId: String + namespace: Namespace! + user: User! +} + +# The `DateTime` scalar type represents a DateTime +# value as specified by +# [iso8601](https://en.wikipedia.org/wiki/ISO_8601). +scalar DateTime + +input DeleteNamespaceInput { + clientMutationId: String + namespaceId: ID! +} + +type DeleteNamespacePayload { + clientMutationId: String + success: Boolean! +} + +type ErrorType { + field: String! + messages: [String!]! +} + +input GenerateAPITokenInput { + clientMutationId: String + identifier: String +} + +type GenerateAPITokenPayload { + clientMutationId: String + token: APIToken + tokenRaw: String + user: User +} + +# The `GenericScalar` scalar type represents a generic +# GraphQL scalar value that could be: +# String, Boolean, Int, Float, List or Object. +scalar GenericScalar + +type GetPasswordResetToken { + user: User + valid: Boolean! +} + +union GlobalObject = Namespace | User + +input InputSignature { + data: String! + publicKeyKeyId: String! +} + +type Interface implements Node { + createdAt: DateTime! + description: String! + displayName: String! + homepage: String + icon: String + + # The ID of the object + id: ID! + lastVersion: InterfaceVersion + name: String! + updatedAt: DateTime! + versions(after: String = null, before: String = null, first: Int = null, last: Int = null, offset: Int = null): InterfaceVersionConnection! +} + +type InterfaceVersion implements Node { + content: String! + createdAt: DateTime! + + # The ID of the object + id: ID! + interface: Interface! + packageVersions(after: String = null, before: String = null, first: Int = null, last: Int = null, offset: Int = null): PackageVersionConnection! + publishedBy: User! + updatedAt: DateTime! + version: String! +} + +type InterfaceVersionConnection { + # Contains the nodes in this connection. + edges: [InterfaceVersionEdge]! + + # Pagination data for this connection. + pageInfo: PageInfo! +} + +# A Relay edge containing a `InterfaceVersion` and its cursor. +type InterfaceVersionEdge { + # A cursor for use in pagination + cursor: String! + + # The item at the end of the edge + node: InterfaceVersion +} + +input InviteNamespaceCollaboratorInput { + clientMutationId: String + email: String + namespaceId: ID! + role: Role! + username: String +} + +type InviteNamespaceCollaboratorPayload { + clientMutationId: String + invite: NamespaceCollaboratorInvite! + namespace: Namespace! +} + +input InvitePackageCollaboratorInput { + clientMutationId: String + email: String + packageName: String! + role: Role! + username: String +} + +type InvitePackageCollaboratorPayload { + clientMutationId: String + invite: PackageCollaboratorInvite! + package: Package! +} + +input LikePackageInput { + clientMutationId: String + packageId: ID! +} + +type LikePackagePayload { + clientMutationId: String + package: Package! +} + +interface Likeable { + id: ID! + likersCount: Int! + viewerHasLiked: Boolean! +} + +type Mutation { + acceptNamespaceCollaboratorInvite(input: AcceptNamespaceCollaboratorInviteInput!): AcceptNamespaceCollaboratorInvitePayload + acceptPackageCollaboratorInvite(input: AcceptPackageCollaboratorInviteInput!): AcceptPackageCollaboratorInvitePayload + acceptPackageTransferRequest(input: AcceptPackageTransferRequestInput!): AcceptPackageTransferRequestPayload + archivePackage(input: ArchivePackageInput!): ArchivePackagePayload + changePackageVersionArchivedStatus(input: ChangePackageVersionArchivedStatusInput!): ChangePackageVersionArchivedStatusPayload + changeUserEmail(input: ChangeUserEmailInput!): ChangeUserEmailPayload + changeUserPassword(input: ChangeUserPasswordInput!): ChangeUserPasswordPayload + changeUserUsername(input: ChangeUserUsernameInput!): ChangeUserUsernamePayload + checkUserExists(input: CheckUserExistsInput!): CheckUserExistsPayload + createNamespace(input: CreateNamespaceInput!): CreateNamespacePayload + deleteNamespace(input: DeleteNamespaceInput!): DeleteNamespacePayload + generateApiToken(input: GenerateAPITokenInput!): GenerateAPITokenPayload + inviteNamespaceCollaborator(input: InviteNamespaceCollaboratorInput!): InviteNamespaceCollaboratorPayload + invitePackageCollaborator(input: InvitePackageCollaboratorInput!): InvitePackageCollaboratorPayload + likePackage(input: LikePackageInput!): LikePackagePayload + publishPackage(input: PublishPackageInput!): PublishPackagePayload + publishPublicKey(input: PublishPublicKeyInput!): PublishPublicKeyPayload + readNotification(input: ReadNotificationInput!): ReadNotificationPayload + refreshToken(input: RefreshInput!): RefreshPayload + registerUser(input: RegisterUserInput!): RegisterUserPayload + removeNamespaceCollaborator(input: RemoveNamespaceCollaboratorInput!): RemoveNamespaceCollaboratorPayload + removeNamespaceCollaboratorInvite(input: RemoveNamespaceCollaboratorInviteInput!): RemoveNamespaceCollaboratorInvitePayload + removePackageCollaborator(input: RemovePackageCollaboratorInput!): RemovePackageCollaboratorPayload + removePackageCollaboratorInvite(input: RemovePackageCollaboratorInviteInput!): RemovePackageCollaboratorInvitePayload + removePackageTransferRequest(input: RemovePackageTransferRequestInput!): RemovePackageTransferRequestPayload + requestPackageTransfer(input: RequestPackageTransferInput!): RequestPackageTransferPayload + requestPasswordReset(input: RequestPasswordResetInput!): RequestPasswordResetPayload + requestValidationEmail(input: RequestValidationEmailInput!): RequestValidationEmailPayload + revokeApiToken(input: RevokeAPITokenInput!): RevokeAPITokenPayload + seePendingNotifications(input: SeePendingNotificationsInput!): SeePendingNotificationsPayload + + # Social Auth for JSON Web Token (JWT) + socialAuth(input: SocialAuthJWTInput!): SocialAuthJWTPayload + + # Obtain JSON Web Token mutation + tokenAuth(input: ObtainJSONWebTokenInput!): ObtainJSONWebTokenPayload + unlikePackage(input: UnlikePackageInput!): UnlikePackagePayload + unwatchPackage(input: UnwatchPackageInput!): UnwatchPackagePayload + updateNamespace(input: UpdateNamespaceInput!): UpdateNamespacePayload + updateNamespaceCollaboratorRole(input: UpdateNamespaceCollaboratorRoleInput!): UpdateNamespaceCollaboratorRolePayload + updatePackage(input: UpdatePackageInput!): UpdatePackagePayload + updatePackageCollaboratorRole(input: UpdatePackageCollaboratorRoleInput!): UpdatePackageCollaboratorRolePayload + updateUserInfo(input: UpdateUserInfoInput!): UpdateUserInfoPayload + validateUserEmail(input: ValidateUserEmailInput!): ValidateUserEmailPayload + validateUserPassword(input: ValidateUserPasswordInput!): ValidateUserPasswordPayload + verifyToken(input: VerifyInput!): VerifyPayload + watchPackage(input: WatchPackageInput!): WatchPackagePayload +} + +type Namespace implements Node & PackageOwner { + avatar: String! + avatarUpdatedAt: DateTime + collaborators(after: String = null, before: String = null, first: Int = null, last: Int = null): NamespaceCollaboratorConnection + createdAt: DateTime! + description: String! + displayName: String + globalName: String! + + # The ID of the object + id: ID! + maintainerInvites: [NamespaceCollaboratorInvite!]! + maintainersWithRoles(after: String = null, before: String = null, first: Int = null, last: Int = null, offset: Int = null): NamespaceMaintainerConnection! + name: String! + packageVersions(after: String = null, before: String = null, first: Int = null, last: Int = null): PackageVersionConnection + packages(after: String = null, before: String = null, first: Int = null, last: Int = null): PackageConnection + pendingInvites(after: String = null, before: String = null, first: Int = null, last: Int = null): NamespaceCollaboratorInviteConnection + publicActivity(after: String = null, before: String = null, first: Int = null, last: Int = null): ActivityEventConnection! + updatedAt: DateTime! + userSet(after: String = null, before: String = null, first: Int = null, last: Int = null, offset: Int = null): UserConnection! + viewerHasRole(role: Role!): Boolean! +} + +type NamespaceCollaborator { + createdAt: DateTime! + id: ID! + invite: NamespaceCollaboratorInvite + namespace: Namespace! + role: RegistryNamespaceMaintainerRoleChoices! + updatedAt: DateTime! + user: User! +} + +type NamespaceCollaboratorConnection { + # Contains the nodes in this connection. + edges: [NamespaceCollaboratorEdge]! + + # Pagination data for this connection. + pageInfo: PageInfo! +} + +# A Relay edge containing a `NamespaceCollaborator` and its cursor. +type NamespaceCollaboratorEdge { + # A cursor for use in pagination + cursor: String! + + # The item at the end of the edge + node: NamespaceCollaborator +} + +type NamespaceCollaboratorInvite { + accepted: NamespaceMaintainer + approvedBy: User + closedAt: DateTime + createdAt: DateTime! + declinedBy: User + expiresAt: DateTime! + id: ID! + inviteEmail: String + namespace: Namespace! + requestedBy: User! + role: RegistryNamespaceMaintainerInviteRoleChoices! + user: User +} + +type NamespaceCollaboratorInviteConnection { + # Contains the nodes in this connection. + edges: [NamespaceCollaboratorInviteEdge]! + + # Pagination data for this connection. + pageInfo: PageInfo! +} + +# A Relay edge containing a `NamespaceCollaboratorInvite` and its cursor. +type NamespaceCollaboratorInviteEdge { + # A cursor for use in pagination + cursor: String! + + # The item at the end of the edge + node: NamespaceCollaboratorInvite +} + +type NamespaceConnection { + # Contains the nodes in this connection. + edges: [NamespaceEdge]! + + # Pagination data for this connection. + pageInfo: PageInfo! +} + +# A Relay edge containing a `Namespace` and its cursor. +type NamespaceEdge { + # A cursor for use in pagination + cursor: String! + + # The item at the end of the edge + node: Namespace +} + +type NamespaceMaintainer implements Node { + createdAt: DateTime! + + # The ID of the object + id: ID! + invite: NamespaceCollaboratorInvite + namespace: Namespace! + role: RegistryNamespaceMaintainerRoleChoices! + updatedAt: DateTime! + user: User! +} + +type NamespaceMaintainerConnection { + # Contains the nodes in this connection. + edges: [NamespaceMaintainerEdge]! + + # Pagination data for this connection. + pageInfo: PageInfo! +} + +# A Relay edge containing a `NamespaceMaintainer` and its cursor. +type NamespaceMaintainerEdge { + # A cursor for use in pagination + cursor: String! + + # The item at the end of the edge + node: NamespaceMaintainer +} + +# An object with an ID +interface Node { + # The ID of the object + id: ID! +} + +type NodeBodyRange { + entity: Node! + length: Int! + offset: Int! +} + +input ObtainJSONWebTokenInput { + clientMutationId: String + password: String! + username: String! +} + +# Obtain JSON Web Token mutation +type ObtainJSONWebTokenPayload { + clientMutationId: String + payload: GenericScalar! + refreshExpiresIn: Int! + refreshToken: String! + token: String! +} + +type Package implements Likeable & Node & PackageOwner { + alias: String + + # The app icon. It should be formatted in the same way as Apple icons + appIcon: String! @deprecated(reason: "Please use icon instead") + collaborators(after: String = null, before: String = null, first: Int = null, last: Int = null): PackageCollaboratorConnection + createdAt: DateTime! + curated: Boolean! + displayName: String! + + # The total number of downloads of the package + downloadsCount: Int + globalName: String! + + # The app icon. It should be formatted in the same way as Apple icons + icon: String! + iconUpdatedAt: DateTime + + # The ID of the object + id: ID! + isTransferring: Boolean! + lastVersion: PackageVersion + likeCount: Int! + likersCount: Int! + maintainers: [User]! @deprecated(reason: "Please use collaborators instead") + name: String! + namespace: String + owner: PackageOwner + ownerObjectId: Int! + + # The name of the package without the owner + packageName: String! + pendingInvites(after: String = null, before: String = null, first: Int = null, last: Int = null): PackageCollaboratorInviteConnection + private: Boolean! + + # The public keys for all the published versions + publicKeys: [PublicKey!]! + updatedAt: DateTime! + versions: [PackageVersion] + viewerHasLiked: Boolean! + viewerHasRole(role: Role!): Boolean! + viewerIsWatching: Boolean! + watchCount: Int! +} + +type PackageCollaborator implements Node { + createdAt: DateTime! + + # The ID of the object + id: ID! + invite: PackageCollaboratorInvite + package: Package! + role: RegistryPackageMaintainerRoleChoices! + updatedAt: DateTime! + user: User! +} + +type PackageCollaboratorConnection { + # Contains the nodes in this connection. + edges: [PackageCollaboratorEdge]! + + # Pagination data for this connection. + pageInfo: PageInfo! +} + +# A Relay edge containing a `PackageCollaborator` and its cursor. +type PackageCollaboratorEdge { + # A cursor for use in pagination + cursor: String! + + # The item at the end of the edge + node: PackageCollaborator +} + +type PackageCollaboratorInvite implements Node { + accepted: PackageCollaborator + approvedBy: User + closedAt: DateTime + createdAt: DateTime! + declinedBy: User + expiresAt: DateTime! + + # The ID of the object + id: ID! + inviteEmail: String + package: Package! + requestedBy: User! + role: RegistryPackageMaintainerInviteRoleChoices! + user: User +} + +type PackageCollaboratorInviteConnection { + # Contains the nodes in this connection. + edges: [PackageCollaboratorInviteEdge]! + + # Pagination data for this connection. + pageInfo: PageInfo! +} + +# A Relay edge containing a `PackageCollaboratorInvite` and its cursor. +type PackageCollaboratorInviteEdge { + # A cursor for use in pagination + cursor: String! + + # The item at the end of the edge + node: PackageCollaboratorInvite +} + +type PackageConnection { + # Contains the nodes in this connection. + edges: [PackageEdge]! + + # Pagination data for this connection. + pageInfo: PageInfo! +} + +type PackageDistribution { + downloadUrl: String! + size: Int! + piritaDownloadUrl: String + piritaSize: Int +} + +# A Relay edge containing a `Package` and its cursor. +type PackageEdge { + # A cursor for use in pagination + cursor: String! + + # The item at the end of the edge + node: Package +} + +interface PackageOwner { + globalName: String! +} + +type PackageTransferRequest implements Node { + approvedBy: User + closedAt: DateTime + createdAt: DateTime! + declinedBy: User + expiresAt: DateTime! + + # The ID of the object + id: ID! + newOwnerObjectId: Int! + package: Package! + previousOwnerObjectId: Int! + requestedBy: User! +} + +type PackageTransferRequestConnection { + # Contains the nodes in this connection. + edges: [PackageTransferRequestEdge]! + + # Pagination data for this connection. + pageInfo: PageInfo! +} + +# A Relay edge containing a `PackageTransferRequest` and its cursor. +type PackageTransferRequestEdge { + # A cursor for use in pagination + cursor: String! + + # The item at the end of the edge + node: PackageTransferRequest +} + +type PackageVersion implements Node { + commands: [Command!]! + createdAt: DateTime! + description: String! + distribution: PackageDistribution! + file: String! + fileSize: Int! + filesystem: [PackageVersionFilesystem]! + homepage: String + + # The ID of the object + id: ID! + isArchived: Boolean! + isLastVersion: Boolean! + isSigned: Boolean! + license: String + licenseFile: String + manifest: String! + moduleInterfaces: [InterfaceVersion!]! + modules: [PackageVersionModule!]! + package: Package! + publishedBy: User! + readme: String + repository: String + signature: Signature + updatedAt: DateTime! + version: String! +} + +type PackageVersionConnection { + # Contains the nodes in this connection. + edges: [PackageVersionEdge]! + + # Pagination data for this connection. + pageInfo: PageInfo! +} + +# A Relay edge containing a `PackageVersion` and its cursor. +type PackageVersionEdge { + # A cursor for use in pagination + cursor: String! + + # The item at the end of the edge + node: PackageVersion +} + +type PackageVersionFilesystem { + host: String! + wasm: String! +} + +type PackageVersionModule { + abi: String + name: String! + publicUrl: String! + source: String! +} + +# The Relay compliant `PageInfo` type, containing data necessary to paginate this connection. +type PageInfo { + # When paginating forwards, the cursor to continue. + endCursor: String + + # When paginating forwards, are there more items? + hasNextPage: Boolean! + + # When paginating backwards, are there more items? + hasPreviousPage: Boolean! + + # When paginating backwards, the cursor to continue. + startCursor: String +} + +type PublicKey implements Node { + # The ID of the object + id: ID! + key: String! + keyId: String! + owner: User! + revoked: Boolean! + revokedAt: DateTime + uploadedAt: DateTime! + verifyingSignature: Signature +} + +input PublishPackageInput { + clientMutationId: String + description: String! + file: String + homepage: String + + # The package icon + icon: String + license: String + licenseFile: String + manifest: String! + name: String! + readme: String + repository: String + signature: InputSignature + version: String! +} + +type PublishPackagePayload { + clientMutationId: String + packageVersion: PackageVersion! + success: Boolean! +} + +input PublishPublicKeyInput { + clientMutationId: String + key: String! + keyId: String! + verifyingSignatureId: String +} + +type PublishPublicKeyPayload { + clientMutationId: String + publicKey: PublicKey! + success: Boolean! +} + +type Query { + getCommand(name: String!): Command + getCommands(names: [String!]!): [Command] + getContract(name: String!): Interface @deprecated(reason: "Please use getInterface instead") + getContractVersion(name: String!, version: String = null): InterfaceVersion @deprecated(reason: "Please use getInterfaceVersion instead") + getContracts(names: [String!]!): [Interface]! @deprecated(reason: "Please use getInterfaces instead") + getGlobalObject(slug: String!): GlobalObject + getInterface(name: String!): Interface + getInterfaceVersion(name: String!, version: String = "latest"): InterfaceVersion + getInterfaces(names: [String!]!): [Interface]! + getNamespace(name: String!): Namespace + getPackage(name: String!): Package + getPackageVersion(name: String!, version: String = "latest"): PackageVersion + getPackageVersions(names: [String!]!): [PackageVersion] + getPackages(names: [String!]!): [Package]! + getPasswordResetToken(token: String!): GetPasswordResetToken + getUser(username: String!): User + node( + # The ID of the object + id: ID! + ): Node + packages(after: String = null, before: String = null, first: Int = null, last: Int = null): PackageConnection + recentPackageVersions(after: String = null, before: String = null, curated: Boolean = null, first: Int = null, last: Int = null, offset: Int = null): PackageVersionConnection + search(after: String = null, before: String = null, curated: Boolean = null, first: Int = null, hasBindings: Boolean = null, isStandalone: Boolean = null, kind: [SearchKind!] = null, last: Int = null, orderBy: SearchOrderBy = null, publishDate: SearchPublishDate = null, query: String!, sort: SearchOrderSort = null, withInterfaces: [String!] = null): SearchConnection! + searchAutocomplete(after: String = null, before: String = null, first: Int = null, kind: [SearchKind!] = null, last: Int = null, query: String!): SearchConnection! + viewer: User +} + +input ReadNotificationInput { + clientMutationId: String + notificationId: ID! +} + +type ReadNotificationPayload { + clientMutationId: String + notification: UserNotification +} + +input RefreshInput { + clientMutationId: String + refreshToken: String +} + +type RefreshPayload { + clientMutationId: String + payload: GenericScalar! + refreshExpiresIn: Int! + refreshToken: String! + token: String! +} + +input RegisterUserInput { + clientMutationId: String + email: String! + fullName: String! + password: String! + username: String! +} + +type RegisterUserPayload { + clientMutationId: String + token: String +} + +# An enumeration. +enum RegistryNamespaceMaintainerInviteRoleChoices { + # Admin + ADMIN + + # Editor + EDITOR + + # Viewer + VIEWER +} + +# An enumeration. +enum RegistryNamespaceMaintainerRoleChoices { + # Admin + ADMIN + + # Editor + EDITOR + + # Viewer + VIEWER +} + +# An enumeration. +enum RegistryPackageMaintainerInviteRoleChoices { + # Admin + ADMIN + + # Editor + EDITOR + + # Viewer + VIEWER +} + +# An enumeration. +enum RegistryPackageMaintainerRoleChoices { + # Admin + ADMIN + + # Editor + EDITOR + + # Viewer + VIEWER +} + +input RemoveNamespaceCollaboratorInput { + clientMutationId: String + namespaceCollaboratorId: ID! +} + +input RemoveNamespaceCollaboratorInviteInput { + clientMutationId: String + inviteId: ID! +} + +type RemoveNamespaceCollaboratorInvitePayload { + clientMutationId: String + namespace: Namespace! +} + +type RemoveNamespaceCollaboratorPayload { + clientMutationId: String + namespace: Namespace! +} + +input RemovePackageCollaboratorInput { + clientMutationId: String + packageCollaboratorId: ID! +} + +input RemovePackageCollaboratorInviteInput { + clientMutationId: String + inviteId: ID! +} + +type RemovePackageCollaboratorInvitePayload { + clientMutationId: String + package: Package! +} + +type RemovePackageCollaboratorPayload { + clientMutationId: String + package: Package! +} + +input RemovePackageTransferRequestInput { + clientMutationId: String + packageTransferRequestId: ID! +} + +type RemovePackageTransferRequestPayload { + clientMutationId: String + package: Package! +} + +input RequestPackageTransferInput { + clientMutationId: String + newOwnerId: ID! + packageId: ID! +} + +type RequestPackageTransferPayload { + clientMutationId: String + package: Package! +} + +input RequestPasswordResetInput { + clientMutationId: String + email: String! +} + +type RequestPasswordResetPayload { + clientMutationId: String + email: String! + errors: [ErrorType] +} + +input RequestValidationEmailInput { + clientMutationId: String + + # The user id + userId: ID +} + +type RequestValidationEmailPayload { + clientMutationId: String + success: Boolean! + user: User +} + +input RevokeAPITokenInput { + clientMutationId: String + + # The API token ID + tokenId: ID! +} + +type RevokeAPITokenPayload { + clientMutationId: String + success: Boolean + token: APIToken +} + +enum Role { + ADMIN + EDITOR + VIEWER +} + +type SearchConnection { + # Contains the nodes in this connection. + edges: [SearchEdge]! + + # Pagination data for this connection. + pageInfo: PageInfo! +} + +# A Relay edge containing a `Search` and its cursor. +type SearchEdge { + # A cursor for use in pagination + cursor: String! + + # The item at the end of the edge + node: SearchResult +} + +enum SearchKind { + NAMESPACE + PACKAGE + USER +} + +enum SearchOrderBy { + ALPHABETICALLY + PUBLISHED_DATE + SIZE + TOTAL_DOWNLOADS +} + +enum SearchOrderSort { + ASC + DESC +} + +enum SearchPublishDate { + LAST_DAY + LAST_MONTH + LAST_WEEK + LAST_YEAR +} + +union SearchResult = Namespace | PackageVersion | User + +input SeePendingNotificationsInput { + clientMutationId: String +} + +type SeePendingNotificationsPayload { + clientMutationId: String + success: Boolean +} + +type Signature { + createdAt: DateTime! + data: String! + id: ID! + publicKey: PublicKey! +} + +input SocialAuthJWTInput { + accessToken: String! + clientMutationId: String + provider: String! +} + +# Social Auth for JSON Web Token (JWT) +type SocialAuthJWTPayload { + clientMutationId: String + social: SocialNode + token: String +} + +scalar SocialCamelJSON + +type SocialNode implements Node { + created: DateTime! + extraData: SocialCamelJSON + + # The ID of the object + id: ID! + modified: DateTime! + provider: String! + uid: String! + user: User! +} + +type Subscription { + packageVersionCreated(ownerId: ID = null, publishedBy: ID = null): PackageVersion! + userNotificationCreated(userId: ID!): UserNotificationCreated! +} + +input UnlikePackageInput { + clientMutationId: String + packageId: ID! +} + +type UnlikePackagePayload { + clientMutationId: String + package: Package! +} + +input UnwatchPackageInput { + clientMutationId: String + packageId: ID! +} + +type UnwatchPackagePayload { + clientMutationId: String + package: Package! +} + +input UpdateNamespaceCollaboratorRoleInput { + clientMutationId: String + namespaceCollaboratorId: ID! + role: Role! +} + +type UpdateNamespaceCollaboratorRolePayload { + clientMutationId: String + collaborator: NamespaceCollaborator! +} + +input UpdateNamespaceInput { + # The namespace avatar + avatar: String + clientMutationId: String + + # The namespace description + description: String + + # The namespace display name + displayName: String + + # The namespace slug name + name: String + namespaceId: ID! +} + +type UpdateNamespacePayload { + clientMutationId: String + namespace: Namespace! +} + +input UpdatePackageCollaboratorRoleInput { + clientMutationId: String + packageCollaboratorId: ID! + role: Role! +} + +type UpdatePackageCollaboratorRolePayload { + clientMutationId: String + collaborator: PackageCollaborator! +} + +input UpdatePackageInput { + clientMutationId: String + + # The package icon + icon: String + packageId: ID! +} + +type UpdatePackagePayload { + clientMutationId: String + package: Package! +} + +input UpdateUserInfoInput { + # The user avatar + avatar: String + + # The user bio + bio: String + clientMutationId: String + + # The user full name + fullName: String + + # The user Github (it can be the url, or the handle with or without the @) + github: String + + # The user location + location: String + + # The user Twitter (it can be the url, or the handle with or without the @) + twitter: String + + # The user id + userId: ID + + # The user website (it must be a valid url) + websiteUrl: String +} + +type UpdateUserInfoPayload { + clientMutationId: String + user: User +} + +type User implements Node & PackageOwner { + apiTokens(after: String = null, before: String = null, first: Int = null, last: Int = null): APITokenConnection + avatar(size: Int = 80): String! + bio: String + dateJoined: DateTime! + email: String! + firstName: String! + fullName: String! + githubUrl: String + globalName: String! + + # The ID of the object + id: ID! + isEmailValidated: Boolean! + isViewer: Boolean! + lastName: String! + location: String + namespaceInvitesIncoming(after: String = null, before: String = null, first: Int = null, last: Int = null): NamespaceCollaboratorInviteConnection + namespaces(after: String = null, before: String = null, first: Int = null, last: Int = null): NamespaceConnection + notifications(after: String = null, before: String = null, first: Int = null, last: Int = null): UserNotificationConnection + packageInvitesIncoming(after: String = null, before: String = null, first: Int = null, last: Int = null): PackageCollaboratorInviteConnection + packageTransfersIncoming(after: String = null, before: String = null, first: Int = null, last: Int = null): PackageTransferRequestConnection + packageVersions(after: String = null, before: String = null, first: Int = null, last: Int = null): PackageVersionConnection + packages(after: String = null, before: String = null, collaborating: Boolean = null, first: Int = null, last: Int = null): PackageConnection + publicActivity(after: String = null, before: String = null, first: Int = null, last: Int = null): ActivityEventConnection! + twitterUrl: String + + # Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only. + username: String! + websiteUrl: String +} + +type UserConnection { + # Contains the nodes in this connection. + edges: [UserEdge]! + + # Pagination data for this connection. + pageInfo: PageInfo! +} + +# A Relay edge containing a `User` and its cursor. +type UserEdge { + # A cursor for use in pagination + cursor: String! + + # The item at the end of the edge + node: User +} + +type UserNotification implements Node { + body: UserNotificationBody! + createdAt: DateTime! + icon: String + + # The ID of the object + id: ID! + kind: UserNotificationKind + seenState: UserNotificationSeenState! +} + +type UserNotificationBody { + ranges: [NodeBodyRange]! + text: String! +} + +type UserNotificationConnection { + # Contains the nodes in this connection. + edges: [UserNotificationEdge]! + hasPendingNotifications: Boolean! + + # Pagination data for this connection. + pageInfo: PageInfo! +} + +type UserNotificationCreated { + notification: UserNotification + notificationDeletedId: ID +} + +# A Relay edge containing a `UserNotification` and its cursor. +type UserNotificationEdge { + # A cursor for use in pagination + cursor: String! + + # The item at the end of the edge + node: UserNotification +} + +union UserNotificationKind = UserNotificationKindIncomingPackageInvite | UserNotificationKindIncomingPackageTransfer | UserNotificationKindPublishedPackageVersion + +type UserNotificationKindIncomingPackageInvite { + packageInvite: PackageCollaboratorInvite! +} + +type UserNotificationKindIncomingPackageTransfer { + packageTransferRequest: PackageTransferRequest! +} + +type UserNotificationKindPublishedPackageVersion { + packageVersion: PackageVersion! +} + +enum UserNotificationSeenState { + SEEN + SEEN_AND_READ + UNSEEN +} + +input ValidateUserEmailInput { + challenge: String! + clientMutationId: String + + # The user id + userId: ID +} + +type ValidateUserEmailPayload { + clientMutationId: String + user: User +} + +input ValidateUserPasswordInput { + clientMutationId: String + password: String! +} + +type ValidateUserPasswordPayload { + clientMutationId: String + success: Boolean +} + +input VerifyInput { + clientMutationId: String + token: String +} + +type VerifyPayload { + clientMutationId: String + payload: GenericScalar! +} + +input WatchPackageInput { + clientMutationId: String + packageId: ID! +} + +type WatchPackagePayload { + clientMutationId: String + package: Package! +} diff --git a/wapm-resolve-url/src/graphql.rs b/wapm-resolve-url/src/graphql.rs new file mode 100644 index 00000000..4334f8cf --- /dev/null +++ b/wapm-resolve-url/src/graphql.rs @@ -0,0 +1,102 @@ +use graphql_client::{QueryBody, Response}; +use serde; +use std::env; +use std::string::ToString; +use thiserror::Error; +use crate::whoami_distro; +use url::Url; + +#[cfg(not(target_os = "wasi"))] +use { + crate::proxy, + reqwest::{ + blocking::{multipart::Form, Client}, + header::USER_AGENT, + }, +}; +// #[cfg(target_os = "wasi")] +// use {wasm_bus_reqwest::prelude::header::*, wasm_bus_reqwest::prelude::*}; + +#[derive(Debug, Error)] +enum GraphQLError { + #[error("{message}")] + Error { message: String }, +} + +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); + +#[cfg(not(target_os = "wasi"))] +pub fn execute_query_modifier(registry: &Url, query: &QueryBody, form_modifier: F) -> anyhow::Result +where + for<'de> R: serde::Deserialize<'de>, + V: serde::Serialize, + F: FnOnce(Form) -> Form, +{ + let client = { + let builder = Client::builder(); + + #[cfg(not(target_os = "wasi"))] + let builder = if let Some(proxy) = proxy::maybe_set_up_proxy()? { + builder.proxy(proxy) + } else { + builder + }; + builder.build()? + }; + + let registry_url = registry; + + let vars = serde_json::to_string(&query.variables).unwrap(); + + let form = Form::new() + .text("query", query.query.to_string()) + .text("operationName", query.operation_name.to_string()) + .text("variables", vars); + + let form = form_modifier(form); + + let user_agent = format!( + "wapm/{} {} {}", + VERSION, + whoami::platform(), + whoami_distro(), + ); + + let res = client + .post(registry_url.clone()) + .multipart(form) + .bearer_auth( + env::var("WAPM_REGISTRY_TOKEN") + .unwrap_or_default() + ) + .header(USER_AGENT, user_agent) + .send()?; + + let response_body: Response = res.json()?; + if let Some(errors) = response_body.errors { + let error_messages: Vec = errors.into_iter().map(|err| err.message).collect(); + return Err(GraphQLError::Error { + message: error_messages.join(", "), + } + .into()); + } + Ok(response_body.data.expect("missing response data")) +} + +#[cfg(not(target_os = "wasi"))] +pub fn execute_query(registry: &Url, query: &QueryBody) -> anyhow::Result +where + for<'de> R: serde::Deserialize<'de>, + V: serde::Serialize, +{ + execute_query_modifier(registry, query, |f| f) +} + +#[cfg(target_os = "wasi")] +pub fn execute_query(registry: &Url, query: &QueryBody) -> anyhow::Result +where + for<'de> R: serde::Deserialize<'de>, + V: serde::Serialize, +{ + Err(anyhow::anyhow!("networking is not implemented on wasm32-wasi")) +} diff --git a/wapm-resolve-url/src/lib.rs b/wapm-resolve-url/src/lib.rs new file mode 100644 index 00000000..561572e8 --- /dev/null +++ b/wapm-resolve-url/src/lib.rs @@ -0,0 +1,150 @@ +use url::Url; +use graphql_client::GraphQLQuery; + +mod graphql; +#[cfg(not(target_arch = "wasm32"))] +mod proxy; + +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "graphql/schema.graphql", + query_path = "graphql/query-url-of-file-targz.graphql", + response_derives = "Debug" +)] +pub struct GetPackageQueryTarGz; + +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "graphql/schema.graphql", + query_path = "graphql/query-url-of-file-pirita.graphql", + response_derives = "Debug" +)] +pub struct GetPackageQueryPirita; + +pub fn whoami_distro() -> String { + whoami::distro().to_lowercase() +} + +pub fn get_current_wapm_registry() -> Option { + let command = std::process::Command::new("wapm") + .arg("config") + .arg("get") + .arg("registry.url") + .output() + .ok()?; + Some(Url::parse(std::str::from_utf8(&command.stdout).ok()?).ok()?) +} + +#[derive(Debug, PartialEq, Clone)] +pub struct PackageRegistryInfoTarGz { + pub registry: Url, + /// Name of the package as originally queried + pub queried_name: String, + /// Version of the originally queried package + pub queried_version: Option, + /// Name of the resolved package, this can differ from the original package name + /// due to server-side package redirection + pub resolved_name: String, + /// Resolved version of the package + pub resolved_version: String, + /// URL of the .tar.gz file + pub url: Url, +} + +pub fn get_tar_gz_url_of_package(registry: &Url, package_id: &str, version: Option<&str>) -> Option { + + let q = GetPackageQueryTarGz::build_query(get_package_query_tar_gz::Variables { + name: package_id.to_string(), + }); + let all_package_versions: get_package_query_tar_gz::ResponseData = crate::graphql::execute_query(registry, &q).ok()?; + + match version { + Some(specific) => { + let last_package = all_package_versions.package.as_ref()?.versions.as_ref()?; + + let last_package = last_package + .iter() + .filter_map(|v| v.as_ref()) + .filter(|v| v.version == specific) + .next()?; + + let url = Url::parse(&last_package.distribution.download_url).ok()?; + Some(PackageRegistryInfoTarGz { + registry: registry.clone(), + queried_name: package_id.to_string(), + queried_version: version.as_ref().map(|s| s.to_string()), + resolved_name: all_package_versions.package.as_ref()?.name.to_string(), + resolved_version: last_package.version.to_string(), + url: url, + }) + }, + None => { + let last_version = all_package_versions.package.as_ref()?.last_version.as_ref()?; + let url = Url::parse(&last_version.distribution.download_url).ok()?; + Some(PackageRegistryInfoTarGz { + registry: registry.clone(), + queried_name: package_id.to_string(), + queried_version: version.as_ref().map(|s| s.to_string()), + resolved_name: all_package_versions.package.as_ref()?.name.to_string(), + resolved_version: last_version.version.to_string(), + url: url, + }) + }, + } +} + +#[derive(Debug, PartialEq, Clone)] +pub struct PackageRegistryInfoPirita { + pub registry: Url, + /// Name of the package as originally queried + pub queried_name: String, + /// Version of the originally queried package + pub queried_version: Option, + /// Name of the resolved package, this can differ from the original package name + /// due to server-side package redirection + pub resolved_name: String, + /// Resolved version of the package + pub resolved_version: String, + /// URL of the .tar.gz file + pub url: Url, +} +pub fn get_pirita_url_of_package(registry: &Url, package_id: &str, version: Option<&str>) -> Option { + + let q = GetPackageQueryPirita::build_query(get_package_query_pirita::Variables { + name: package_id.to_string(), + }); + let all_package_versions: get_package_query_pirita::ResponseData = crate::graphql::execute_query(registry, &q).ok()?; + + match version { + Some(specific) => { + let last_package = all_package_versions.package.as_ref()?.versions.as_ref()?; + let last_package = last_package + .iter() + .filter_map(|v| v.as_ref()) + .filter(|v| v.version == specific) + .next()?; + + let url = Url::parse(&last_package.distribution.pirita_download_url.as_ref().map(|s| s.as_str())?).ok()?; + Some(PackageRegistryInfoPirita { + registry: registry.clone(), + queried_name: package_id.to_string(), + queried_version: version.as_ref().map(|s| s.to_string()), + resolved_name: all_package_versions.package.as_ref()?.name.to_string(), + resolved_version: last_package.version.to_string(), + url: url, + }) + }, + None =>{ + let last_version = all_package_versions.package.as_ref()?.last_version.as_ref()?; + let url = Url::parse(&last_version.distribution.pirita_download_url.as_ref().map(|s| s.as_str())?).ok()?; + Some(PackageRegistryInfoPirita { + registry: registry.clone(), + queried_name: package_id.to_string(), + queried_version: version.as_ref().map(|s| s.to_string()), + resolved_name: all_package_versions.package.as_ref()?.name.to_string(), + resolved_version: last_version.version.to_string(), + url: url, + }) + }, + } +} diff --git a/wapm-resolve-url/src/proxy.rs b/wapm-resolve-url/src/proxy.rs new file mode 100644 index 00000000..4820498d --- /dev/null +++ b/wapm-resolve-url/src/proxy.rs @@ -0,0 +1,58 @@ +//! Code for dealing with setting things up to proxy network requests +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum ProxyError { + #[error("Failed to parse URL from {}: {}", url_location, error_message)] + UrlParseError { + url_location: String, + error_message: String, + }, + + #[error("Could not connect to proxy: {0}")] + ConnectionError(String), +} + +/// Tries to set up a proxy +/// +/// This function reads from wapm config's `proxy.url` first, then checks +/// `ALL_PROXY`, `HTTPS_PROXY`, and `HTTP_PROXY` environment variables, in both +/// upper case and lower case, in that order. +/// +/// If a proxy is specified in wapm config's `proxy.url`, it is assumed +/// to be a general proxy +/// +/// A return value of `Ok(None)` means that there was no attempt to set up a proxy, +/// `Ok(Some(proxy))` means that the proxy was set up successfully, and `Err(e)` that +/// there was a failure while attempting to set up the proxy. +pub fn maybe_set_up_proxy() -> anyhow::Result> { + use std::env; + let proxy = if let Ok(proxy_url) = env::var("ALL_PROXY").or(env::var("all_proxy")) { + reqwest::Proxy::all(&proxy_url).map(|proxy| (proxy_url, proxy, "ALL_PROXY")) + } else if let Ok(https_proxy_url) = env::var("HTTPS_PROXY").or(env::var("https_proxy")) { + reqwest::Proxy::https(&https_proxy_url).map(|proxy| (https_proxy_url, proxy, "HTTPS_PROXY")) + } else if let Ok(http_proxy_url) = env::var("HTTP_PROXY").or(env::var("http_proxy")) { + reqwest::Proxy::http(&http_proxy_url).map(|proxy| (http_proxy_url, proxy, "http_proxy")) + } else { + return Ok(None); + } + .map_err(|e| ProxyError::ConnectionError(e.to_string())) + .and_then( + |(proxy_url_str, proxy, url_location): (String, _, &'static str)| { + url::Url::parse(&proxy_url_str) + .map_err(|e| ProxyError::UrlParseError { + url_location: url_location.to_string(), + error_message: e.to_string(), + }) + .map(|url| { + if !(url.username().is_empty()) && url.password().is_some() { + proxy.basic_auth(url.username(), url.password().unwrap_or_default()) + } else { + proxy + } + }) + }, + )?; + + Ok(Some(proxy)) +} diff --git a/wapm-toml/Cargo.toml b/wapm-toml/Cargo.toml index bbb4ccb8..dedca9ba 100644 --- a/wapm-toml/Cargo.toml +++ b/wapm-toml/Cargo.toml @@ -15,6 +15,11 @@ semver = { version = "1.0", features = ["serde"] } serde_json = "1.0.81" serde_yaml = "0.8.24" serde_cbor = "0.11.2" +indexmap = { version = "1.6", features = ["serde"] } +validator = "0.15.0" + +[target.'cfg(not(target_os = "wasi"))'.dependencies] +wapm-resolve-url = { version = "0.1.0", path = "../wapm-resolve-url" } [features] integration_tests = [] diff --git a/wapm-toml/src/lib.rs b/wapm-toml/src/lib.rs index 9ff990b2..0bd4fa68 100644 --- a/wapm-toml/src/lib.rs +++ b/wapm-toml/src/lib.rs @@ -6,6 +6,8 @@ use std::collections::hash_map::HashMap; use std::fmt; use std::path::{Path, PathBuf}; use thiserror::Error; +use indexmap::IndexMap; +use std::collections::BTreeMap; /// The ABI is a hint to WebAssembly runtimes about what additional imports to insert. /// It currently is only used for validation (in the validation subcommand). The default value is `None`. @@ -58,6 +60,57 @@ impl Default for Abi { pub static MANIFEST_FILE_NAME: &str = "wapm.toml"; pub static PACKAGES_DIR_NAME: &str = "wapm_packages"; +pub fn get_dependencies(wapm: &str) -> Vec<(String, String)>{ + let wapm: Manifest = match toml::from_str(wapm) { + Ok(o) => o, + Err(_) => { return Vec::new(); }, + }; + let mut dependencies = wapm.dependencies + .clone().unwrap_or_default() + .iter().map(|(k, v)| (k.clone(), v.clone())) + .collect::>(); + + #[cfg(not(target_os = "wasi"))] { + let current_registry = wapm_resolve_url::get_current_wapm_registry(); + + for (k, _) in dependencies.iter_mut() { + if k.split("/").count() == 1 { + // Somebody only specified the package / command as the dependency instead + // of using the owner/package format + if let Some(r) = current_registry.as_ref() { + let package_info = wapm_resolve_url::get_tar_gz_url_of_package(r, k, None); + if let Some(pi) = package_info { + *k = pi.resolved_name.clone(); + } + } + } + } + } + + dependencies +} + +pub fn get_wapm_atom_file_paths( + paths: &BTreeMap<&PathBuf, &Vec> +) -> Result, anyhow::Error> { + + println!("searching for {MANIFEST_FILE_NAME:?} in {:#?}", paths.keys().collect::>()); + + let wapm_toml = paths.get(&Path::new(MANIFEST_FILE_NAME).to_path_buf()) + .ok_or(anyhow::anyhow!("Could not find wapm.toml in FileMap"))?; + + let wapm_toml: Manifest = toml::from_slice(&wapm_toml) + .map_err(|e| anyhow::anyhow!("Could not parse wapm.toml: {e}"))?; + + Ok(wapm_toml.module.clone().unwrap_or_default().into_iter().map(|m| { + (m.name.clone(), Path::new(&m.source).to_path_buf()) + }).collect()) +} + +pub fn get_wapm_manifest_file_name() -> PathBuf { + Path::new(MANIFEST_FILE_NAME).to_path_buf() +} + pub static README_PATHS: &[&str; 5] = &[ "README", "README.md", @@ -68,6 +121,79 @@ pub static README_PATHS: &[&str; 5] = &[ pub static LICENSE_PATHS: &[&str; 3] = &["LICENSE", "LICENSE.md", "COPYING"]; +pub fn get_modules(wapm: &str) -> Vec<(String, String, String)> { + let wapm: Manifest = match toml::from_str(wapm) { + Ok(o) => o, + Err(_) => { return Vec::new(); }, + }; + wapm.module.clone().unwrap_or_default().iter() + .map(|m| ( + m.name.to_string(), + m.abi.to_string(), + m.kind.as_ref().map(|s| s.as_str()).unwrap_or("wasm").to_string(), + )).collect() +} + +pub fn get_package_annotations(wapm: &str) -> serde_cbor::Value { + let wapm: Manifest = match toml::from_str(wapm) { + Ok(o) => o, + Err(_) => { return serde_cbor::Value::Null; }, + }; + transform_package_meta_to_annotations(&wapm.package) +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct PathBufWithVolume { + pub volume: String, + pub path: PathBuf, +} + +#[derive(Debug, Default, Clone, Deserialize, Serialize)] +pub struct InternalPackageMeta { + pub name: String, + pub version: String, + pub description: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub license: Option, + #[serde( + rename = "license-file", + default, + skip_serializing_if = "Option::is_none" + )] + pub license_file: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub readme: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub repository: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub homepage: Option, +} + +fn transform_package_meta_to_annotations(package: &Package) -> serde_cbor::Value { + let internal_package = InternalPackageMeta { + name: package.name.clone(), + version: format!("{}", package.version), + description: package.description.clone(), + license: package.license.clone(), + license_file: package.license_file.as_ref().map(|path| PathBufWithVolume { + volume: format!("metadata"), + path: path.clone(), + }), + readme: package.readme.as_ref().map(|path| PathBufWithVolume { + volume: format!("metadata"), + path: path.clone(), + }), + repository: package.repository.clone(), + homepage: package.homepage.clone(), + }; + + // convert InternalPackageMeta to a serde_cbor::Value + serde_cbor::to_vec(&internal_package) + .ok() + .and_then(|s| serde_cbor::from_slice(&s).ok()) + .unwrap_or(serde_cbor::Value::Null) +} + /// Describes a command for a wapm module #[derive(Clone, Debug, Deserialize, Serialize)] pub struct Package { @@ -155,7 +281,7 @@ pub struct CommandV1 { #[derive(Clone, Debug, Deserialize, Serialize)] pub struct CommandV2 { pub name: String, - pub module: String, + pub module: Option, pub runner: String, pub annotations: Option, } @@ -297,7 +423,7 @@ pub enum FileKind { Json, } -#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] pub struct Module { pub name: String, pub source: PathBuf, @@ -364,6 +490,172 @@ pub struct Manifest { pub base_directory_path: PathBuf, } + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct WitBindingsExtended { + pub wit: WitBindings, +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct WitBindings { + pub exports: String, + pub module: String, +} + +pub type WebcBinding = (String, String, serde_cbor::Value); + +pub fn get_bindings( + wapm: &str, + _base_path: &PathBuf, + _atom_kinds: &BTreeMap +) -> Result, anyhow::Error> { + + let wapm: Manifest = toml::from_str(wapm)?; + let default_modules = Vec::new(); + let mut bindings = Vec::new(); + + for module in wapm.module.as_ref().unwrap_or(&default_modules).iter() { + if let Some(b) = module.bindings.as_ref() { + let value = serde_cbor::from_slice(&serde_cbor::to_vec(&WitBindingsExtended { + wit: WitBindings { + exports: format!("metadata://{}", b.wit_exports.display()), + module: format!("atoms://{}", module.name), + } + })?)?; + bindings.push(("library-bindings".to_string(), format!("wit@{}", b.wit_bindgen), value)); + } + } + + Ok(bindings) +} + +// command name => (runner, annotations) +pub type WebcCommand = (String, Vec<(String, serde_cbor::Value)>); + +pub fn get_commands( + wapm: &str, + base_path: &PathBuf, + atom_kinds: &BTreeMap +) -> Result, anyhow::Error> { + + let wapm: Manifest = toml::from_str(wapm)?; + let default_commands = Vec::new(); + let mut commands = Vec::new(); + + for command in wapm.command.as_ref().unwrap_or(&default_commands).iter() { + match command { + Command::V1(command) => { + let name = &command.name; + let module = &command.module; + let main_args = command.main_args.as_ref(); + let package = command.package.as_ref(); + + if commands.iter().any(|(k, _)| k == name) { + return Err(anyhow::anyhow!("Command {name} is defined more than once")); + } + + let abi = atom_kinds.get(module).map(|s| s.as_str()); + let runner = match abi { + Some("emscripten") => "https://webc.org/runner/emscripten/command@unstable_", + Some("wasm4") => "https://webc.org/runner/wasm4/command@unstable_", + Some("wasi") | Some("generic") => "https://webc.org/runner/wasi/command@unstable_", + _ => { return Err(anyhow::anyhow!("Unknown ABI in command {name:?}: {:?}", abi.unwrap_or(""))); }, + }; + + let annotations_str = match abi { + Some("emscripten") => "emscripten", + Some("wasm4") => "wasm4", + Some("wasi") | Some("generic") => "wasi", + _ => { return Err(anyhow::anyhow!("Unknown ABI in command {name:?}: {:?}", abi.unwrap_or(""))); }, + }; + + let runner = runner.to_string(); + let annotations = { + let mut map = Vec::new(); + map.push(( + annotations_str.to_string(), + transform_cmd_args(&TransformCmdArgs { + atom: module.clone(), + main_args: main_args.cloned(), + package: package.cloned(), + }), + )); + map + }; + + commands.push(( + name.clone(), + (runner, annotations) + )); + }, + Command::V2(command) => { + + let runner = if validator::validate_url(&command.runner) { + command.runner.to_string() + } else { + format!("https://webc.org/runner/{}", command.runner.to_string()) + }; + + let annotations = { + let mut map = Vec::new(); + + let annotations = command + .get_annotations(base_path) + .map_err(|e| anyhow::anyhow!("command {}: {e}", command.name))?; + + if let Some(s) = annotations { + map.push((command.runner.clone(), s)); + } + map + }; + + commands.push(( + command.name.clone(), + (runner, annotations), + )); + } + } + } + + Ok(commands) +} + +pub fn get_manifest_file_names() -> Vec { + vec![Path::new(MANIFEST_FILE_NAME).to_path_buf()] +} + +pub fn get_metadata_paths(bindings: &[serde_cbor::Value]) -> Vec { + let mut paths = Vec::new(); + + for b in bindings { + if let Ok(wit) = serde_cbor::from_slice::(&serde_cbor::to_vec(b).unwrap()) { + paths.push(Path::new(&wit.wit.exports.replacen("metadata://", "", 1)).to_path_buf()); + } + } + + for p in README_PATHS.iter() { + paths.push(Path::new(p).to_path_buf()); + } + for p in LICENSE_PATHS.iter() { + paths.push(Path::new(p).to_path_buf()); + } + paths +} + +#[derive(Serialize, Deserialize)] +struct TransformCmdArgs { + atom: String, + main_args: Option, + package: Option, +} + +fn transform_cmd_args(args: &TransformCmdArgs) -> serde_cbor::Value { + serde_cbor::to_vec(&args) + .ok() + .and_then(|s| serde_cbor::from_slice(&s).ok()) + .unwrap_or(serde_cbor::Value::Null) +} + #[cfg(feature = "integration_tests")] pub mod integration_tests { pub mod data { @@ -384,6 +676,7 @@ pub mod integration_tests { } } } + impl Manifest { #[cfg(not(feature = "integration_tests"))] fn locate_file(path: &Path, candidates: &[&str]) -> Option {