commit ec1c6fcffaf8ac01e41f211632fbd07a5d7b39ae Author: daimond113 <72147841+daimond113@users.noreply.github.com> Date: Mon Mar 4 21:18:49 2024 +0100 feat: :tada: initial commit diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..0f9adde --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +* +!src +!registry +!Cargo.lock +!Cargo.toml +!rust-toolchain.toml \ No newline at end of file diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..213b826 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,101 @@ +name: Release +on: + push: + tags: + - v* +jobs: + build: + strategy: + matrix: + include: + - os: ubuntu-latest + host: linux + label: linux-x86_64 + target: x86_64-unknown-linux-gnu + + - os: windows-latest + host: windows + label: windows-x86_64 + target: x86_64-pc-windows-msvc + + - os: macos-latest + host: macos + label: macos-x86_64 + target: x86_64-apple-darwin + + - os: macos-latest-xlarge + host: macos + label: macos-aarch64 + target: aarch64-apple-darwin + runs-on: ${{ matrix.os }} + name: Build for ${{ matrix.label }} + steps: + - uses: actions/checkout@v4 + - name: Set up Rust + uses: moonrepo/setup-rust@v1 + with: + targets: ${{ matrix.target }} + + - name: Set env + shell: bash + run: | + BIN_NAME=pesde + ARCHIVE_NAME=$BIN_NAME-$(echo ${{ github.ref_name }} | cut -c 2-)-${{ matrix.label }}.zip + + echo "BIN_NAME=$BIN_NAME" >> $GITHUB_ENV + echo "ARCHIVE_NAME=$ARCHIVE_NAME" >> $GITHUB_ENV + + - name: Build + run: cargo build --bins --all-features --release --target ${{ matrix.target }} --locked + + - name: Archive + shell: bash + run: | + if [ ${{ matrix.host }} = "windows" ]; then + cp target/${{ matrix.target }}/release/${{ env.BIN_NAME }}.exe ${{ env.BIN_NAME }}.exe + 7z a ${{ env.ARCHIVE_NAME }} ${{ env.BIN_NAME }}.exe + else + cp target/${{ matrix.target }}/release/${{ env.BIN_NAME }} ${{ env.BIN_NAME }} + zip -r ${{ env.ARCHIVE_NAME }} ${{ env.BIN_NAME }} + fi + + - name: Upload assets + uses: actions/upload-artifact@v4 + with: + name: ${{ env.ARCHIVE_NAME }} + path: ${{ env.ARCHIVE_NAME }} + + create_release: + name: Create Release + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: read + needs: [build] + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: actions/download-artifact@v4 + with: + path: artifacts + merge-multiple: true + + - name: Generate a changelog + uses: orhun/git-cliff-action@v3 + id: git-cliff + with: + config: cliff.toml + args: --verbose --current --strip header --github-repo ${{ github.repository }} --github-token ${{ secrets.GITHUB_TOKEN }} + + - name: Create Release + id: create_release + uses: softprops/action-gh-release@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + tag_name: ${{ github.ref_name }} + name: ${{ github.ref_name }} + body: ${{ steps.git-cliff.outputs.content }} + draft: true + prerelease: false + files: artifacts/* \ No newline at end of file diff --git a/.github/workflows/test-and-lint.yaml b/.github/workflows/test-and-lint.yaml new file mode 100644 index 0000000..dcb8caa --- /dev/null +++ b/.github/workflows/test-and-lint.yaml @@ -0,0 +1,35 @@ +name: Test & Lint +on: + - push + - pull_request + +env: + CARGO_TERM_COLOR: always + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Rust + uses: moonrepo/setup-rust@v1 + with: + bins: cargo-tarpaulin + components: rustfmt, clippy + + - name: Run tests + run: cargo test --all + + - name: Check formatting + run: cargo fmt --all -- --check + + - name: Run clippy + run: cargo clippy --all-targets --all-features -- -D warnings + + - name: Generate coverage report + run: cargo tarpaulin --all-features --out xml --exclude-files src/cli/* --exclude-files registry/* --exclude-files src/main.rs --skip-clean + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v4.0.1 + with: + token: ${{ secrets.CODECOV_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0302135 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +**/target +**/.env +.idea +cobertura.xml +tarpaulin-report.html +build_rs_cov.profraw +registry/cache \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..14768c1 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,5550 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "actix-codec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" +dependencies = [ + "bitflags 2.4.2", + "bytes", + "futures-core", + "futures-sink", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "actix-cors" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9e772b3bcafe335042b5db010ab7c09013dad6eac4915c91d8d50902769f331" +dependencies = [ + "actix-utils", + "actix-web", + "derive_more", + "futures-util", + "log", + "once_cell", + "smallvec", +] + +[[package]] +name = "actix-http" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d223b13fd481fc0d1f83bb12659ae774d9e3601814c68a0bc539731698cca743" +dependencies = [ + "actix-codec", + "actix-rt", + "actix-service", + "actix-utils", + "ahash", + "base64 0.21.7", + "bitflags 2.4.2", + "brotli", + "bytes", + "bytestring", + "derive_more", + "encoding_rs", + "flate2", + "futures-core", + "h2", + "http", + "httparse", + "httpdate", + "itoa", + "language-tags", + "local-channel", + "mime", + "percent-encoding", + "pin-project-lite", + "rand", + "sha1 0.10.6", + "smallvec", + "tokio", + "tokio-util", + "tracing", + "zstd 0.13.0", +] + +[[package]] +name = "actix-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" +dependencies = [ + "quote", + "syn 2.0.52", +] + +[[package]] +name = "actix-multipart" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b960e2aea75f49c8f069108063d12a48d329fc8b60b786dfc7552a9d5918d2d" +dependencies = [ + "actix-multipart-derive", + "actix-utils", + "actix-web", + "bytes", + "derive_more", + "futures-core", + "futures-util", + "httparse", + "local-waker", + "log", + "memchr", + "mime", + "serde", + "serde_json", + "serde_plain", + "tempfile", + "tokio", +] + +[[package]] +name = "actix-multipart-derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a0a77f836d869f700e5b47ac7c3c8b9c8bc82e4aec861954c6198abee3ebd4d" +dependencies = [ + "darling", + "parse-size", + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "actix-router" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22475596539443685426b6bdadb926ad0ecaefdfc5fb05e5e3441f15463c511" +dependencies = [ + "bytestring", + "http", + "regex", + "serde", + "tracing", +] + +[[package]] +name = "actix-rt" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28f32d40287d3f402ae0028a9d54bef51af15c8769492826a69d28f81893151d" +dependencies = [ + "futures-core", + "tokio", +] + +[[package]] +name = "actix-server" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb13e7eef0423ea6eab0e59f6c72e7cb46d33691ad56a726b3cd07ddec2c2d4" +dependencies = [ + "actix-rt", + "actix-service", + "actix-utils", + "futures-core", + "futures-util", + "mio", + "socket2 0.5.6", + "tokio", + "tracing", +] + +[[package]] +name = "actix-service" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" +dependencies = [ + "futures-core", + "paste", + "pin-project-lite", +] + +[[package]] +name = "actix-utils" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" +dependencies = [ + "local-waker", + "pin-project-lite", +] + +[[package]] +name = "actix-web" +version = "4.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a6556ddebb638c2358714d853257ed226ece6023ef9364f23f0c70737ea984" +dependencies = [ + "actix-codec", + "actix-http", + "actix-macros", + "actix-router", + "actix-rt", + "actix-server", + "actix-service", + "actix-utils", + "actix-web-codegen", + "ahash", + "bytes", + "bytestring", + "cfg-if", + "cookie 0.16.2", + "derive_more", + "encoding_rs", + "futures-core", + "futures-util", + "itoa", + "language-tags", + "log", + "mime", + "once_cell", + "pin-project-lite", + "regex", + "serde", + "serde_json", + "serde_urlencoded", + "smallvec", + "socket2 0.5.6", + "time 0.3.34", + "url", +] + +[[package]] +name = "actix-web-codegen" +version = "4.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb1f50ebbb30eca122b188319a4398b3f7bb4a8cdf50ecfb73bfc6a3c3ce54f5" +dependencies = [ + "actix-router", + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "actix-web-httpauth" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d613edf08a42ccc6864c941d30fe14e1b676a77d16f1dbadc1174d065a0a775" +dependencies = [ + "actix-utils", + "actix-web", + "base64 0.21.7", + "futures-core", + "futures-util", + "log", + "pin-project-lite", +] + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "opaque-debug", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom 0.2.12", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" + +[[package]] +name = "arc-swap" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b3d0060af21e8d11a926981cc00c6c1541aa91dd64b9f881985c3da1094425f" + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "async-broadcast" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c48ccdbf6ca6b121e0f586cbc0e73ae440e56c67c30fa0873b4e110d9c26d2b" +dependencies = [ + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3" +dependencies = [ + "concurrent-queue", + "event-listener 5.2.0", + "event-listener-strategy 0.5.0", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-compression" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a116f46a969224200a0a97f29cfd4c50e7534e4b4826bd23ea2c3c533039c82c" +dependencies = [ + "brotli", + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "async-executor" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ae5ebefcc48e7452b4987947920dac9450be1110cadf34d1b8c116bdbaf97c" +dependencies = [ + "async-lock 3.3.0", + "async-task", + "concurrent-queue", + "fastrand 2.0.1", + "futures-lite 2.2.0", + "slab", +] + +[[package]] +name = "async-fs" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "blocking", + "futures-lite 1.13.0", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite 1.13.0", + "log", + "parking", + "polling 2.8.0", + "rustix 0.37.27", + "slab", + "socket2 0.4.10", + "waker-fn", +] + +[[package]] +name = "async-io" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f97ab0c5b00a7cdbe5a371b9a782ee7be1316095885c8a4ea1daf490eb0ef65" +dependencies = [ + "async-lock 3.3.0", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite 2.2.0", + "parking", + "polling 3.5.0", + "rustix 0.38.31", + "slab", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" +dependencies = [ + "event-listener 4.0.3", + "event-listener-strategy 0.4.0", + "pin-project-lite", +] + +[[package]] +name = "async-process" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88" +dependencies = [ + "async-io 1.13.0", + "async-lock 2.8.0", + "async-signal", + "blocking", + "cfg-if", + "event-listener 3.1.0", + "futures-lite 1.13.0", + "rustix 0.38.31", + "windows-sys 0.48.0", +] + +[[package]] +name = "async-recursion" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "async-signal" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e47d90f65a225c4527103a8d747001fc56e375203592b25ad103e1ca13124c5" +dependencies = [ + "async-io 2.3.1", + "async-lock 2.8.0", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix 0.38.31", + "signal-hook-registry", + "slab", + "windows-sys 0.48.0", +] + +[[package]] +name = "async-task" +version = "4.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799" + +[[package]] +name = "async-trait" +version = "0.1.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "auth-git2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41e7771d4ab6635cbd685ce8db215b29c78a468098126de77c57f3b2e6eb3757" +dependencies = [ + "dirs 5.0.1", + "git2", + "terminal-prompt", +] + +[[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.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base-x" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "beef" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + +[[package]] +name = "bitpacking" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c7d2ac73c167c06af4a5f37e6e59d84148d57ccbe4480b76f0273eefea82d7" +dependencies = [ + "crunchy", +] + +[[package]] +name = "blake2b_simd" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" +dependencies = [ + "arrayref", + "arrayvec 0.5.2", + "constant_time_eq 0.1.5", +] + +[[package]] +name = "blake3" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" +dependencies = [ + "arrayref", + "arrayvec 0.7.4", + "cc", + "cfg-if", + "constant_time_eq 0.3.0", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-modes" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cb03d1bed155d89dce0f845b7899b18a9a163e148fd004e1c28421a783e2d8e" +dependencies = [ + "block-padding", + "cipher", +] + +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "blocking" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" +dependencies = [ + "async-channel", + "async-lock 3.3.0", + "async-task", + "fastrand 2.0.1", + "futures-io", + "futures-lite 2.2.0", + "piper", + "tracing", +] + +[[package]] +name = "brotli" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516074a47ef4bce09577a3b379392300159ce5b1ba2e501ff1c819950066100f" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bstr" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b" + +[[package]] +name = "bytecount" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205" + +[[package]] +name = "byteorder" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "bytestring" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d80203ea6b29df88012294f62733de21cfeab47f17b41af3a38bc30a03ee72" +dependencies = [ + "bytes", +] + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "census" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f4c707c6a209cbe82d10abd08e1ea8995e9ea937d2550646e02798948992be0" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets 0.52.4", +] + +[[package]] +name = "chrono_lc" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809c968b91b4949802fba00279fd0610158cbb2ae5f10663f0c3d5331f88d6d6" +dependencies = [ + "chrono", + "lazy_static", + "num-integer", + "serde", + "serde_derive", + "serde_json", + "walkdir", +] + +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array", +] + +[[package]] +name = "clap" +version = "4.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim 0.11.0", +] + +[[package]] +name = "clap_derive" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "clipboard-win" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f9a0700e0127ba15d1d52dd742097f821cd9c65939303a44d970465040a297" +dependencies = [ + "error-code", +] + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "concurrent-queue" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "windows-sys 0.52.0", +] + +[[package]] +name = "const_fn" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935" + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "cookie" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6e25dfc584d06a3dbf775d207ff00d7de98d824c952dd2233dfbb261889a42" +dependencies = [ + "time 0.2.27", + "version_check", +] + +[[package]] +name = "cookie" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" +dependencies = [ + "percent-encoding", + "time 0.3.34", + "version_check", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[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 = "darling" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 2.0.52", +] + +[[package]] +name = "darling_macro" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "data-encoding" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" + +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "serde", + "uuid", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.0", + "syn 1.0.109", +] + +[[package]] +name = "dialoguer" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de" +dependencies = [ + "console", + "shell-words", + "tempfile", + "thiserror", + "zeroize", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "directories" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" +dependencies = [ + "libc", + "redox_users 0.3.5", + "winapi", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users 0.4.4", + "windows-sys 0.48.0", +] + +[[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "enumflags2" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3278c9d5fb675e0a51dabcf4c0d355f692b064171535ba72361be1528a9d8e8d" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "env_logger" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "erased-serde" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388979d208a049ffdfb22fa33b9c81942215b940910bccfe258caeb25d125cb3" +dependencies = [ + "serde", +] + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "error-code" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b" + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b5fb89194fa3cad959b833185b3063ba881dbfc7030680b314250779fb4cc91" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" +dependencies = [ + "event-listener 4.0.3", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291" +dependencies = [ + "event-listener 5.2.0", + "pin-project-lite", +] + +[[package]] +name = "fastdivide" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25c7df09945d65ea8d70b3321547ed414bbc540aad5bac6883d021b970f35b04" + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "fd-lock" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947" +dependencies = [ + "cfg-if", + "rustix 0.38.31", + "windows-sys 0.52.0", +] + +[[package]] +name = "filetime" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.4.1", + "windows-sys 0.52.0", +] + +[[package]] +name = "findshlibs" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64" +dependencies = [ + "cc", + "lazy_static", + "libc", + "winapi", +] + +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +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.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs4" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eeb4ed9e12f43b7fa0baae3f9cdda28352770132ef2e09a23760c29cae8bd47" +dependencies = [ + "rustix 0.38.31", + "windows-sys 0.48.0", +] + +[[package]] +name = "full_moon" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ef4f8ad0689d3a86bb483650422d72e6f79a37fdc83ed5426cafe96b776ce1" +dependencies = [ + "bytecount", + "cfg-if", + "derive_more", + "full_moon_derive", + "logos", + "paste", + "serde", + "smol_str", + "stacker", +] + +[[package]] +name = "full_moon_derive" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99b4bd12ce56927d1dc5478d21528ea8c4b93ca85ff8f8043b6a5351a2a3c6f7" +dependencies = [ + "indexmap 1.9.3", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-lite" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445ba825b27408685aaecefd65178908c36c6e96aaf6d8599419d46e624192ba" +dependencies = [ + "fastrand 2.0.1", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generator" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b25e5b3e733153bcab35ee4671b46604b42516163cae442d1601cb716f2ac5" +dependencies = [ + "cc", + "cfg-if", + "libc", + "log", + "rustversion", + "windows", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[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 = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "git2" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b3ba52851e73b46a4c3df1d89343741112003f0f6f13beb0dfac9e457c3fdcd" +dependencies = [ + "bitflags 2.4.2", + "libc", + "libgit2-sys", + "log", + "openssl-probe", + "openssl-sys", + "url", +] + +[[package]] +name = "glam" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "globset" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata 0.4.5", + "regex-syntax 0.8.2", +] + +[[package]] +name = "h2" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 2.2.5", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + +[[package]] +name = "htmlescape" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163" + +[[package]] +name = "http" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.6", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http", + "hyper", + "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", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "hyper-tungstenite" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cc7dcb1ab67cd336f468a12491765672e61a3b6b148634dbfe2fe8acd3fe7d9" +dependencies = [ + "hyper", + "pin-project-lite", + "tokio", + "tokio-tungstenite", + "tungstenite", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core 0.52.0", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "ignore" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata 0.4.5", + "same-file", + "walkdir", + "winapi-util", +] + +[[package]] +name = "include_dir" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18762faeff7122e89e0857b02f7ce6fcc0d101d5e9ad2ad7846cc01d61b7f19e" +dependencies = [ + "glob", + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", +] + +[[package]] +name = "indicatif" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +dependencies = [ + "console", + "instant", + "number_prefix", + "portable-atomic", + "unicode-width", +] + +[[package]] +name = "indicatif-log-bridge" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2963046f28a204e3e3fd7e754fd90a6235da05b5378f24707ff0ec9513725ce3" +dependencies = [ + "indicatif", + "log", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "is-terminal" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "jobserver" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "keyring" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1be8bc4c6b6e9d85ecdad090fcf342a9216f53d747a537cc05e3452fd650ca46" +dependencies = [ + "byteorder 1.5.0", + "lazy_static", + "linux-keyutils", + "secret-service", + "security-framework", + "windows-sys 0.52.0", +] + +[[package]] +name = "language-tags" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "levenshtein_automata" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2cdeb66e45e9f36bfad5bbdb4d2384e70936afbee843c6f6543f0c551ebb25" + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "libgit2-sys" +version = "0.16.2+1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee4126d8b4ee5c9d9ea891dd875cfdc1e9d0950437179104b183d7d8a74d24e8" +dependencies = [ + "cc", + "libc", + "libssh2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", +] + +[[package]] +name = "libloading" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2caa5afb8bf9f3a2652760ce7d4f62d21c4d5a423e68466fca30df82f2330164" +dependencies = [ + "cfg-if", + "windows-targets 0.52.4", +] + +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.2", + "libc", + "redox_syscall 0.4.1", +] + +[[package]] +name = "libssh2-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libz-sys" +version = "1.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037731f5d3aaa87a5675e895b63ddff1a87624bc29f77004ea829809654e48f6" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "line-wrap" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9" +dependencies = [ + "safemem", +] + +[[package]] +name = "linux-keyutils" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "761e49ec5fd8a5a463f9b84e877c373d888935b71c6be78f3767fe2ae6bed18e" +dependencies = [ + "bitflags 2.4.2", + "libc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "local-channel" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6cbc85e69b8df4b8bb8b89ec634e7189099cea8927a276b7384ce5488e53ec8" +dependencies = [ + "futures-core", + "futures-sink", + "local-waker", +] + +[[package]] +name = "local-waker" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "logos" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf8b031682c67a8e3d5446840f9573eb7fe26efe7ec8d195c9ac4c0647c502f1" +dependencies = [ + "logos-derive", +] + +[[package]] +name = "logos-derive" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d849148dbaf9661a6151d1ca82b13bb4c4c128146a88d05253b38d4e2f496c" +dependencies = [ + "beef", + "fnv", + "proc-macro2", + "quote", + "regex-syntax 0.6.29", + "syn 1.0.109", +] + +[[package]] +name = "loom" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" +dependencies = [ + "cfg-if", + "generator", + "pin-utils", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "lru" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a83fb7698b3643a0e34f9ae6f2e8f0178c0fd42f8b59d493aa271ff3a5bf21" +dependencies = [ + "hashbrown 0.14.3", +] + +[[package]] +name = "luau0-src" +version = "0.8.3+luau614" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d0dc9f950d074893d18af156124f8296e7477f96dfbdc0520fb8df5a8aa3898" +dependencies = [ + "cc", +] + +[[package]] +name = "lune" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bcc079b3fb923a1e21c6c4ec0ff879636b85ae566f6370fc7f9a603749ca573" +dependencies = [ + "anyhow", + "async-compression", + "async-trait", + "chrono", + "chrono_lc", + "clap", + "console", + "dialoguer", + "directories", + "dunce", + "env_logger", + "futures-util", + "glam", + "hyper", + "hyper-tungstenite", + "include_dir", + "itertools 0.12.1", + "lz4_flex", + "mlua", + "once_cell", + "os_str_bytes", + "path-clean", + "pathdiff", + "pin-project", + "rand", + "rbx_binary", + "rbx_cookie", + "rbx_dom_weak", + "rbx_reflection", + "rbx_reflection_database", + "rbx_xml", + "regex", + "reqwest", + "rustyline", + "serde", + "serde_json", + "serde_yaml", + "thiserror", + "tokio", + "tokio-tungstenite", + "toml", + "tracing", + "tracing-subscriber", + "urlencoding", +] + +[[package]] +name = "lz4" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e9e2dd86df36ce760a60f6ff6ad526f7ba1f14ba0356f8254fb6905e6494df1" +dependencies = [ + "libc", + "lz4-sys", +] + +[[package]] +name = "lz4-sys" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "lz4_flex" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "912b45c753ff5f7f5208307e8ace7d2a2e30d024e26d3509f3dce546c044ce15" +dependencies = [ + "twox-hash", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + +[[package]] +name = "measure_time" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56220900f1a0923789ecd6bf25fbae8af3b2f1ff3e9e297fc9b6b8674dd4d852" +dependencies = [ + "instant", + "log", +] + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "memmap2" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49388d20533534cd19360ad3d6a7dadc885944aa802ba3995040c5ec11288c6" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.48.0", +] + +[[package]] +name = "mlua" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "868d02cb5eb97761bbf6bd6922c1c7a88b8ea252bbf43bd8350a0bf8497a1fc0" +dependencies = [ + "bstr", + "erased-serde", + "libloading", + "mlua-sys", + "num-traits", + "once_cell", + "rustc-hash", + "serde", + "serde-value", +] + +[[package]] +name = "mlua-sys" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2847b42764435201d8cbee1f517edb79c4cca4181877b90047587c89e1b7bce4" +dependencies = [ + "cc", + "cfg-if", + "luau0-src", + "pkg-config", +] + +[[package]] +name = "murmurhash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2195bf6aa996a481483b29d62a7663eed3fe39600c460e323f8ff41e90bdd89b" + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.7.1", +] + +[[package]] +name = "nix" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +dependencies = [ + "bitflags 2.4.2", + "cfg-if", + "libc", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "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.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "oneshot" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f6640c6bda7731b1fdbab747981a0f896dd1fedaf9f4a53fa237a04a84431f4" +dependencies = [ + "loom", +] + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openssl" +version = "0.10.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8" +dependencies = [ + "bitflags 2.4.2", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[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.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + +[[package]] +name = "ordered-stream" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "os_info" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "006e42d5b888366f1880eda20371fedde764ed2213dc8496f49622fa0c99cd5e" +dependencies = [ + "log", + "serde", + "winapi", +] + +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" +dependencies = [ + "memchr", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "ownedbytes" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e8a72b918ae8198abb3a18c190288123e1d442b6b9a7d709305fd194688b4b7" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + +[[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.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.4.1", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "parse-size" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "944553dd59c802559559161f9816429058b869003836120e262e8caec061b7ae" + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "path-clean" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef" + +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pesde" +version = "0.1.0" +dependencies = [ + "anyhow", + "auth-git2", + "clap", + "directories", + "flate2", + "full_moon", + "futures-executor", + "git2", + "ignore", + "indicatif", + "indicatif-log-bridge", + "keyring", + "log", + "lune", + "pathdiff", + "pretty_env_logger", + "relative-path", + "reqwest", + "semver 1.0.22", + "serde", + "serde_json", + "serde_yaml", + "tar", + "tempfile", + "thiserror", + "threadpool", +] + +[[package]] +name = "pesde-registry" +version = "0.1.0" +dependencies = [ + "actix-cors", + "actix-multipart", + "actix-multipart-derive", + "actix-web", + "actix-web-httpauth", + "dotenvy", + "flate2", + "git2", + "log", + "pesde", + "pretty_env_logger", + "reqwest", + "rusty-s3", + "semver 1.0.22", + "sentry", + "sentry-actix", + "sentry-log", + "serde", + "serde_json", + "serde_yaml", + "tantivy", + "tar", + "thiserror", +] + +[[package]] +name = "pin-project" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "piper" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" +dependencies = [ + "atomic-waker", + "fastrand 2.0.1", + "futures-io", +] + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "plist" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5699cc8a63d1aa2b1ee8e12b9ad70ac790d65788cd36101fa37f87ea46c4cef" +dependencies = [ + "base64 0.21.7", + "indexmap 2.2.5", + "line-wrap", + "quick-xml 0.31.0", + "serde", + "time 0.3.34", +] + +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", +] + +[[package]] +name = "polling" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24f040dee2588b4963afb4e420540439d126f73fdacf4a9c486a96d840bac3c9" +dependencies = [ + "cfg-if", + "concurrent-queue", + "pin-project-lite", + "rustix 0.38.31", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "portable-atomic" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "pretty_env_logger" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c" +dependencies = [ + "env_logger", + "log", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "profiling" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8021cf59c8ec9c432cfc2526ac6b8aa508ecaf29cd415f271b8406c1b851c3fd" +dependencies = [ + "quote", + "syn 2.0.52", +] + +[[package]] +name = "psm" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", +] + +[[package]] +name = "quick-xml" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "quick-xml" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.12", +] + +[[package]] +name = "rayon" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "rbx_binary" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6314dd6bf5c21d0598cdb53cf5d241aa643ba41da8b8abf7402b4a35096f03f6" +dependencies = [ + "log", + "lz4", + "profiling", + "rbx_dom_weak", + "rbx_reflection", + "rbx_reflection_database", + "thiserror", +] + +[[package]] +name = "rbx_cookie" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a61b073240f4c13b1e780a8999a113dfa28bc93f2cf9fc41c6f36e7aceb5bf" +dependencies = [ + "byteorder 0.5.3", + "cookie 0.15.2", + "dirs 1.0.5", + "log", + "plist", + "winapi", + "winreg 0.10.1", +] + +[[package]] +name = "rbx_dom_weak" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b67b56bac99849c2e3c57547b036927f71c57cf7f4d900d04e3e4ee774ec316" +dependencies = [ + "rbx_types", + "serde", +] + +[[package]] +name = "rbx_reflection" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d41509c991b53a7276a746a795eae2b9204f398164920f61976995b47fe1722" +dependencies = [ + "rbx_types", + "serde", + "thiserror", +] + +[[package]] +name = "rbx_reflection_database" +version = "0.2.10+roblox-607" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12e20c06fa41f7aadc79005c8354f592b2c2f4d0c61e1080ed5718dafc30aea0" +dependencies = [ + "lazy_static", + "rbx_reflection", + "rmp-serde", + "serde", +] + +[[package]] +name = "rbx_types" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca23bfd469d067d81ef14f65fe09aeddc25abcf576a889d1a7664fe021cf18c" +dependencies = [ + "base64 0.13.1", + "bitflags 1.3.2", + "blake3", + "lazy_static", + "rand", + "serde", + "thiserror", +] + +[[package]] +name = "rbx_xml" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8c03f95500961c32340791d1fabd4587f6873bdbff077ecca6ae32db7960dea" +dependencies = [ + "base64 0.13.1", + "log", + "rbx_dom_weak", + "rbx_reflection", + "rbx_reflection_database", + "xml-rs", +] + +[[package]] +name = "redox_syscall" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" +dependencies = [ + "getrandom 0.1.16", + "redox_syscall 0.1.57", + "rust-argon2", +] + +[[package]] +name = "redox_users" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +dependencies = [ + "getrandom 0.2.12", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.5", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "relative-path" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e898588f33fdd5b9420719948f9f2a32c922a246964576f71ba7f24f80610fbc" +dependencies = [ + "serde", +] + +[[package]] +name = "reqwest" +version = "0.11.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "mime_guess", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-native-tls", + "tokio-rustls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "winreg 0.50.0", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.12", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rmp" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f9860a6cc38ed1da53456442089b4dfa35e7cedaa326df63017af88385e6b20" +dependencies = [ + "byteorder 1.5.0", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bffea85eea980d8a74453e5d02a8d93028f3c34725de143085a844ebe953258a" +dependencies = [ + "byteorder 1.5.0", + "rmp", + "serde", +] + +[[package]] +name = "rust-argon2" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" +dependencies = [ + "base64 0.13.1", + "blake2b_simd", + "constant_time_eq 0.1.5", + "crossbeam-utils", +] + +[[package]] +name = "rust-stemmers" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e46a2036019fdb888131db7a4c847a1063a7493f971ed94ea82c67eada63ca54" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.22", +] + +[[package]] +name = "rustix" +version = "0.37.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +dependencies = [ + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys 0.4.13", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.21.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "rusty-s3" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31aa883f1b986a5249641e574ca0e11ac4fb9970b009c6fbb96fedaf4fa78db8" +dependencies = [ + "base64 0.21.7", + "hmac", + "md-5", + "percent-encoding", + "quick-xml 0.30.0", + "serde", + "serde_json", + "sha2", + "time 0.3.34", + "url", + "zeroize", +] + +[[package]] +name = "rustyline" +version = "13.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02a2d683a4ac90aeef5b1013933f6d977bd37d51ff3f4dad829d4931a7e6be86" +dependencies = [ + "bitflags 2.4.2", + "cfg-if", + "clipboard-win", + "fd-lock", + "home", + "libc", + "log", + "memchr", + "nix 0.27.1", + "radix_trie", + "unicode-segmentation", + "unicode-width", + "utf8parse", + "winapi", +] + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "safemem" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" + +[[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.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "secret-service" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5da1a5ad4d28c03536f82f77d9f36603f5e37d8869ac98f0a750d5b5686d8d95" +dependencies = [ + "aes", + "block-modes", + "futures-util", + "generic-array", + "hkdf", + "num", + "once_cell", + "rand", + "serde", + "sha2", + "zbus", +] + +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +dependencies = [ + "serde", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "sentry" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "766448f12e44d68e675d5789a261515c46ac6ccd240abdd451a9c46c84a49523" +dependencies = [ + "httpdate", + "native-tls", + "reqwest", + "sentry-backtrace", + "sentry-contexts", + "sentry-core", + "sentry-debug-images", + "sentry-panic", + "sentry-tracing", + "tokio", + "ureq", +] + +[[package]] +name = "sentry-actix" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "285f2c101ed64f00585ec98f0d81a402c1cf5c2f9b1e1d53a84901812bcd4530" +dependencies = [ + "actix-web", + "futures-util", + "sentry-core", +] + +[[package]] +name = "sentry-backtrace" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32701cad8b3c78101e1cd33039303154791b0ff22e7802ed8cc23212ef478b45" +dependencies = [ + "backtrace", + "once_cell", + "regex", + "sentry-core", +] + +[[package]] +name = "sentry-contexts" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ddd2a91a13805bd8dab4ebf47323426f758c35f7bf24eacc1aded9668f3824" +dependencies = [ + "hostname", + "libc", + "os_info", + "rustc_version 0.4.0", + "sentry-core", + "uname", +] + +[[package]] +name = "sentry-core" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1189f68d7e7e102ef7171adf75f83a59607fafd1a5eecc9dc06c026ff3bdec4" +dependencies = [ + "once_cell", + "rand", + "sentry-types", + "serde", + "serde_json", +] + +[[package]] +name = "sentry-debug-images" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4d0a615e5eeca5699030620c119a094e04c14cf6b486ea1030460a544111a7" +dependencies = [ + "findshlibs", + "once_cell", + "sentry-core", +] + +[[package]] +name = "sentry-log" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d7cd58e7b31a1a533163abf86c182824ea8f8867853a6b402cde053595a54b" +dependencies = [ + "log", + "sentry-core", +] + +[[package]] +name = "sentry-panic" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1c18d0b5fba195a4950f2f4c31023725c76f00aabb5840b7950479ece21b5ca" +dependencies = [ + "sentry-backtrace", + "sentry-core", +] + +[[package]] +name = "sentry-tracing" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3012699a9957d7f97047fd75d116e22d120668327db6e7c59824582e16e791b2" +dependencies = [ + "sentry-backtrace", + "sentry-core", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "sentry-types" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7173fd594569091f68a7c37a886e202f4d0c1db1e1fa1d18a051ba695b2e2ec" +dependencies = [ + "debugid", + "hex", + "rand", + "serde", + "serde_json", + "thiserror", + "time 0.3.34", + "url", + "uuid", +] + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "serde_json" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +dependencies = [ + "indexmap 2.2.5", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_plain" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1fc6db65a611022b23a0dec6975d63fb80a302cb3388835ff02c097258d50" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "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.9.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd075d994154d4a774f95b51fb96bdc2832b0ea48425c92546073816cda1f2f" +dependencies = [ + "indexmap 2.2.5", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha1" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +dependencies = [ + "sha1_smol", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "sketches-ddsketch" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85636c14b73d81f541e525f585c0a2109e6744e1565b5c1668e31c70c10ed65c" +dependencies = [ + "serde", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" + +[[package]] +name = "smol_str" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad6c857cbab2627dcf01ec85a623ca4e7dcb5691cbaa3d7fb7653671f0d09c9" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "socket2" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "stacker" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "winapi", +] + +[[package]] +name = "standback" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" +dependencies = [ + "version_check", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stdweb" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version 0.2.3", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "serde_derive", + "syn 1.0.109", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +dependencies = [ + "base-x", + "proc-macro2", + "quote", + "serde", + "serde_derive", + "serde_json", + "sha1 0.6.1", + "syn 1.0.109", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strsim" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tantivy" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6083cd777fa94271b8ce0fe4533772cb8110c3044bab048d20f70108329a1f2" +dependencies = [ + "aho-corasick", + "arc-swap", + "async-trait", + "base64 0.21.7", + "bitpacking", + "byteorder 1.5.0", + "census", + "crc32fast", + "crossbeam-channel", + "downcast-rs", + "fastdivide", + "fs4", + "htmlescape", + "itertools 0.11.0", + "levenshtein_automata", + "log", + "lru", + "lz4_flex", + "measure_time", + "memmap2", + "murmurhash32", + "num_cpus", + "once_cell", + "oneshot", + "rayon", + "regex", + "rust-stemmers", + "rustc-hash", + "serde", + "serde_json", + "sketches-ddsketch", + "smallvec", + "tantivy-bitpacker", + "tantivy-columnar", + "tantivy-common", + "tantivy-fst", + "tantivy-query-grammar", + "tantivy-stacker", + "tantivy-tokenizer-api", + "tempfile", + "thiserror", + "time 0.3.34", + "uuid", + "winapi", +] + +[[package]] +name = "tantivy-bitpacker" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecb164321482301f514dd582264fa67f70da2d7eb01872ccd71e35e0d96655a" +dependencies = [ + "bitpacking", +] + +[[package]] +name = "tantivy-columnar" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d85f8019af9a78b3118c11298b36ffd21c2314bd76bbcd9d12e00124cbb7e70" +dependencies = [ + "fastdivide", + "fnv", + "itertools 0.11.0", + "serde", + "tantivy-bitpacker", + "tantivy-common", + "tantivy-sstable", + "tantivy-stacker", +] + +[[package]] +name = "tantivy-common" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af4a3a975e604a2aba6b1106a04505e1e7a025e6def477fab6e410b4126471e1" +dependencies = [ + "async-trait", + "byteorder 1.5.0", + "ownedbytes", + "serde", + "time 0.3.34", +] + +[[package]] +name = "tantivy-fst" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc3c506b1a8443a3a65352df6382a1fb6a7afe1a02e871cee0d25e2c3d5f3944" +dependencies = [ + "byteorder 1.5.0", + "regex-syntax 0.6.29", + "utf8-ranges", +] + +[[package]] +name = "tantivy-query-grammar" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d39c5a03100ac10c96e0c8b07538e2ab8b17da56434ab348309b31f23fada77" +dependencies = [ + "nom", +] + +[[package]] +name = "tantivy-sstable" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0c1bb43e5e8b8e05eb8009610344dbf285f06066c844032fbb3e546b3c71df" +dependencies = [ + "tantivy-common", + "tantivy-fst", + "zstd 0.12.4", +] + +[[package]] +name = "tantivy-stacker" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2c078595413f13f218cf6f97b23dcfd48936838f1d3d13a1016e05acd64ed6c" +dependencies = [ + "murmurhash32", + "tantivy-common", +] + +[[package]] +name = "tantivy-tokenizer-api" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "347b6fb212b26d3505d224f438e3c4b827ab8bd847fe9953ad5ac6b8f9443b66" +dependencies = [ + "serde", +] + +[[package]] +name = "tar" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand 2.0.1", + "rustix 0.38.31", + "windows-sys 0.52.0", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "terminal-prompt" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "572818b3472910acbd5dff46a3413715c18e934b071ab2ba464a7b2c2af16376" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "time" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" +dependencies = [ + "const_fn", + "libc", + "standback", + "stdweb", + "time-macros 0.1.1", + "version_check", + "winapi", +] + +[[package]] +name = "time" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros 0.2.17", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" +dependencies = [ + "proc-macro-hack", + "time-macros-impl", +] + +[[package]] +name = "time-macros" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "time-macros-impl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "standback", + "syn 1.0.109", +] + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.5.6", + "tokio-macros", + "tracing", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +dependencies = [ + "futures-util", + "log", + "rustls", + "tokio", + "tokio-rustls", + "tungstenite", + "webpki-roots", +] + +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a9aad4a3066010876e8dcf5a8a06e70a558751117a145c6ce2b82c2e2054290" +dependencies = [ + "indexmap 2.2.5", + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.6", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.2.5", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6" +dependencies = [ + "indexmap 2.2.5", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.6.5", +] + +[[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.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +dependencies = [ + "byteorder 1.5.0", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand", + "rustls", + "sha1 0.10.6", + "thiserror", + "url", + "utf-8", +] + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "static_assertions", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "uds_windows" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" +dependencies = [ + "memoffset 0.9.0", + "tempfile", + "winapi", +] + +[[package]] +name = "uname" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b72f89f0ca32e4db1c04e2a72f5345d59796d4866a1ee0609084569f73683dc8" +dependencies = [ + "libc", +] + +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "2.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11f214ce18d8b2cbe84ed3aa6486ed3f5b285cf8d8fbdbce9f3f767a724adc35" +dependencies = [ + "base64 0.21.7", + "log", + "native-tls", + "once_cell", + "url", +] + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8-ranges" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "uuid" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +dependencies = [ + "getrandom 0.2.12", + "serde", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[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.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "waker-fn" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[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.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.52", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" + +[[package]] +name = "web-sys" +version = "0.3.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[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-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[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" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efc5cf48f83140dcaab716eeaea345f9e93d0018fb81162753a3f76c3397b538" +dependencies = [ + "windows-core 0.53.0", + "windows-targets 0.52.4", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.4", +] + +[[package]] +name = "windows-core" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dcc5b895a6377f1ab9fa55acedab1fd5ac0db66ad1e6c7f47e28a22e446a5dd" +dependencies = [ + "windows-result", + "windows-targets 0.52.4", +] + +[[package]] +name = "windows-result" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd19df78e5168dfb0aedc343d1d1b8d422ab2db6756d2dc3fef75035402a3f64" +dependencies = [ + "windows-targets 0.52.4", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.4", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "xattr" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +dependencies = [ + "libc", + "linux-raw-sys 0.4.13", + "rustix 0.38.31", +] + +[[package]] +name = "xdg-home" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21e5a325c3cb8398ad6cf859c1135b25dd29e186679cf2da7581d9679f63b38e" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "xml-rs" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" + +[[package]] +name = "zbus" +version = "3.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "675d170b632a6ad49804c8cf2105d7c31eddd3312555cffd4b740e08e97c25e6" +dependencies = [ + "async-broadcast", + "async-executor", + "async-fs", + "async-io 1.13.0", + "async-lock 2.8.0", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "byteorder 1.5.0", + "derivative", + "enumflags2", + "event-listener 2.5.3", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "nix 0.26.4", + "once_cell", + "ordered-stream", + "rand", + "serde", + "serde_repr", + "sha1 0.10.6", + "static_assertions", + "tracing", + "uds_windows", + "winapi", + "xdg-home", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "3.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7131497b0f887e8061b430c530240063d33bf9455fa34438f388a245da69e0a5" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "437d738d3750bed6ca9b8d423ccc7a8eb284f6b1d6d4e225a0e4e6258d864c8d" +dependencies = [ + "serde", + "static_assertions", + "zvariant", +] + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" + +[[package]] +name = "zstd" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" +dependencies = [ + "zstd-safe 6.0.6", +] + +[[package]] +name = "zstd" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bffb3309596d527cfcba7dfc6ed6052f1d39dfbd7c867aa2e865e4a449c10110" +dependencies = [ + "zstd-safe 7.0.0", +] + +[[package]] +name = "zstd-safe" +version = "6.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-safe" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43747c7422e2924c11144d5229878b98180ef8b06cca4ab5af37afc8a8d8ea3e" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.9+zstd.1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "zvariant" +version = "3.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eef2be88ba09b358d3b58aca6e41cd853631d44787f319a1383ca83424fb2db" +dependencies = [ + "byteorder 1.5.0", + "enumflags2", + "libc", + "serde", + "static_assertions", + "zvariant_derive", +] + +[[package]] +name = "zvariant_derive" +version = "3.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37c24dc0bed72f5f90d1f8bb5b07228cbf63b3c6e9f82d82559d4bae666e7ed9" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7234f0d811589db492d16893e3f21e8e2fd282e6d01b0cddee310322062cc200" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..35755cd --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,56 @@ +[package] +name = "pesde" +version = "0.1.0" +edition = "2021" +license = "MIT" +authors = ["daimond113 "] +description = "A package manager for Roblox" +homepage = "https://pesde.daimond113.com" + +[features] +bin = ["clap", "directories", "keyring", "anyhow", "ignore", "pretty_env_logger", "serde_json", "reqwest/json", "reqwest/multipart", "lune", "futures-executor", "indicatif", "auth-git2", "indicatif-log-bridge"] + +[[bin]] +name = "pesde" +path = "src/main.rs" +required-features = ["bin"] + +[dependencies] +serde = { version = "1.0.197", features = ["derive"] } +serde_yaml = "0.9.32" +git2 = "0.18.2" +semver = { version = "1.0.22", features = ["serde"] } +reqwest = { version = "0.11.24", default-features = false, features = ["rustls-tls", "blocking"] } +tar = "0.4.40" +flate2 = "1.0.28" +pathdiff = "0.2.1" +relative-path = { version = "1.9.2", features = ["serde"] } +log = "0.4.20" +thiserror = "1.0.57" +threadpool = "1.8.1" +full_moon = { version = "0.19.0", features = ["stacker", "roblox"] } + +clap = { version = "4.5.1", features = ["derive"], optional = true } +directories = { version = "5.0.1", optional = true } +keyring = { version = "2.3.2", optional = true } +anyhow = { version = "1.0.80", optional = true } +ignore = { version = "0.4.22", optional = true } +pretty_env_logger = { version = "0.5.0", optional = true } +serde_json = { version = "1.0.114", optional = true } +lune = { version = "0.8.0", optional = true } +futures-executor = { version = "0.3.30", optional = true } +indicatif = { version = "0.17.8", optional = true } +auth-git2 = { version = "0.5.3", optional = true } +indicatif-log-bridge = { version = "0.2.2", optional = true } + +[dev-dependencies] +tempfile = "3.10.1" + +[workspace] +resolver = "2" +members = [ + "registry" +] + +[profile.dev.package.full_moon] +opt-level = 3 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d979d09 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM rust:1.76 + +COPY . . + +WORKDIR /registry + +RUN cargo install --path . + +CMD ["pesde-registry"] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..455350d --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# pesde + +pesde is a package manager for Roblox that is designed to be feature-rich and easy to use. +Currently, pesde is in a very early stage of development, but already supports the following features: + +- Managing dependencies +- Re-exporting types +- `bin` exports (ran with Lune) +- Patching packages + +## Installation + +pesde can be installed from GitHub Releases. You can find the latest release [here](https://github.com/daimond113/pesde/releases). +It can also be installed by using [Aftman](https://github.com/LPGhatguy/aftman). + +## Hosting + +The pesde registry is hosted on [fly.io](https://fly.io). You can find the registry [here](https://registry.pesde.daimond113.com). + +## Previous art + +pesde is heavily inspired by [npm](https://www.npmjs.com/), [pnpm](https://pnpm.io/), [wally](https://wally.run), and [cargo](https://doc.rust-lang.org/cargo/). It aims to take the best parts of each package manager and combine them into one. diff --git a/cliff.toml b/cliff.toml new file mode 100644 index 0000000..029e7b1 --- /dev/null +++ b/cliff.toml @@ -0,0 +1,86 @@ +[changelog] +header = """ +# Changelog\n +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n +""" + +body = """ +{%- macro remote_url() -%} + https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }} +{%- endmacro -%} + +{% if version -%} + ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} +{% else -%} + ## [Unreleased] +{% endif -%} + +### Details\ + +{% for group, commits in commits | group_by(attribute="group") %} + #### {{ group | upper_first }} + {%- for commit in commits %} + - {{ commit.message | upper_first | trim }}\ + {% if commit.github.username %} by @{{ commit.github.username }}{%- endif -%} + {% if commit.github.pr_number %} in \ + [#{{ commit.github.pr_number }}]({{ self::remote_url() }}/pull/{{ commit.github.pr_number }}) \ + {%- endif -%} + {% endfor %} +{% endfor %} + +{%- if github.contributors | filter(attribute="is_first_time", value=true) | length != 0 %} + ## New Contributors +{%- endif -%} + +{% for contributor in github.contributors | filter(attribute="is_first_time", value=true) %} + * @{{ contributor.username }} made their first contribution + {%- if contributor.pr_number %} in \ + [#{{ contributor.pr_number }}](({{ self::remote_url() }}/pull/{{ contributor.pr_number }}) \ + {%- endif %} +{%- endfor %}\n +""" + +footer = """ +{%- macro remote_url() -%} + https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }} +{%- endmacro -%} + +{% for release in releases -%} + {% if release.version -%} + {% if release.previous.version -%} + [{{ release.version | trim_start_matches(pat="v") }}]: \ + {{ self::remote_url() }}/compare/{{ release.previous.version }}..{{ release.version }} + {% endif -%} + {% else -%} + [unreleased]: {{ self::remote_url() }}/compare/{{ release.previous.version }}..HEAD + {% endif -%} +{% endfor %} + +""" +trim = true + +[git] +conventional_commits = true +filter_unconventional = true +split_commits = false +commit_parsers = [ + { message = "^feat", group = "Features" }, + { message = "^fix", group = "Bug Fixes" }, + { message = "^doc", group = "Documentation", default_scope = "unscoped" }, + { message = "^perf", group = "Performance" }, + { message = "^refactor", group = "Refactor" }, + { message = "^style", group = "Styling" }, + { message = "^test", group = "Testing" }, + { message = "^chore\\(release\\): prepare for", skip = true }, + { message = "^chore", group = "Miscellaneous Tasks" }, + { body = ".*security", group = "Security" }, +] +protect_breaking_commits = true +filter_commits = true +tag_pattern = "v[0-9].*" +ignore_tags = "" +topo_order = true +sort_commits = "newest" \ No newline at end of file diff --git a/fly.toml b/fly.toml new file mode 100644 index 0000000..d4c97ac --- /dev/null +++ b/fly.toml @@ -0,0 +1,31 @@ +# fly.toml app configuration file generated for pesde-registry on 2024-03-04T20:57:13+01:00 +# +# See https://fly.io/docs/reference/configuration/ for information about how to use this file. +# + +app = 'pesde-registry' +primary_region = 'waw' +kill_signal = 'SIGINT' +kill_timeout = '5s' + +[build] + +[env] +ADDRESS = '0.0.0.0' +PORT = '8080' +INDEX_REPO_URL = 'https://github.com/daimond113/pesde-index' +COMITTER_GIT_NAME = 'Pesde Index Updater' +COMITTER_GIT_EMAIL = 'pesde@daimond113.com' + +[http_service] +internal_port = 8080 +force_https = true +auto_stop_machines = true +auto_start_machines = true +min_machines_running = 0 +processes = ['app'] + +[[vm]] +memory = '1gb' +cpu_kind = 'shared' +cpus = 1 diff --git a/registry/.env.example b/registry/.env.example new file mode 100644 index 0000000..778c2a2 --- /dev/null +++ b/registry/.env.example @@ -0,0 +1,11 @@ +INDEX_REPO_URL=# url of the git repository to be used as the package index +S3_ENDPOINT=# endpoint of the s3 bucket +S3_BUCKET_NAME=# name of the s3 bucket +S3_REGION=# region of the s3 bucket +S3_ACCESS_KEY=# access key of the s3 bucket +S3_SECRET_KEY=# secret key of the s3 bucket +COMMITTER_GIT_NAME=# name of the committer used for index updates +COMMITTER_GIT_EMAIL=# email of the committer used for index updates +GITHUB_USERNAME=# username of github account with push access to the index repository +GITHUB_PAT=# personal access token of github account with push access to the index repository +SENTRY_URL=# optional url of sentry error tracking \ No newline at end of file diff --git a/registry/Cargo.lock b/registry/Cargo.lock new file mode 100644 index 0000000..ec1fa89 --- /dev/null +++ b/registry/Cargo.lock @@ -0,0 +1,3201 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "actix-codec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" +dependencies = [ + "bitflags 1.3.2", + "bytes", + "futures-core", + "futures-sink", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "actix-cors" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9e772b3bcafe335042b5db010ab7c09013dad6eac4915c91d8d50902769f331" +dependencies = [ + "actix-utils", + "actix-web", + "derive_more", + "futures-util", + "log", + "once_cell", + "smallvec", +] + +[[package]] +name = "actix-http" +version = "3.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "129d4c88e98860e1758c5de288d1632b07970a16d59bdf7b8d66053d582bb71f" +dependencies = [ + "actix-codec", + "actix-rt", + "actix-service", + "actix-utils", + "ahash", + "base64", + "bitflags 2.4.2", + "brotli", + "bytes", + "bytestring", + "derive_more", + "encoding_rs", + "flate2", + "futures-core", + "h2", + "http", + "httparse", + "httpdate", + "itoa", + "language-tags", + "local-channel", + "mime", + "percent-encoding", + "pin-project-lite", + "rand", + "sha1", + "smallvec", + "tokio", + "tokio-util", + "tracing", + "zstd", +] + +[[package]] +name = "actix-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" +dependencies = [ + "quote", + "syn 2.0.48", +] + +[[package]] +name = "actix-router" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22475596539443685426b6bdadb926ad0ecaefdfc5fb05e5e3441f15463c511" +dependencies = [ + "bytestring", + "http", + "regex", + "serde", + "tracing", +] + +[[package]] +name = "actix-rt" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28f32d40287d3f402ae0028a9d54bef51af15c8769492826a69d28f81893151d" +dependencies = [ + "futures-core", + "tokio", +] + +[[package]] +name = "actix-server" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb13e7eef0423ea6eab0e59f6c72e7cb46d33691ad56a726b3cd07ddec2c2d4" +dependencies = [ + "actix-rt", + "actix-service", + "actix-utils", + "futures-core", + "futures-util", + "mio", + "socket2", + "tokio", + "tracing", +] + +[[package]] +name = "actix-service" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" +dependencies = [ + "futures-core", + "paste", + "pin-project-lite", +] + +[[package]] +name = "actix-utils" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" +dependencies = [ + "local-waker", + "pin-project-lite", +] + +[[package]] +name = "actix-web" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e43428f3bf11dee6d166b00ec2df4e3aa8cc1606aaa0b7433c146852e2f4e03b" +dependencies = [ + "actix-codec", + "actix-http", + "actix-macros", + "actix-router", + "actix-rt", + "actix-server", + "actix-service", + "actix-utils", + "actix-web-codegen", + "ahash", + "bytes", + "bytestring", + "cfg-if", + "cookie", + "derive_more", + "encoding_rs", + "futures-core", + "futures-util", + "itoa", + "language-tags", + "log", + "mime", + "once_cell", + "pin-project-lite", + "regex", + "serde", + "serde_json", + "serde_urlencoded", + "smallvec", + "socket2", + "time", + "url", +] + +[[package]] +name = "actix-web-codegen" +version = "4.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb1f50ebbb30eca122b188319a4398b3f7bb4a8cdf50ecfb73bfc6a3c3ce54f5" +dependencies = [ + "actix-router", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "actix-web-httpauth" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d613edf08a42ccc6864c941d30fe14e1b676a77d16f1dbadc1174d065a0a775" +dependencies = [ + "actix-utils", + "actix-web", + "base64", + "futures-core", + "futures-util", + "log", + "pin-project-lite", +] + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "arc-swap" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" + +[[package]] +name = "async-trait" +version = "0.1.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atomic-write-file" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edcdbedc2236483ab103a53415653d6b4442ea6141baf1ffa85df29635e88436" +dependencies = [ + "nix", + "rand", +] + +[[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.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bcrypt" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d1c9c15093eb224f0baa400f38fcd713fc1391a6f1c389d886beef146d60a3" +dependencies = [ + "base64", + "blowfish", + "getrandom", + "subtle", + "zeroize", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +dependencies = [ + "serde", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blowfish" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" +dependencies = [ + "byteorder", + "cipher", +] + +[[package]] +name = "brotli" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516074a47ef4bce09577a3b379392300159ce5b1ba2e501ff1c819950066100f" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "bytestring" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d80203ea6b29df88012294f62733de21cfeab47f17b41af3a38bc30a03ee72" +dependencies = [ + "bytes", +] + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets 0.52.0", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "cookie" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[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 = "cuid-util" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea2bfe0336ff1b7ca74819b2df8dfae9afea358aff6b1688baa5c181d8c3713" + +[[package]] +name = "cuid2" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d99cacd52fd67db7490ad051c8c1973fb75520174d69aabbae08c534c9d0e8" +dependencies = [ + "cuid-util", + "num", + "rand", + "sha3", +] + +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +dependencies = [ + "serde", +] + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "finl_unicode" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" + +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "futures-core", + "futures-sink", + "spin 0.9.8", +] + +[[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.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "h2" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "http" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "http-range-header" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +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.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http", + "hyper", + "log", + "rustls", + "rustls-native-certs", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "if_chain" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" + +[[package]] +name = "indexmap" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf2a4f498956c7723dc280afc6a37d0dec50b39a29e232c6187ce4503703e8c2" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "iri-string" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21859b667d66a4c1dacd9df0863b3efb65785474255face87f5bca39dd8407c0" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "itertools" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "jobserver" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "9.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7ea04a7c5c055c175f189b6dc6ba036fd62306b58c66c9f6389036c503a3f4" +dependencies = [ + "base64", + "js-sys", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "language-tags" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] + +[[package]] +name = "libc" +version = "0.2.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libsqlite3-sys" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "local-channel" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6cbc85e69b8df4b8bb8b89ec634e7189099cea8927a276b7384ce5488e53ec8" +dependencies = [ + "futures-core", + "futures-sink", + "local-waker", +] + +[[package]] +name = "local-waker" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nix" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +dependencies = [ + "bitflags 2.4.2", + "cfg-if", + "libc", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-complex" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "octocrab" +version = "0.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054a8bf47dfa8f89bb0dcf17e485e9f49f2586c05bf0aa67b8ec5a9e7bc8dfd5" +dependencies = [ + "arc-swap", + "async-trait", + "base64", + "bytes", + "cfg-if", + "chrono", + "either", + "futures", + "futures-util", + "http", + "http-body", + "hyper", + "hyper-rustls", + "hyper-timeout", + "jsonwebtoken", + "once_cell", + "percent-encoding", + "pin-project", + "secrecy", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "snafu", + "tokio", + "tower", + "tower-http", + "tracing", + "url", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "openssl" +version = "0.10.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8" +dependencies = [ + "bitflags 2.4.2", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[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.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "organizations" +version = "0.1.0" + +[[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.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "pem" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8fcc794035347fb64beda2d3b462595dd2753e3f268d89c5aae77e8cf2c310" +dependencies = [ + "base64", + "serde", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-xml" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "registry" +version = "0.1.0" +dependencies = [ + "actix-cors", + "actix-web", + "actix-web-httpauth", + "bcrypt", + "chrono", + "cuid2", + "derive_more", + "dotenvy", + "log", + "octocrab", + "reqwest", + "rusty-s3", + "serde", + "serde_json", + "sqlx", + "validator", +] + +[[package]] +name = "reqwest" +version = "0.11.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "ring" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted", + "windows-sys 0.48.0", +] + +[[package]] +name = "rsa" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" +dependencies = [ + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.21.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-native-certs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rusty-s3" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31aa883f1b986a5249641e574ca0e11ac4fb9970b009c6fbb96fedaf4fa78db8" +dependencies = [ + "base64", + "hmac", + "md-5", + "percent-encoding", + "quick-xml", + "serde", + "serde_json", + "sha2", + "time", + "url", + "zeroize", +] + +[[package]] +name = "ryu" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" + +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" + +[[package]] +name = "serde" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "serde_json" +version = "1.0.112" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d1bd37ce2324cf3bf85e5a25f96eb4baf0d5aa6eba43e7ae8958870c4ec48ed" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd154a240de39fdebcf5775d2675c204d7c13cf39a4c697be6493c8e734337c" +dependencies = [ + "itoa", + "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 = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" + +[[package]] +name = "snafu" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4de37ad025c587a29e8f3f5605c00f70b98715ef90b9061a815b9e59e9042d6" +dependencies = [ + "backtrace", + "doc-comment", + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990079665f075b699031e9c08fd3ab99be5029b96f3b78dc0709e8f77e4efebf" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlformat" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c" +dependencies = [ + "itertools", + "nom", + "unicode_categories", +] + +[[package]] +name = "sqlx" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd" +dependencies = [ + "ahash", + "atoi", + "byteorder", + "bytes", + "crc", + "crossbeam-queue", + "dotenvy", + "either", + "event-listener", + "futures-channel", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashlink", + "hex", + "indexmap", + "log", + "memchr", + "native-tls", + "once_cell", + "paste", + "percent-encoding", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlformat", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "url", +] + +[[package]] +name = "sqlx-macros" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 1.0.109", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0bd4519486723648186a08785143599760f7cc81c52334a55d6a83ea1e20841" +dependencies = [ + "atomic-write-file", + "dotenvy", + "either", + "heck", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-mysql", + "sqlx-sqlite", + "syn 1.0.109", + "tempfile", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4" +dependencies = [ + "atoi", + "base64", + "bitflags 2.4.2", + "byteorder", + "bytes", + "crc", + "digest", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "percent-encoding", + "rand", + "rsa", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24" +dependencies = [ + "atoi", + "base64", + "bitflags 2.4.2", + "byteorder", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand", + "serde", + "serde_json", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490" +dependencies = [ + "atoi", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "sqlx-core", + "tracing", + "url", + "urlencoding", +] + +[[package]] +name = "stringprep" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" +dependencies = [ + "finl_unicode", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "thiserror" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "time" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" +dependencies = [ + "deranged", + "itoa", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" +dependencies = [ + "time-core", +] + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.35.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" +dependencies = [ + "bitflags 2.4.2", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[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.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna 0.5.0", + "percent-encoding", + "serde", +] + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "validator" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b92f40481c04ff1f4f61f304d61793c7b56ff76ac1469f1beb199b1445b253bd" +dependencies = [ + "idna 0.4.0", + "lazy_static", + "regex", + "serde", + "serde_derive", + "serde_json", + "url", + "validator_derive", +] + +[[package]] +name = "validator_derive" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc44ca3088bb3ba384d9aecf40c6a23a676ce23e09bdaca2073d99c207f864af" +dependencies = [ + "if_chain", + "lazy_static", + "proc-macro-error", + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", + "validator_types", +] + +[[package]] +name = "validator_types" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "111abfe30072511849c5910134e8baf8dc05de4c0e5903d681cbd5c9c4d611e3" +dependencies = [ + "proc-macro2", + "syn 1.0.109", +] + +[[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.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.48", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" + +[[package]] +name = "web-sys" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "whoami" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" + +[[package]] +name = "zstd" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bffb3309596d527cfcba7dfc6ed6052f1d39dfbd7c867aa2e865e4a449c10110" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43747c7422e2924c11144d5229878b98180ef8b06cca4ab5af37afc8a8d8ea3e" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.9+zstd.1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/registry/Cargo.toml b/registry/Cargo.toml new file mode 100644 index 0000000..851c78d --- /dev/null +++ b/registry/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "pesde-registry" +version = "0.1.0" +edition = "2021" + +[dependencies] +actix-web = "4.5.1" +actix-cors = "0.7.0" +actix-web-httpauth = "0.8.1" +actix-multipart = "0.6.1" +actix-multipart-derive = "0.6.1" +dotenvy = "0.15.7" +reqwest = { version = "0.11.24", features = ["json", "blocking"] } +rusty-s3 = "0.5.0" +serde = { version = "1.0.197", features = ["derive"] } +serde_json = "1.0.114" +serde_yaml = "0.9.32" +flate2 = "1.0.28" +tar = "0.4.40" +pesde = { path = ".." } +semver = "1.0.22" +git2 = "0.18.2" +thiserror = "1.0.57" +tantivy = "0.21.1" +log = "0.4.21" +pretty_env_logger = "0.5.0" +sentry = "0.32.2" +sentry-log = "0.32.2" +sentry-actix = "0.32.2" \ No newline at end of file diff --git a/registry/src/endpoints/mod.rs b/registry/src/endpoints/mod.rs new file mode 100644 index 0000000..d1cd92d --- /dev/null +++ b/registry/src/endpoints/mod.rs @@ -0,0 +1,8 @@ +use actix_web::web; + +pub mod packages; +pub mod search; + +pub fn configure(cfg: &mut web::ServiceConfig) { + cfg.configure(packages::configure); +} diff --git a/registry/src/endpoints/packages.rs b/registry/src/endpoints/packages.rs new file mode 100644 index 0000000..be879be --- /dev/null +++ b/registry/src/endpoints/packages.rs @@ -0,0 +1,208 @@ +use actix_multipart::form::{bytes::Bytes, MultipartForm}; +use actix_web::{get, post, web, HttpResponse, Responder}; +use flate2::read::GzDecoder; +use reqwest::StatusCode; +use rusty_s3::S3Action; +use tantivy::{doc, Term}; +use tar::Archive; + +use pesde::{ + dependencies::DependencySpecifier, index::Index, manifest::Manifest, package_name::PackageName, + IGNORED_FOLDERS, MANIFEST_FILE_NAME, +}; + +use crate::{commit_signature, errors, AppState, UserId, S3_EXPIRY}; + +#[derive(MultipartForm)] +struct CreateForm { + #[multipart(limit = "4 MiB")] + tarball: Bytes, +} + +#[post("/packages")] +async fn create( + form: MultipartForm, + app_state: web::Data, + user_id: web::ReqData, +) -> Result { + let bytes = form.tarball.data.as_ref().to_vec(); + let mut decoder = GzDecoder::new(bytes.as_slice()); + let mut archive = Archive::new(&mut decoder); + + let archive_entries = archive.entries()?.filter_map(|e| e.ok()); + + let mut manifest = None; + + for mut e in archive_entries { + let Ok(path) = e.path() else { + return Ok(HttpResponse::BadRequest().json(errors::ErrorResponse { + error: "Attached file contains non-UTF-8 path".to_string(), + })); + }; + + let Some(path) = path.as_os_str().to_str() else { + return Ok(HttpResponse::BadRequest().json(errors::ErrorResponse { + error: "Attached file contains non-UTF-8 path".to_string(), + })); + }; + + match path { + MANIFEST_FILE_NAME => { + if !e.header().entry_type().is_file() { + continue; + } + + let received_manifest: Manifest = + serde_yaml::from_reader(&mut e).map_err(errors::Errors::UserYaml)?; + + manifest = Some(received_manifest); + } + path => { + if e.header().entry_type().is_file() { + continue; + } + + if IGNORED_FOLDERS.contains(&path) { + return Ok(HttpResponse::BadRequest().json(errors::ErrorResponse { + error: format!("Attached file contains forbidden directory {}", path), + })); + } + } + } + } + + let Some(manifest) = manifest else { + return Ok(HttpResponse::BadRequest().json(errors::ErrorResponse { + error: format!("Attached file doesn't contain {MANIFEST_FILE_NAME}"), + })); + }; + + let (scope, name) = manifest.name.parts(); + + { + let mut index = app_state.index.lock().unwrap(); + let config = index.config()?; + + for (dependency, _) in manifest.dependencies().iter() { + match dependency { + DependencySpecifier::Git(_) => { + if !config.git_allowed { + return Ok(HttpResponse::BadRequest().json(errors::ErrorResponse { + error: "Git dependencies are not allowed on this registry".to_string(), + })); + } + } + DependencySpecifier::Registry(registry) => { + if index.package(®istry.name).unwrap().is_none() { + return Ok(HttpResponse::BadRequest().json(errors::ErrorResponse { + error: format!("Dependency {} not found", registry.name), + })); + } + } + }; + } + + let success = index.create_package_version(&manifest, &user_id.0)?; + + if !success { + return Ok(HttpResponse::BadRequest().json(errors::ErrorResponse { + error: format!( + "Version {} of {} already exists", + manifest.version, manifest.name + ), + })); + } + + index.commit_and_push( + &format!("Add version {}@{}", manifest.name, manifest.version), + &commit_signature(), + )?; + } + + { + let mut search_writer = app_state.search_writer.lock().unwrap(); + let schema = search_writer.index().schema(); + let name_field = schema.get_field("name").unwrap(); + + search_writer.delete_term(Term::from_field_text( + name_field, + &manifest.name.to_string(), + )); + + search_writer.add_document( + doc!( + name_field => manifest.name.to_string(), + schema.get_field("version").unwrap() => manifest.version.to_string(), + schema.get_field("description").unwrap() => manifest.description.unwrap_or_default(), + ) + ).unwrap(); + + search_writer.commit().unwrap(); + } + + let url = app_state + .s3_bucket + .put_object( + Some(&app_state.s3_credentials), + &*format!("{scope}-{name}-{}.tar.gz", manifest.version), + ) + .sign(S3_EXPIRY); + + app_state.reqwest_client.put(url).body(bytes).send().await?; + + Ok(HttpResponse::Ok().body(format!( + "Successfully published {}@{}", + manifest.name, manifest.version + ))) +} + +#[get("/packages/{author_name}/{package_name}/{version}")] +async fn get( + app_state: web::Data, + path: web::Path<(String, String, String)>, +) -> Result { + let (scope, name, version) = path.into_inner(); + + let package_name = PackageName::new(&scope, &name)?; + + { + let index = app_state.index.lock().unwrap(); + + if !index.package(&package_name)?.is_some() { + return Ok(HttpResponse::NotFound().finish()); + } + } + + let url = app_state + .s3_bucket + .get_object( + Some(&app_state.s3_credentials), + &*format!("{scope}-{name}-{version}.tar.gz"), + ) + .sign(S3_EXPIRY); + + let response = match app_state + .reqwest_client + .get(url) + .send() + .await? + .error_for_status() + { + Ok(response) => response, + Err(e) => { + if let Some(status) = e.status() { + if status == StatusCode::NOT_FOUND { + return Ok(HttpResponse::NotFound().finish()); + } + } + + return Err(e.into()); + } + }; + + Ok(HttpResponse::Ok().body(response.bytes().await?)) +} + +pub fn configure(cfg: &mut web::ServiceConfig) { + cfg.service(create).service(get); +} diff --git a/registry/src/endpoints/search.rs b/registry/src/endpoints/search.rs new file mode 100644 index 0000000..1aedb23 --- /dev/null +++ b/registry/src/endpoints/search.rs @@ -0,0 +1,56 @@ +use actix_web::{get, web, Responder}; +use serde::Deserialize; +use serde_json::{json, Value}; + +use crate::{errors, AppState}; + +#[derive(Deserialize)] +struct Query { + query: String, +} + +#[get("/search")] +async fn search( + app_state: web::Data, + query: web::Query, +) -> Result { + let searcher = app_state.search_reader.searcher(); + let schema = searcher.schema(); + + let name = schema.get_field("name").unwrap(); + let version = schema.get_field("version").unwrap(); + let description = schema.get_field("description").unwrap(); + + let query = query.query.trim(); + + if query.is_empty() { + return Ok(web::Json(vec![])); + } + + let query_parser = + tantivy::query::QueryParser::for_index(&searcher.index(), vec![name, description]); + let query = query_parser.parse_query(&query)?; + + let top_docs = searcher + .search(&query, &tantivy::collector::TopDocs::with_limit(10)) + .unwrap(); + + Ok(web::Json( + top_docs + .into_iter() + .map(|(_, doc_address)| { + let retrieved_doc = searcher.doc(doc_address).unwrap(); + + json!({ + "name": retrieved_doc.get_first(name).unwrap().as_text().unwrap(), + "version": retrieved_doc.get_first(version).unwrap().as_text().unwrap(), + "description": retrieved_doc.get_first(description).unwrap().as_text().unwrap(), + }) + }) + .collect::>(), + )) +} + +pub fn configure(cfg: &mut web::ServiceConfig) { + cfg.service(search); +} diff --git a/registry/src/errors.rs b/registry/src/errors.rs new file mode 100644 index 0000000..f84f70e --- /dev/null +++ b/registry/src/errors.rs @@ -0,0 +1,71 @@ +use actix_web::{HttpResponse, ResponseError}; +use log::error; +use serde::Serialize; +use thiserror::Error; + +#[derive(Serialize)] +pub struct ErrorResponse { + pub error: String, +} + +#[derive(Debug, Error)] +pub enum Errors { + #[error("io error")] + Io(#[from] std::io::Error), + + #[error("user yaml error")] + UserYaml(serde_yaml::Error), + + #[error("reqwest error")] + Reqwest(#[from] reqwest::Error), + + #[error("package name invalid")] + PackageName(#[from] pesde::package_name::PackageNameValidationError), + + #[error("config error")] + Config(#[from] pesde::index::ConfigError), + + #[error("create package version error")] + CreatePackageVersion(#[from] pesde::index::CreatePackageVersionError), + + #[error("commit and push error")] + CommitAndPush(#[from] pesde::index::CommitAndPushError), + + #[error("index package error")] + IndexPackage(#[from] pesde::index::IndexPackageError), + + #[error("error parsing query")] + QueryParser(#[from] tantivy::query::QueryParserError), +} + +impl ResponseError for Errors { + fn error_response(&self) -> HttpResponse { + match self { + Errors::UserYaml(_) | Errors::PackageName(_) | Errors::QueryParser(_) => {} + Errors::CreatePackageVersion(err) => match err { + pesde::index::CreatePackageVersionError::MissingScopeOwnership => { + return HttpResponse::Unauthorized().json(ErrorResponse { + error: "You do not have permission to publish this scope".to_string(), + }); + } + _ => error!("{err:?}"), + }, + err => { + error!("{err:?}"); + } + } + + match self { + Errors::UserYaml(err) => HttpResponse::BadRequest().json(ErrorResponse { + error: format!("Error parsing YAML file: {}", err.to_string()), + }), + Errors::PackageName(err) => HttpResponse::BadRequest().json(ErrorResponse { + error: format!("Invalid package name: {}", err.to_string()), + }), + Errors::QueryParser(err) => HttpResponse::BadRequest().json(ErrorResponse { + error: format!("Error parsing query: {}", err.to_string()), + }), + _ => HttpResponse::InternalServerError().finish(), + } + } +} diff --git a/registry/src/main.rs b/registry/src/main.rs new file mode 100644 index 0000000..18a1c6f --- /dev/null +++ b/registry/src/main.rs @@ -0,0 +1,272 @@ +use std::{fs::read_dir, sync::Mutex, time::Duration}; + +use actix_cors::Cors; +use actix_web::{ + dev::ServiceRequest, + error::ErrorUnauthorized, + middleware::{Compress, Condition}, + rt::System, + web, App, Error, HttpMessage, HttpServer, +}; +use actix_web_httpauth::{extractors::bearer::BearerAuth, middleware::HttpAuthentication}; +use dotenvy::dotenv; +use git2::{Cred, Signature}; +use log::info; +use reqwest::{header::AUTHORIZATION, Client}; +use rusty_s3::{Bucket, Credentials, UrlStyle}; +use tantivy::{doc, IndexReader, IndexWriter}; + +use pesde::{ + index::{GitIndex, IndexFile}, + package_name::PackageName, +}; + +mod endpoints; +mod errors; + +const S3_EXPIRY: Duration = Duration::from_secs(60 * 60); + +struct AppState { + s3_bucket: Bucket, + s3_credentials: Credentials, + reqwest_client: Client, + index: Mutex, + + search_reader: IndexReader, + search_writer: Mutex, +} + +macro_rules! get_env { + ($name:expr, "p") => { + std::env::var($name) + .expect(concat!("Environment variable `", $name, "` must be set")) + .parse() + .expect(concat!( + "Environment variable `", + $name, + "` must be a valid value" + )) + }; + ($name:expr) => { + std::env::var($name).expect(concat!("Environment variable `", $name, "` must be set")) + }; + ($name:expr, $default:expr, "p") => { + std::env::var($name) + .unwrap_or($default.to_string()) + .parse() + .expect(concat!( + "Environment variable `", + $name, + "` must a valid value" + )) + }; + ($name:expr, $default:expr) => { + std::env::var($name).unwrap_or($default.to_string()) + }; +} + +pub fn commit_signature<'a>() -> Signature<'a> { + Signature::now( + &get_env!("COMMITTER_GIT_NAME"), + &get_env!("COMMITTER_GIT_EMAIL"), + ) + .unwrap() +} + +#[derive(Debug, Clone)] +pub struct UserId(pub u64); + +async fn validator( + req: ServiceRequest, + credentials: BearerAuth, +) -> Result { + let token = credentials.token(); + let app_state = req.app_data::>().unwrap(); + + let Ok(user_info) = app_state + .reqwest_client + .get("https://api.github.com/user") + .header(AUTHORIZATION, format!("Bearer {}", token)) + .send() + .await + .map(|r| r.json::()) + else { + return Err((ErrorUnauthorized("Failed to fetch user info"), req)); + }; + + let Ok(user_info) = user_info.await else { + return Err((ErrorUnauthorized("Failed to parse user info"), req)); + }; + + let Some(id) = user_info["id"].as_u64() else { + return Err((ErrorUnauthorized("Failed to fetch user info"), req)); + }; + + req.extensions_mut().insert(UserId(id)); + + Ok(req) +} + +fn search_index(index: &GitIndex) -> (IndexReader, IndexWriter) { + let mut schema_builder = tantivy::schema::SchemaBuilder::new(); + let name = + schema_builder.add_text_field("name", tantivy::schema::TEXT | tantivy::schema::STORED); + let version = + schema_builder.add_text_field("version", tantivy::schema::TEXT | tantivy::schema::STORED); + let description = schema_builder.add_text_field( + "description", + tantivy::schema::TEXT | tantivy::schema::STORED, + ); + + let search_index = tantivy::Index::create_in_ram(schema_builder.build()); + let search_reader = search_index + .reader_builder() + .reload_policy(tantivy::ReloadPolicy::OnCommit) + .try_into() + .unwrap(); + let mut search_writer = search_index.writer(50_000_000).unwrap(); + + for entry in read_dir(index.path()).unwrap() { + let entry = entry.unwrap(); + let path = entry.path(); + + if !path.is_dir() || path.file_name().unwrap() == ".git" { + continue; + } + + let scope = path.file_name().unwrap().to_str().unwrap(); + + for entry in read_dir(&path).unwrap() { + let entry = entry.unwrap(); + let path = entry.path(); + + if !path.is_file() || path.extension().is_some() { + continue; + } + + let package = path.file_name().unwrap().to_str().unwrap(); + + let package_name = PackageName::new(scope, package).unwrap(); + let entries: IndexFile = + serde_yaml::from_slice(&std::fs::read(&path).unwrap()).unwrap(); + let entry = entries + .iter() + .max_by(|a, b| a.version.cmp(&b.version)) + .unwrap() + .clone(); + + search_writer + .add_document(doc!( + name => package_name.to_string(), + version => entry.version.to_string(), + description => entry.description.unwrap_or_default() + )) + .unwrap(); + } + } + + search_writer.commit().unwrap(); + + (search_reader, search_writer) +} + +fn main() -> std::io::Result<()> { + dotenv().ok(); + + let sentry_url = std::env::var("SENTRY_URL").ok(); + let with_sentry = sentry_url.is_some(); + + let mut log_builder = pretty_env_logger::formatted_builder(); + log_builder.parse_env(pretty_env_logger::env_logger::Env::default().default_filter_or("info")); + + if with_sentry { + let logger = sentry_log::SentryLogger::with_dest(log_builder.build()); + log::set_boxed_logger(Box::new(logger)).unwrap(); + log::set_max_level(log::LevelFilter::Info); + } else { + log_builder.try_init().unwrap(); + } + + let _guard = if let Some(sentry_url) = sentry_url { + std::env::set_var("RUST_BACKTRACE", "1"); + + Some(sentry::init(( + sentry_url, + sentry::ClientOptions { + release: sentry::release_name!(), + ..Default::default() + }, + ))) + } else { + None + }; + + let address = get_env!("ADDRESS", "127.0.0.1"); + let port: u16 = get_env!("PORT", "8080", "p"); + + let current_dir = std::env::current_dir().unwrap(); + + let index = GitIndex::new( + current_dir.join("cache"), + &get_env!("INDEX_REPO_URL"), + Some(Box::new(|| { + Box::new(|_, _, _| { + let username = get_env!("GITHUB_USERNAME"); + let pat = get_env!("GITHUB_PAT"); + + Cred::userpass_plaintext(&username, &pat) + }) + })), + ); + index.refresh().expect("failed to refresh index"); + + let (search_reader, search_writer) = search_index(&index); + + let app_data = web::Data::new(AppState { + s3_bucket: Bucket::new( + get_env!("S3_ENDPOINT", "p"), + UrlStyle::Path, + get_env!("S3_BUCKET_NAME"), + get_env!("S3_REGION"), + ) + .unwrap(), + s3_credentials: Credentials::new(get_env!("S3_ACCESS_KEY"), get_env!("S3_SECRET_KEY")), + reqwest_client: Client::builder() + .user_agent(concat!( + env!("CARGO_PKG_NAME"), + "/", + env!("CARGO_PKG_VERSION") + )) + .build() + .unwrap(), + index: Mutex::new(index), + + search_reader, + search_writer: Mutex::new(search_writer), + }); + + info!("listening on {address}:{port}"); + + System::new().block_on(async move { + HttpServer::new(move || { + App::new() + .wrap(Condition::new(with_sentry, sentry_actix::Sentry::new())) + .wrap(Cors::permissive()) + .wrap(Compress::default()) + .app_data(app_data.clone()) + .route("/", web::get().to(|| async { env!("CARGO_PKG_VERSION") })) + .service( + web::scope("/v0") + .configure(endpoints::search::configure) + .service( + web::scope("") + .wrap(HttpAuthentication::with_fn(validator)) + .configure(endpoints::configure), + ), + ) + }) + .bind((address, port))? + .run() + .await + }) +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..31578d3 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "stable" \ No newline at end of file diff --git a/src/cli/auth.rs b/src/cli/auth.rs new file mode 100644 index 0000000..419ed21 --- /dev/null +++ b/src/cli/auth.rs @@ -0,0 +1,110 @@ +use clap::Subcommand; +use pesde::index::Index; +use reqwest::{header::AUTHORIZATION, Url}; + +use crate::{send_request, CliParams}; + +#[derive(Subcommand)] +pub enum AuthCommand { + /// Logs in to the registry + Login, + /// Logs out from the registry + Logout, +} + +pub fn auth_command(cmd: AuthCommand, params: CliParams) -> anyhow::Result<()> { + let index_config = params.index.config()?; + + match cmd { + AuthCommand::Login => { + let response = send_request!(params.reqwest_client.post(Url::parse_with_params( + "https://github.com/login/device/code", + &[("client_id", index_config.github_oauth_client_id.as_str())], + )?)) + .json::()?; + + println!( + "go to {} and enter the code `{}`", + response["verification_uri"], response["user_code"] + ); + + let mut time_left = response["expires_in"] + .as_i64() + .ok_or(anyhow::anyhow!("couldn't get expires_in"))?; + let interval = std::time::Duration::from_secs( + response["interval"] + .as_u64() + .ok_or(anyhow::anyhow!("couldn't get interval"))?, + ); + let device_code = response["device_code"] + .as_str() + .ok_or(anyhow::anyhow!("couldn't get device_code"))?; + + while time_left > 0 { + std::thread::sleep(interval); + time_left -= interval.as_secs() as i64; + let response = send_request!(params.reqwest_client.post(Url::parse_with_params( + "https://github.com/login/oauth/access_token", + &[ + ("client_id", index_config.github_oauth_client_id.as_str()), + ("device_code", device_code), + ("grant_type", "urn:ietf:params:oauth:grant-type:device_code") + ], + )?)) + .json::()?; + + match response + .get("error") + .map(|s| { + s.as_str() + .ok_or(anyhow::anyhow!("couldn't get error as string")) + }) + .unwrap_or(Ok(""))? + { + "authorization_pending" => continue, + "slow_down" => { + std::thread::sleep(std::time::Duration::from_secs(5)); + continue; + } + "expired_token" => { + break; + } + "access_denied" => { + anyhow::bail!("access denied, re-run the login command"); + } + _ => (), + } + + if response.get("access_token").is_some() { + let access_token = response["access_token"] + .as_str() + .ok_or(anyhow::anyhow!("couldn't get access_token"))?; + + params.api_token_entry.set_password(access_token)?; + + let response = send_request!(params + .reqwest_client + .get("https://api.github.com/user") + .header(AUTHORIZATION, format!("Bearer {access_token}"))) + .json::()?; + + let login = response["login"] + .as_str() + .ok_or(anyhow::anyhow!("couldn't get login"))?; + + println!("you're now logged in as {login}"); + return Ok(()); + } + } + + anyhow::bail!("code expired, please re-run the login command"); + } + AuthCommand::Logout => { + params.api_token_entry.delete_password()?; + + println!("you're now logged out"); + } + } + + Ok(()) +} diff --git a/src/cli/config.rs b/src/cli/config.rs new file mode 100644 index 0000000..c09689d --- /dev/null +++ b/src/cli/config.rs @@ -0,0 +1,66 @@ +use std::path::PathBuf; + +use clap::Subcommand; + +use crate::{CliConfig, CliParams}; + +#[derive(Subcommand)] +pub enum ConfigCommand { + /// Sets the index repository URL + SetIndexRepo { + #[clap(value_name = "URL")] + url: String, + }, + /// Gets the index repository URL + GetIndexRepo, + + /// Sets the cache directory + SetCacheDir { + #[clap(value_name = "DIRECTORY")] + directory: Option, + }, + /// Gets the cache directory + GetCacheDir, +} + +pub fn config_command(cmd: ConfigCommand, params: CliParams) -> anyhow::Result<()> { + match cmd { + ConfigCommand::SetIndexRepo { url } => { + let cli_config = CliConfig { + index_repo_url: url.clone(), + ..params.cli_config + }; + + cli_config.write(¶ms.directories)?; + + println!("index repository url set to: `{url}`"); + } + ConfigCommand::GetIndexRepo => { + println!( + "current index repository url: `{}`", + params.cli_config.index_repo_url + ); + } + ConfigCommand::SetCacheDir { directory } => { + let cli_config = CliConfig { + cache_dir: directory, + ..params.cli_config + }; + + cli_config.write(¶ms.directories)?; + + println!( + "cache directory set to: `{}`", + cli_config.cache_dir(¶ms.directories).display() + ); + } + ConfigCommand::GetCacheDir => { + println!( + "current cache directory: `{}`", + params.cli_config.cache_dir(¶ms.directories).display() + ); + } + } + + Ok(()) +} diff --git a/src/cli/mod.rs b/src/cli/mod.rs new file mode 100644 index 0000000..7a5ccd6 --- /dev/null +++ b/src/cli/mod.rs @@ -0,0 +1,3 @@ +pub mod auth; +pub mod config; +pub mod root; diff --git a/src/cli/root.rs b/src/cli/root.rs new file mode 100644 index 0000000..386cd41 --- /dev/null +++ b/src/cli/root.rs @@ -0,0 +1,281 @@ +use std::{ + fs::{create_dir_all, read, remove_dir_all, write}, + time::Duration, +}; + +use flate2::{write::GzEncoder, Compression}; +use futures_executor::block_on; +use ignore::{overrides::OverrideBuilder, WalkBuilder}; +use log::debug; +use lune::Runtime; +use reqwest::{header::AUTHORIZATION, Url}; +use semver::Version; +use serde_json::Value; +use tar::Builder as TarBuilder; + +use pesde::{ + dependencies::PackageRef, + index::{GitIndex, Index}, + manifest::Manifest, + package_name::PackageName, + patches::{create_patch, setup_patches_repo}, + project::{InstallOptions, Project}, + DEV_PACKAGES_FOLDER, IGNORED_FOLDERS, PACKAGES_FOLDER, PATCHES_FOLDER, SERVER_PACKAGES_FOLDER, +}; + +use crate::{send_request, CliParams, Command}; + +pub const MAX_ARCHIVE_SIZE: usize = 4 * 1024 * 1024; + +fn get_project(params: &CliParams) -> anyhow::Result> { + Project::from_path( + ¶ms.cwd, + params.cli_config.cache_dir(¶ms.directories), + params.index.clone(), + params.api_token_entry.get_password().ok(), + ) + .map_err(Into::into) +} + +pub fn root_command(cmd: Command, params: CliParams) -> anyhow::Result<()> { + match cmd { + Command::Install { locked } => { + let project = get_project(¶ms)?; + + for packages_folder in &[PACKAGES_FOLDER, DEV_PACKAGES_FOLDER, SERVER_PACKAGES_FOLDER] { + if let Err(e) = remove_dir_all(¶ms.cwd.join(packages_folder)) { + if e.kind() != std::io::ErrorKind::NotFound { + return Err(e.into()); + } else { + debug!("no {packages_folder} folder found, skipping removal"); + } + }; + } + + let resolved_versions_map = project.manifest().dependency_tree(&project, locked)?; + + let download_job = project.download(&resolved_versions_map)?; + let bar = params.multi.add( + indicatif::ProgressBar::new(resolved_versions_map.len() as u64) + .with_style(indicatif::ProgressStyle::default_bar().template( + "{msg} {bar:40.208/166} {pos}/{len} {percent}% {elapsed_precise}", + )?) + .with_message("Downloading packages"), + ); + bar.enable_steady_tick(Duration::from_millis(100)); + + while let Ok(result) = download_job.progress().recv() { + result?; + bar.inc(1); + } + + bar.finish_with_message("done"); + + project.install( + InstallOptions::new() + .locked(locked) + .auto_download(false) + .resolved_versions_map(resolved_versions_map), + )?; + } + Command::Run { package, args } => { + let project = get_project(¶ms)?; + + let name: PackageName = package.parse()?; + + let lockfile = project + .lockfile()? + .ok_or(anyhow::anyhow!("lockfile not found"))?; + + let (_, resolved_pkg) = lockfile + .get(&name) + .and_then(|versions| versions.iter().find(|(_, pkg_ref)| pkg_ref.is_root)) + .ok_or(anyhow::anyhow!("package not found in lockfile"))?; + + if !resolved_pkg.is_root { + anyhow::bail!("package is not a root package"); + } + + let pkg_path = resolved_pkg.directory(project.path()).1; + let manifest = Manifest::from_path(&pkg_path)?; + + let Some(bin_path) = manifest.exports.bin else { + anyhow::bail!("no bin found in package"); + }; + + let absolute_bin_path = bin_path.to_path(pkg_path); + + let mut runtime = Runtime::new().with_args(args); + + block_on(runtime.run( + resolved_pkg.pkg_ref.name().to_string(), + &read(absolute_bin_path)?, + ))?; + } + Command::Search { query } => { + let config = params.index.config()?; + let api_url = config.api(); + + let response = send_request!(params.reqwest_client.get(Url::parse_with_params( + &format!("{}/v0/search", api_url), + &query.map_or_else(Vec::new, |q| vec![("query", q)]) + )?)) + .json::()?; + + for package in response.as_array().unwrap() { + println!( + "{}@{}{}", + package["name"].as_str().unwrap(), + package["version"].as_str().unwrap(), + package["description"] + .as_str() + .map(|d| if d.is_empty() { + d.to_string() + } else { + format!("\n{}\n", d) + }) + .unwrap() + ); + } + } + Command::Publish => { + let project = get_project(¶ms)?; + + if project.manifest().private { + anyhow::bail!("package is private, cannot publish"); + } + + let encoder = GzEncoder::new(vec![], Compression::default()); + let mut archive = TarBuilder::new(encoder); + + let mut walk_builder = WalkBuilder::new(¶ms.cwd); + walk_builder.add_custom_ignore_filename(".pesdeignore"); + let mut overrides = OverrideBuilder::new(¶ms.cwd); + + for packages_folder in IGNORED_FOLDERS { + overrides.add(&format!("!{}", packages_folder))?; + } + + walk_builder.overrides(overrides.build()?); + + for entry in walk_builder.build() { + let entry = entry?; + let path = entry.path(); + let relative_path = path.strip_prefix(¶ms.cwd)?; + let entry_type = entry + .file_type() + .ok_or(anyhow::anyhow!("failed to get file type"))?; + + if relative_path.as_os_str().is_empty() { + continue; + } + + if entry_type.is_file() { + archive.append_path_with_name(path, relative_path)?; + } else if entry_type.is_dir() { + archive.append_dir(relative_path, path)?; + } + } + + let archive = archive.into_inner()?.finish()?; + + if archive.len() > MAX_ARCHIVE_SIZE { + anyhow::bail!( + "archive is too big ({} bytes), max {MAX_ARCHIVE_SIZE}. aborting...", + archive.len() + ); + } + + let part = reqwest::blocking::multipart::Part::bytes(archive) + .file_name("tarball.tar.gz") + .mime_str("application/gzip")?; + + let mut request = params + .reqwest_client + .post(format!("{}/v0/packages", project.index().config()?.api())) + .multipart(reqwest::blocking::multipart::Form::new().part("tarball", part)); + + if let Some(token) = project.registry_auth_token() { + request = request.header(AUTHORIZATION, format!("Bearer {token}")); + } else { + request = request.header(AUTHORIZATION, ""); + } + + println!("{}", send_request!(request).text()?); + } + Command::Patch { package } => { + let project = get_project(¶ms)?; + + let (name, version) = package + .split_once('@') + .ok_or(anyhow::anyhow!("Malformed package name"))?; + let name: PackageName = name.parse()?; + let version = Version::parse(version)?; + + let lockfile = project + .lockfile()? + .ok_or(anyhow::anyhow!("lockfile not found"))?; + + let resolved_pkg = lockfile + .get(&name) + .and_then(|versions| versions.get(&version)) + .ok_or(anyhow::anyhow!("package not found in lockfile"))?; + + let dir = params.directories.data_dir().join("patches").join(format!( + "{}_{}", + name.escaped(), + version + )); + + if dir.exists() { + anyhow::bail!( + "patch already exists. remove the directory {} to create a new patch", + dir.display() + ); + } + + create_dir_all(&dir)?; + + resolved_pkg.pkg_ref.download(&project, &dir)?; + match resolved_pkg.pkg_ref { + PackageRef::Git(_) => {} + _ => { + setup_patches_repo(&dir)?; + } + } + + println!("done! modify the files in {} and run `{} patch-commit ` to commit the changes", dir.display(), env!("CARGO_BIN_NAME")); + } + Command::PatchCommit { dir } => { + let project = get_project(¶ms)?; + + let manifest = Manifest::from_path(&dir)?; + let patch_path = project.path().join(PATCHES_FOLDER).join(format!( + "{}@{}.patch", + manifest.name.escaped(), + manifest.version + )); + + if patch_path.exists() { + anyhow::bail!( + "patch already exists. remove the file {} to create a new patch", + patch_path.display() + ); + } + + let patches = create_patch(&dir)?; + + write(&patch_path, patches)?; + + remove_dir_all(&dir)?; + + println!( + "done! to apply the patch, run `{} install`", + env!("CARGO_BIN_NAME") + ); + } + _ => unreachable!(), + } + + Ok(()) +} diff --git a/src/dependencies/git.rs b/src/dependencies/git.rs new file mode 100644 index 0000000..4415eea --- /dev/null +++ b/src/dependencies/git.rs @@ -0,0 +1,161 @@ +use std::{fs::create_dir_all, path::Path}; + +use git2::{build::RepoBuilder, Repository}; +use log::{debug, warn}; +use semver::Version; +use serde::{Deserialize, Serialize}; +use thiserror::Error; + +use crate::{ + index::{remote_callbacks, Index}, + manifest::{Manifest, ManifestReadError, Realm}, + package_name::PackageName, + project::Project, +}; + +/// A dependency of a package that can be downloaded from a git repository +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] +#[serde(deny_unknown_fields)] +pub struct GitDependencySpecifier { + /// The URL of the git repository (can be in the form of `owner/repo`, in which case it will default to GitHub) + pub repo: String, + /// The revision of the git repository to use + pub rev: String, + /// The realm of the package + pub realm: Option, +} + +/// A reference to a package that can be downloaded from a git repository +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] +#[serde(deny_unknown_fields)] +pub struct GitPackageRef { + /// The name of the package + pub name: PackageName, + /// The version of the package + pub version: Version, + /// The URL of the git repository + pub repo_url: String, + /// The revision of the git repository to use + pub rev: String, +} + +/// An error that occurred while downloading a git repository +#[derive(Debug, Error)] +pub enum GitDownloadError { + /// An error that occurred while interacting with git + #[error("error interacting with git")] + Git(#[from] git2::Error), + + /// An error that occurred while interacting with the file system + #[error("error interacting with the file system")] + Io(#[from] std::io::Error), + + /// An error that occurred while reading the manifest of the git repository + #[error("error reading manifest")] + ManifestRead(#[from] ManifestReadError), +} + +impl GitDependencySpecifier { + pub(crate) fn resolve( + &self, + project: &Project, + ) -> Result<(Manifest, String, String), GitDownloadError> { + debug!("resolving git dependency {}", self.repo); + + // should also work with ssh urls + let is_url = self.repo.contains(':'); + + let repo_name = { + if !is_url { + self.repo.to_string() + } else { + let parts: Vec<&str> = self.repo.split('/').collect(); + format!( + "{}/{}", + parts[parts.len() - 2], + parts[parts.len() - 1].trim_end_matches(".git") + ) + } + }; + + if is_url { + debug!("resolved git repository name to: {}", &repo_name); + } else { + debug!("assuming git repository is a name: {}", &repo_name); + } + + let repo_url = { + if !is_url { + format!("https://github.com/{}.git", &self.repo) + } else { + self.repo.to_string() + } + }; + + if is_url { + debug!("assuming git repository is a url: {}", &repo_url); + } else { + debug!("resolved git repository url to: {}", &repo_url); + } + + let dest = project + .cache_dir() + .join("git") + .join(repo_name.replace('/', "_")) + .join(&self.rev); + + let repo = if !dest.exists() { + create_dir_all(&dest)?; + + let mut fetch_options = git2::FetchOptions::new(); + fetch_options.remote_callbacks(remote_callbacks(project.index())); + + RepoBuilder::new() + .fetch_options(fetch_options) + .clone(&repo_url, &dest)? + } else { + Repository::open(&dest)? + }; + + let obj = repo.revparse_single(&self.rev)?; + debug!("resolved git revision {} to: {}", self.rev, obj.id()); + + repo.reset(&obj, git2::ResetType::Hard, None)?; + + Ok(( + Manifest::from_path(dest)?, + repo_url.to_string(), + obj.id().to_string(), + )) + } +} + +impl GitPackageRef { + /// Downloads the package to the specified destination + pub fn download, I: Index>( + &self, + project: &Project, + dest: P, + ) -> Result<(), GitDownloadError> { + let mut fetch_options = git2::FetchOptions::new(); + fetch_options.remote_callbacks(remote_callbacks(project.index())); + + let repo = RepoBuilder::new() + .fetch_options(fetch_options) + .clone(&self.repo_url, dest.as_ref())?; + + let obj = repo.revparse_single(&self.rev)?; + + if self.rev != obj.id().to_string() { + warn!( + "git package ref {} resolved to a different revision: {}. this shouldn't happen", + self.rev, + obj.id() + ); + } + + repo.reset(&obj, git2::ResetType::Hard, None)?; + + Ok(()) + } +} diff --git a/src/dependencies/mod.rs b/src/dependencies/mod.rs new file mode 100644 index 0000000..5adc5cb --- /dev/null +++ b/src/dependencies/mod.rs @@ -0,0 +1,182 @@ +use log::debug; +use std::{fmt::Display, fs::create_dir_all, path::Path}; + +use semver::Version; +use serde::{de::IntoDeserializer, Deserialize, Deserializer, Serialize}; +use thiserror::Error; + +use crate::{ + dependencies::{ + git::{GitDependencySpecifier, GitPackageRef}, + registry::{RegistryDependencySpecifier, RegistryPackageRef}, + resolution::ResolvedVersionsMap, + }, + index::Index, + manifest::Realm, + multithread::MultithreadedJob, + package_name::PackageName, + project::{InstallProjectError, Project}, +}; + +/// Git dependency related stuff +pub mod git; +/// Registry dependency related stuff +pub mod registry; +/// Resolution +pub mod resolution; + +// To improve developer experience, we resolve the type of the dependency specifier with a custom deserializer, so that the user doesn't have to specify the type of the dependency +/// A dependency of a package +#[derive(Serialize, Debug, Clone, PartialEq, Eq, Hash)] +#[serde(untagged)] +pub enum DependencySpecifier { + /// A dependency that can be downloaded from a registry + Registry(RegistryDependencySpecifier), + /// A dependency that can be downloaded from a git repository + Git(GitDependencySpecifier), +} + +impl DependencySpecifier { + /// Gets the name (or repository) of the specifier + pub fn name(&self) -> String { + match self { + DependencySpecifier::Registry(registry) => registry.name.to_string(), + DependencySpecifier::Git(git) => git.repo.to_string(), + } + } + + /// Gets the version (or revision) of the specifier + pub fn version(&self) -> String { + match self { + DependencySpecifier::Registry(registry) => registry.version.to_string(), + DependencySpecifier::Git(git) => git.rev.clone(), + } + } + + /// Gets the realm of the specifier + pub fn realm(&self) -> Option<&Realm> { + match self { + DependencySpecifier::Registry(registry) => registry.realm.as_ref(), + DependencySpecifier::Git(git) => git.realm.as_ref(), + } + } +} + +impl<'de> Deserialize<'de> for DependencySpecifier { + fn deserialize>(deserializer: D) -> Result { + let yaml = serde_yaml::Value::deserialize(deserializer)?; + + let result = if yaml.get("repo").is_some() { + GitDependencySpecifier::deserialize(yaml.into_deserializer()) + .map(DependencySpecifier::Git) + } else if yaml.get("name").is_some() { + RegistryDependencySpecifier::deserialize(yaml.into_deserializer()) + .map(DependencySpecifier::Registry) + } else { + Err(serde::de::Error::custom("invalid dependency")) + }; + + result.map_err(|e| serde::de::Error::custom(e.to_string())) + } +} + +// Here we don't use a custom deserializer, because this is exposed to the user only from the lock file, which mustn't be edited manually anyway +/// A reference to a package +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] +#[serde(rename_all = "snake_case", tag = "type")] +pub enum PackageRef { + /// A reference to a package that can be downloaded from a registry + Registry(RegistryPackageRef), + /// A reference to a package that can be downloaded from a git repository + Git(GitPackageRef), +} + +/// An error that occurred while downloading a package +#[derive(Debug, Error)] +pub enum DownloadError { + /// An error that occurred while downloading a package from a registry + #[error("error downloading package {1} from registry")] + Registry(#[source] registry::RegistryDownloadError, Box), + + /// An error that occurred while downloading a package from a git repository + #[error("error downloading package {1} from git repository")] + Git(#[source] git::GitDownloadError, Box), +} + +impl PackageRef { + /// Gets the name of the package + pub fn name(&self) -> &PackageName { + match self { + PackageRef::Registry(registry) => ®istry.name, + PackageRef::Git(git) => &git.name, + } + } + + /// Gets the version of the package + pub fn version(&self) -> &Version { + match self { + PackageRef::Registry(registry) => ®istry.version, + PackageRef::Git(git) => &git.version, + } + } + + /// Downloads the package to the specified destination + pub fn download, I: Index>( + &self, + project: &Project, + dest: P, + ) -> Result<(), DownloadError> { + match self { + PackageRef::Registry(registry) => registry + .download(project, dest) + .map_err(|e| DownloadError::Registry(e, Box::new(self.clone()))), + PackageRef::Git(git) => git + .download(project, dest) + .map_err(|e| DownloadError::Git(e, Box::new(self.clone()))), + } + } +} + +impl Project { + /// Downloads the project's dependencies + pub fn download( + &self, + map: &ResolvedVersionsMap, + ) -> Result, InstallProjectError> { + let (job, tx) = MultithreadedJob::new(); + + for (name, versions) in map.clone() { + for (version, resolved_package) in versions { + let (_, source) = resolved_package.directory(self.path()); + + if source.exists() { + debug!("package {name}@{version} already downloaded, skipping..."); + continue; + } + + debug!( + "downloading package {name}@{version} to {}", + source.display() + ); + + create_dir_all(&source)?; + + let project = self.clone(); + let tx = tx.clone(); + + job.pool.execute(move || { + let result = resolved_package.pkg_ref.download(&project, source); + tx.send(result).unwrap(); + }); + } + } + + Ok(job) + } +} + +impl Display for PackageRef { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}@{}", self.name(), self.version()) + } +} diff --git a/src/dependencies/registry.rs b/src/dependencies/registry.rs new file mode 100644 index 0000000..7dbb323 --- /dev/null +++ b/src/dependencies/registry.rs @@ -0,0 +1,125 @@ +use std::path::Path; + +use log::{debug, error}; +use reqwest::header::{AUTHORIZATION, USER_AGENT as USER_AGENT_HEADER}; +use semver::{Version, VersionReq}; +use serde::{Deserialize, Serialize}; +use thiserror::Error; + +use crate::{ + index::Index, manifest::Realm, package_name::PackageName, project::Project, USER_AGENT, +}; + +/// A dependency of a package that can be downloaded from a registry +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] +#[serde(deny_unknown_fields)] +pub struct RegistryDependencySpecifier { + /// The name of the package + pub name: PackageName, + /// The version requirement of the package + pub version: VersionReq, + // TODO: support per-package registries + // #[serde(skip_serializing_if = "Option::is_none")] + // pub registry: Option, + /// The realm of the package + pub realm: Option, +} + +/// A reference to a package that can be downloaded from a registry +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] +#[serde(deny_unknown_fields)] +pub struct RegistryPackageRef { + /// The name of the package + pub name: PackageName, + /// The version of the package + pub version: Version, + // TODO: support per-package registries + // #[serde(skip_serializing_if = "Option::is_none")] + // pub index_url: Option, +} + +/// An error that occurred while downloading a package from a registry +#[derive(Debug, Error)] +pub enum RegistryDownloadError { + /// An error that occurred while interacting with reqwest + #[error("error interacting with reqwest")] + Reqwest(#[from] reqwest::Error), + + /// An error that occurred while interacting with the file system + #[error("error interacting with the file system")] + Io(#[from] std::io::Error), + + /// An error that occurred while reading the index config + #[error("error with the index config")] + IndexConfig(#[from] crate::index::ConfigError), + + /// The package was not found on the registry + #[error("package {0} not found on the registry, but found in the index")] + NotFound(PackageName), + + /// The user is unauthorized to download the package + #[error("unauthorized to download package {0}")] + Unauthorized(PackageName), + + /// An HTTP error occurred + #[error("http error {0}: the server responded with {1}")] + Http(reqwest::StatusCode, String), +} + +impl RegistryPackageRef { + /// Downloads the package to the specified destination + pub fn download, I: Index>( + &self, + project: &Project, + dest: P, + ) -> Result<(), RegistryDownloadError> { + let url = project + .index() + .config()? + .download() + .replace("{PACKAGE_AUTHOR}", self.name.scope()) + .replace("{PACKAGE_NAME}", self.name.name()) + .replace("{PACKAGE_VERSION}", &self.version.to_string()); + + debug!( + "downloading registry package {}@{} from {}", + self.name, self.version, url + ); + + let client = reqwest::blocking::Client::new(); + let response = { + let mut builder = client.get(&url).header(USER_AGENT_HEADER, USER_AGENT); + if let Some(token) = project.registry_auth_token() { + let visible_tokens = token.chars().take(8).collect::(); + let hidden_tokens = "*".repeat(token.len() - 8); + debug!("using registry token {visible_tokens}{hidden_tokens}"); + builder = builder.header(AUTHORIZATION, format!("Bearer {}", token)); + } + builder.send()? + }; + + if !response.status().is_success() { + return match response.status() { + reqwest::StatusCode::NOT_FOUND => { + Err(RegistryDownloadError::NotFound(self.name.clone())) + } + reqwest::StatusCode::UNAUTHORIZED => { + Err(RegistryDownloadError::Unauthorized(self.name.clone())) + } + _ => Err(RegistryDownloadError::Http( + response.status(), + response.text()?, + )), + }; + } + + let bytes = response.bytes()?; + + let mut decoder = flate2::read::GzDecoder::new(bytes.as_ref()); + let mut archive = tar::Archive::new(&mut decoder); + + archive.unpack(&dest)?; + + Ok(()) + } +} diff --git a/src/dependencies/resolution.rs b/src/dependencies/resolution.rs new file mode 100644 index 0000000..92ab2d4 --- /dev/null +++ b/src/dependencies/resolution.rs @@ -0,0 +1,442 @@ +use std::{ + collections::{BTreeMap, BTreeSet, VecDeque}, + fmt::Display, + path::{Path, PathBuf}, +}; + +use log::debug; +use semver::Version; +use serde::{Deserialize, Serialize}; +use thiserror::Error; + +use crate::{ + dependencies::{ + git::{GitDownloadError, GitPackageRef}, + registry::{RegistryDependencySpecifier, RegistryPackageRef}, + DependencySpecifier, PackageRef, + }, + index::{Index, IndexPackageError}, + manifest::{DependencyType, Manifest, Realm}, + package_name::PackageName, + project::{Project, ReadLockfileError}, + DEV_PACKAGES_FOLDER, INDEX_FOLDER, PACKAGES_FOLDER, SERVER_PACKAGES_FOLDER, +}; + +/// A node in the dependency tree +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] +#[serde(deny_unknown_fields)] +pub struct ResolvedPackage { + /// The reference to the package + pub pkg_ref: PackageRef, + /// The specifier that resolved to this package + pub specifier: DependencySpecifier, + /// The dependencies of the package + #[serde(default, skip_serializing_if = "BTreeSet::is_empty")] + pub dependencies: BTreeSet<(PackageName, Version)>, + /// Whether the package is a root package (top-level dependency) + pub is_root: bool, + /// The realm of the package + pub realm: Realm, + /// The type of the dependency + pub dep_type: DependencyType, +} + +impl Display for ResolvedPackage { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.pkg_ref) + } +} + +pub(crate) fn packages_folder(realm: &Realm) -> &str { + match realm { + Realm::Shared => PACKAGES_FOLDER, + Realm::Server => SERVER_PACKAGES_FOLDER, + Realm::Development => DEV_PACKAGES_FOLDER, + } +} + +impl ResolvedPackage { + pub(crate) fn packages_folder(&self) -> &str { + packages_folder(&self.realm) + } + + /// Returns the directory of the package in the project, and the parent of the directory + pub fn directory>(&self, project_path: P) -> (PathBuf, PathBuf) { + let name = self.pkg_ref.name().escaped(); + let container_path = project_path + .as_ref() + .join(self.packages_folder()) + .join(INDEX_FOLDER) + .join(&name) + .join(self.pkg_ref.version().to_string()); + + (container_path.clone(), container_path.join(&name)) + } +} + +/// A flat resolved map, a map of package names to versions to resolved packages +pub type ResolvedVersionsMap = BTreeMap>; + +macro_rules! find_highest { + ($iter:expr, $dep:expr) => { + $iter + .filter(|v| $dep.version.matches(v)) + .max_by(|a, b| a.cmp(&b)) + .cloned() + }; +} + +fn find_realm(a: &Realm, b: &Realm) -> Realm { + if a == b { + return *a; + } + + Realm::Shared +} + +fn add_to_map( + map: &mut ResolvedVersionsMap, + name: &PackageName, + version: &Version, + resolved_package: &ResolvedPackage, + lockfile: &ResolvedVersionsMap, + depth: usize, +) -> Result<(), ResolveError> { + debug!( + "{}resolved {resolved_package} from lockfile", + "\t".repeat(depth) + ); + + map.entry(name.clone()) + .or_default() + .insert(version.clone(), resolved_package.clone()); + + for (dep_name, dep_version) in &resolved_package.dependencies { + if map.get(dep_name).and_then(|v| v.get(dep_version)).is_none() { + let dep = lockfile.get(dep_name).and_then(|v| v.get(dep_version)); + + match dep { + Some(dep) => add_to_map(map, dep_name, dep_version, dep, lockfile, depth + 1)?, + // the lockfile is malformed + None => return Err(ResolveError::OutOfDateLockfile), + } + } + } + + Ok(()) +} + +/// An error that occurred while resolving dependencies +#[derive(Debug, Error)] +pub enum ResolveError { + /// An error that occurred while interacting with the file system + #[error("error interacting with the file system")] + Io(#[from] std::io::Error), + + /// An error that occurred because a registry dependency conflicts with a git dependency + #[error("registry dependency {0}@{1} conflicts with git dependency")] + RegistryConflict(PackageName, Version), + + /// An error that occurred because a git dependency conflicts with a registry dependency + #[error("git dependency {0}@{1} conflicts with registry dependency")] + GitConflict(PackageName, Version), + + /// An error that occurred because no satisfying version was found for a dependency + #[error("no satisfying version found for dependency {0:?}")] + NoSatisfyingVersion(RegistryDependencySpecifier), + + /// An error that occurred while downloading a package from a git repository + #[error("error downloading git package")] + GitDownload(#[from] GitDownloadError), + + /// An error that occurred because a package was not found in the index + #[error("package {0} not found in index")] + PackageNotFound(PackageName), + + /// An error that occurred while getting a package from the index + #[error("failed to get package {1} from index")] + IndexPackage(#[source] IndexPackageError, PackageName), + + /// An error that occurred while reading the lockfile + #[error("failed to read lockfile")] + LockfileRead(#[from] ReadLockfileError), + + /// An error that occurred because the lockfile is out of date + #[error("out of date lockfile")] + OutOfDateLockfile, + + /// An error that occurred because two realms are incompatible + #[error("incompatible realms for package {0} (package specified {1}, user specified {2})")] + IncompatibleRealms(PackageName, Realm, Realm), + + /// An error that occurred because a peer dependency is not installed + #[error("peer dependency {0}@{1} is not installed")] + PeerNotInstalled(PackageName, Version), +} + +impl Manifest { + /// Resolves the dependency tree for the project + pub fn dependency_tree( + &self, + project: &Project, + locked: bool, + ) -> Result { + debug!("resolving dependency tree for project {}", self.name); + // try to reuse versions (according to semver specifiers) to decrease the amount of downloads and storage + let mut resolved_versions_map: ResolvedVersionsMap = BTreeMap::new(); + + let tree = if let Some(lockfile) = project.lockfile()? { + debug!("lockfile found, resolving dependencies from it"); + let mut missing = Vec::new(); + + // resolve all root dependencies (and their dependencies) from the lockfile + for (name, versions) in &lockfile { + for (version, resolved_package) in versions { + if !resolved_package.is_root + || !self + .dependencies() + .into_iter() + .any(|(spec, _)| spec == resolved_package.specifier) + { + continue; + } + + add_to_map( + &mut resolved_versions_map, + name, + version, + resolved_package, + &lockfile, + 1, + )?; + } + } + + // resolve new, or modified, dependencies from the lockfile + 'outer: for (dep, dep_type) in self.dependencies() { + for versions in resolved_versions_map.values() { + for resolved_package in versions.values() { + if resolved_package.specifier == dep && resolved_package.is_root { + continue 'outer; + } + } + } + + if locked { + return Err(ResolveError::OutOfDateLockfile); + } + + missing.push((dep.clone(), dep_type)); + } + + debug!( + "resolved {} dependencies from lockfile. new dependencies: {}", + resolved_versions_map.len(), + missing.len() + ); + + missing + } else { + debug!("no lockfile found, resolving all dependencies"); + self.dependencies() + }; + + if tree.is_empty() { + debug!("no dependencies left to resolve, finishing..."); + return Ok(resolved_versions_map); + } + + debug!("resolving {} dependencies from index", tree.len()); + + let mut queue = VecDeque::from_iter(self.dependencies().into_iter().map(|d| (d, None))); + + while let Some(((specifier, dep_type), dependant)) = queue.pop_front() { + let (pkg_ref, default_realm, dependencies) = match &specifier { + DependencySpecifier::Registry(registry_dependency) => { + let index_entries = project + .index() + .package(®istry_dependency.name) + .map_err(|e| { + ResolveError::IndexPackage(e, registry_dependency.name.clone()) + })? + .ok_or_else(|| { + ResolveError::PackageNotFound(registry_dependency.name.clone()) + })?; + + let resolved_versions = resolved_versions_map + .entry(registry_dependency.name.clone()) + .or_default(); + + // try to find the highest already downloaded version that satisfies the requirement, otherwise find the highest satisfying version in the index + let Some(version) = + find_highest!(resolved_versions.keys(), registry_dependency).or_else( + || { + find_highest!( + index_entries.iter().map(|v| &v.version), + registry_dependency + ) + }, + ) + else { + return Err(ResolveError::NoSatisfyingVersion( + registry_dependency.clone(), + )); + }; + + let entry = index_entries + .into_iter() + .find(|e| e.version.eq(&version)) + .unwrap(); + + debug!( + "resolved registry dependency {} to {}", + registry_dependency.name, version + ); + + ( + PackageRef::Registry(RegistryPackageRef { + name: registry_dependency.name.clone(), + version: version.clone(), + }), + entry.realm, + entry.dependencies, + ) + } + DependencySpecifier::Git(git_dependency) => { + let (manifest, url, rev) = git_dependency.resolve(project)?; + + debug!( + "resolved git dependency {} to {url}#{rev}", + git_dependency.repo + ); + + ( + PackageRef::Git(GitPackageRef { + name: manifest.name.clone(), + version: manifest.version.clone(), + repo_url: url, + rev, + }), + manifest.realm, + manifest.dependencies(), + ) + } + }; + + let is_root = dependant.is_none(); + // if the dependency is a root dependency, it can be thought of as a normal dependency + let dep_type = if is_root { + DependencyType::Normal + } else { + dep_type + }; + + if let Some((dependant_name, dependant_version)) = dependant { + resolved_versions_map + .get_mut(&dependant_name) + .and_then(|v| v.get_mut(&dependant_version)) + .unwrap() + .dependencies + .insert((pkg_ref.name().clone(), pkg_ref.version().clone())); + } + + let resolved_versions = resolved_versions_map + .entry(pkg_ref.name().clone()) + .or_default(); + + if let Some(previously_resolved) = resolved_versions.get_mut(pkg_ref.version()) { + match (&pkg_ref, &previously_resolved.pkg_ref) { + (PackageRef::Registry(r), PackageRef::Git(_g)) => { + return Err(ResolveError::RegistryConflict( + r.name.clone(), + r.version.clone(), + )); + } + (PackageRef::Git(g), PackageRef::Registry(_r)) => { + return Err(ResolveError::GitConflict(g.name.clone(), g.version.clone())); + } + _ => (), + } + + if previously_resolved.dep_type == DependencyType::Peer + && dep_type == DependencyType::Normal + { + previously_resolved.dep_type = dep_type; + } + + // need not resolve the package again + continue; + } + + if specifier + .realm() + .is_some_and(|realm| realm == &Realm::Shared) + && default_realm.is_some_and(|realm| realm == Realm::Server) + { + return Err(ResolveError::IncompatibleRealms( + pkg_ref.name().clone(), + default_realm.unwrap(), + *specifier.realm().unwrap(), + )); + } + + resolved_versions.insert( + pkg_ref.version().clone(), + ResolvedPackage { + pkg_ref: pkg_ref.clone(), + specifier: specifier.clone(), + dependencies: BTreeSet::new(), + is_root, + realm: *specifier + .realm() + .copied() + .unwrap_or_default() + .or(&default_realm.unwrap_or_default()), + dep_type, + }, + ); + + for dependency in dependencies { + queue.push_back(( + dependency, + Some((pkg_ref.name().clone(), pkg_ref.version().clone())), + )); + } + } + + debug!("resolving realms and peer dependencies..."); + + for (name, versions) in resolved_versions_map.clone() { + for (version, resolved_package) in versions { + if resolved_package.dep_type == DependencyType::Peer { + return Err(ResolveError::PeerNotInstalled( + resolved_package.pkg_ref.name().clone(), + resolved_package.pkg_ref.version().clone(), + )); + } + + let mut realm = resolved_package.realm; + + for (dep_name, dep_version) in &resolved_package.dependencies { + let dep = resolved_versions_map + .get(dep_name) + .and_then(|v| v.get(dep_version)); + + if let Some(dep) = dep { + realm = find_realm(&realm, &dep.realm); + } + } + + resolved_versions_map + .get_mut(&name) + .and_then(|v| v.get_mut(&version)) + .unwrap() + .realm = realm; + } + } + + debug!("finished resolving dependency tree"); + + Ok(resolved_versions_map) + } +} diff --git a/src/index.rs b/src/index.rs new file mode 100644 index 0000000..efbf9af --- /dev/null +++ b/src/index.rs @@ -0,0 +1,558 @@ +use std::{ + collections::BTreeSet, + fmt::Debug, + fs::create_dir_all, + hash::Hash, + path::{Path, PathBuf}, + sync::Arc, +}; + +use git2::{build::RepoBuilder, Remote, Repository, Signature}; +use log::debug; +use semver::Version; +use serde::{Deserialize, Serialize}; +use thiserror::Error; + +use crate::{ + dependencies::DependencySpecifier, + manifest::{DependencyType, Manifest, Realm}, + package_name::PackageName, +}; + +/// Owners of a scope +pub type ScopeOwners = BTreeSet; + +/// A packages index +pub trait Index: Send + Sync + Debug + Clone + 'static { + /// Gets the owners of a scope + fn scope_owners(&self, scope: &str) -> Result, ScopeOwnersError>; + + /// Creates a scope + fn create_scope_for( + &mut self, + scope: &str, + owners: &ScopeOwners, + ) -> Result; + + /// Gets a package from the index + fn package(&self, name: &PackageName) -> Result, IndexPackageError>; + + /// Creates a package version + fn create_package_version( + &mut self, + manifest: &Manifest, + uploader: &u64, + ) -> Result; + + /// Gets the index's configuration + fn config(&self) -> Result; + + /// Returns a function that gets the credentials for a git repository + fn credentials_fn(&self) -> Option<&Arc>; +} + +/// A function that gets the credentials for a git repository +pub type CredentialsFn = Box< + dyn Fn() -> Box< + dyn FnMut(&str, Option<&str>, git2::CredentialType) -> Result, + > + Send + + Sync, +>; + +/// The packages index +#[derive(Clone)] +pub struct GitIndex { + path: PathBuf, + repo_url: String, + pub(crate) credentials_fn: Option>, +} + +impl Debug for GitIndex { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("GitIndex") + .field("path", &self.path) + .field("repo_url", &self.repo_url) + .finish() + } +} + +impl Hash for GitIndex { + fn hash(&self, state: &mut H) { + self.path.hash(state); + self.repo_url.hash(state); + } +} + +impl PartialEq for GitIndex { + fn eq(&self, other: &Self) -> bool { + self.path == other.path && self.repo_url == other.repo_url + } +} + +impl Eq for GitIndex {} + +/// An error that occurred while getting the index's refspec +#[derive(Debug, Error)] +pub enum GetRefSpecError { + /// An error that occurred while interacting with git + #[error("error interacting with git")] + Git(#[from] git2::Error), + + /// The refspec for the upstream branch was not found + #[error("refspec not found for upstream branch {0}")] + RefSpecNotFound(String), + + /// The refspec is not utf-8 + #[error("refspec not utf-8")] + RefSpecNotUtf8, + + /// The upstream branch was not found + #[error("upstream branch not found")] + UpstreamBranchNotFound, + + /// The upstream branch is not utf-8 + #[error("upstream branch not utf-8")] + UpstreamBranchNotUtf8, +} + +/// An error that occurred while refreshing the index +#[derive(Debug, Error)] +pub enum RefreshError { + /// An error that occurred while interacting with git + #[error("error interacting with git")] + Git(#[from] git2::Error), + + /// An error that occurred while interacting with the file system + #[error("error interacting with the file system")] + Io(#[from] std::io::Error), + + /// An error that occurred while getting the index's refspec + #[error("error getting refspec")] + GetRefSpec(#[from] GetRefSpecError), +} + +/// An error that occurred while interacting with the scope owners +#[derive(Debug, Error)] +pub enum ScopeOwnersError { + /// An error that occurred while interacting with the file system + #[error("error interacting with the file system")] + Io(#[from] std::io::Error), + + /// An error that occurred while deserializing the scope owners + #[error("error deserializing scope owners")] + ScopeOwnersDeser(#[source] serde_yaml::Error), + + /// An error that occurred while committing and pushing to the index + #[error("error committing and pushing to the index")] + CommitAndPush(#[from] CommitAndPushError), +} + +/// An error that occurred while committing and pushing to the index +#[derive(Debug, Error)] +pub enum CommitAndPushError { + /// An error that occurred while interacting with git + #[error("error interacting with git")] + Git(#[from] git2::Error), + + /// An error that occurred while interacting with the file system + #[error("error interacting with the file system")] + Io(#[from] std::io::Error), + + /// An error that occurred while getting the index's refspec + #[error("error getting refspec")] + GetRefSpec(#[from] GetRefSpecError), +} + +/// An error that occurred while getting a package from the index +#[derive(Debug, Error)] +pub enum IndexPackageError { + /// An error that occurred while interacting with the file system + #[error("error interacting with the file system")] + Io(#[from] std::io::Error), + + /// An error that occurred while deserializing the index file + #[error("error deserializing index file")] + FileDeser(#[source] serde_yaml::Error), +} + +/// An error that occurred while creating a package version +#[derive(Debug, Error)] +pub enum CreatePackageVersionError { + /// An error that occurred while interacting with the file system + #[error("error interacting with the file system")] + Io(#[from] std::io::Error), + + /// An error that occurred while getting a package from the index + #[error("error getting a package from the index")] + IndexPackage(#[from] IndexPackageError), + + /// An error that occurred while serializing the index file + #[error("error serializing index file")] + FileSer(#[source] serde_yaml::Error), + + /// An error that occurred while committing and pushing to the index + #[error("error committing and pushing to the index")] + CommitAndPush(#[from] CommitAndPushError), + + /// An error that occurred while interacting with the scope owners + #[error("error interacting with the scope owners")] + ScopeOwners(#[from] ScopeOwnersError), + + /// The scope is missing ownership + #[error("missing scope ownership")] + MissingScopeOwnership, +} + +/// An error that occurred while getting the index's configuration +#[derive(Debug, Error)] +pub enum ConfigError { + /// An error that occurred while interacting with the file system + #[error("error interacting with the file system")] + Io(#[from] std::io::Error), + + /// An error that occurred while deserializing the index config + #[error("error deserializing index config")] + ConfigDeser(#[source] serde_yaml::Error), + + /// The index does not have a config file + #[error("index does not have a config file - this is an issue with the index, please contact the maintainer of the index")] + MissingConfig, +} + +fn get_refspec( + repo: &Repository, + remote: &mut Remote, +) -> Result<(String, String), GetRefSpecError> { + let upstream_branch_buf = repo.branch_upstream_name( + repo.head()? + .name() + .ok_or(GetRefSpecError::UpstreamBranchNotFound)?, + )?; + let upstream_branch = upstream_branch_buf + .as_str() + .ok_or(GetRefSpecError::UpstreamBranchNotUtf8)?; + + let refspec_buf = remote + .refspecs() + .find(|r| r.direction() == git2::Direction::Fetch && r.dst_matches(upstream_branch)) + .ok_or(GetRefSpecError::RefSpecNotFound( + upstream_branch.to_string(), + ))? + .rtransform(upstream_branch)?; + let refspec = refspec_buf + .as_str() + .ok_or(GetRefSpecError::RefSpecNotUtf8)?; + + Ok((refspec.to_string(), upstream_branch.to_string())) +} + +pub(crate) fn remote_callbacks(index: &I) -> git2::RemoteCallbacks { + let mut remote_callbacks = git2::RemoteCallbacks::new(); + + if let Some(credentials) = &index.credentials_fn() { + let credentials = std::sync::Arc::clone(credentials); + + remote_callbacks.credentials(move |a, b, c| credentials()(a, b, c)); + } + + remote_callbacks +} + +impl GitIndex { + /// Creates a new git index. The `refresh` method must be called before using the index, preferably immediately after creating it. + pub fn new>( + path: P, + repo_url: &str, + credentials: Option, + ) -> Self { + Self { + path: path.as_ref().to_path_buf(), + repo_url: repo_url.to_string(), + credentials_fn: credentials.map(Arc::new), + } + } + + /// Gets the path of the index + pub fn path(&self) -> &Path { + &self.path + } + + /// Gets the URL of the index's repository + pub fn repo_url(&self) -> &str { + &self.repo_url + } + + /// Refreshes the index + pub fn refresh(&self) -> Result<(), RefreshError> { + let repo = if self.path.exists() { + Repository::open(&self.path).ok() + } else { + None + }; + + if let Some(repo) = repo { + let mut remote = repo.find_remote("origin")?; + let (refspec, upstream_branch) = get_refspec(&repo, &mut remote)?; + + remote.fetch( + &[&refspec], + Some(git2::FetchOptions::new().remote_callbacks(remote_callbacks(self))), + None, + )?; + + let commit = repo.find_reference(&upstream_branch)?.peel_to_commit()?; + + debug!( + "refreshing index, fetching {refspec}#{} from origin", + commit.id().to_string() + ); + + repo.reset(&commit.into_object(), git2::ResetType::Hard, None)?; + + Ok(()) + } else { + debug!( + "refreshing index - first time, cloning {} into {}", + self.repo_url, + self.path.display() + ); + create_dir_all(&self.path)?; + + let mut fetch_options = git2::FetchOptions::new(); + fetch_options.remote_callbacks(remote_callbacks(self)); + + RepoBuilder::new() + .fetch_options(fetch_options) + .clone(&self.repo_url, &self.path)?; + + Ok(()) + } + } + + /// Commits and pushes to the index + pub fn commit_and_push( + &self, + message: &str, + signature: &Signature, + ) -> Result<(), CommitAndPushError> { + let repo = Repository::open(&self.path)?; + + let mut index = repo.index()?; + index.add_all(["*"].iter(), git2::IndexAddOption::DEFAULT, None)?; + index.write()?; + + let oid = index.write_tree()?; + let tree = repo.find_tree(oid)?; + + let parent_commit = repo.head()?.peel_to_commit()?; + + repo.commit( + Some("HEAD"), + signature, + signature, + message, + &tree, + &[&parent_commit], + )?; + + let mut remote = repo.find_remote("origin")?; + + let (refspec, _) = get_refspec(&repo, &mut remote)?; + + remote.push( + &[&refspec], + Some(git2::PushOptions::new().remote_callbacks(remote_callbacks(self))), + )?; + + Ok(()) + } +} + +impl Index for GitIndex { + fn scope_owners(&self, scope: &str) -> Result, ScopeOwnersError> { + let path = self.path.join(scope).join("owners.yaml"); + + if !path.exists() { + return Ok(None); + } + + let contents = std::fs::read(&path)?; + let owners: ScopeOwners = + serde_yaml::from_slice(&contents).map_err(ScopeOwnersError::ScopeOwnersDeser)?; + + Ok(Some(owners)) + } + + fn create_scope_for( + &mut self, + scope: &str, + owners: &ScopeOwners, + ) -> Result { + let path = self.path.join(scope); + + if path.exists() { + return Ok(false); + } + + create_dir_all(&path)?; + + serde_yaml::to_writer(std::fs::File::create(path.join("owners.yaml"))?, owners) + .map_err(ScopeOwnersError::ScopeOwnersDeser)?; + + Ok(true) + } + + fn package(&self, name: &PackageName) -> Result, IndexPackageError> { + let path = self.path.join(name.scope()).join(name.name()); + + if !path.exists() { + return Ok(None); + } + + let contents = std::fs::read(&path)?; + let file: IndexFile = + serde_yaml::from_slice(&contents).map_err(IndexPackageError::FileDeser)?; + + Ok(Some(file)) + } + + fn create_package_version( + &mut self, + manifest: &Manifest, + uploader: &u64, + ) -> Result { + let scope = manifest.name.scope(); + + if let Some(owners) = self.scope_owners(scope)? { + if !owners.contains(uploader) { + return Err(CreatePackageVersionError::MissingScopeOwnership); + } + } else if !self.create_scope_for(scope, &BTreeSet::from([*uploader]))? { + return Err(CreatePackageVersionError::MissingScopeOwnership); + } + + let path = self.path.join(scope); + + let mut file = if let Some(file) = self.package(&manifest.name)? { + if file.iter().any(|e| e.version == manifest.version) { + return Ok(false); + } + file + } else { + vec![] + }; + + file.push(manifest.clone().into()); + + serde_yaml::to_writer( + std::fs::File::create(path.join(manifest.name.name()))?, + &file, + ) + .map_err(CreatePackageVersionError::FileSer)?; + + Ok(true) + } + + fn config(&self) -> Result { + let path = self.path.join("config.yaml"); + + if !path.exists() { + return Err(ConfigError::MissingConfig); + } + + let contents = std::fs::read(&path)?; + let config: IndexConfig = + serde_yaml::from_slice(&contents).map_err(ConfigError::ConfigDeser)?; + + Ok(config) + } + + fn credentials_fn(&self) -> Option<&Arc> { + self.credentials_fn.as_ref() + } +} + +/// The configuration of the index +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(deny_unknown_fields)] +pub struct IndexConfig { + /// The URL of the index's API + pub api: String, + /// The URL of the index's download API, defaults to `{API_URL}/v0/packages/{PACKAGE_AUTHOR}/{PACKAGE_NAME}/{PACKAGE_VERSION}`. + /// Has the following variables: + /// - `{API_URL}`: The URL of the index's API + /// - `{PACKAGE_AUTHOR}`: The author of the package + /// - `{PACKAGE_NAME}`: The name of the package + /// - `{PACKAGE_VERSION}`: The version of the package + pub download: Option, + /// Whether to allow git dependencies + #[serde(default)] + pub git_allowed: bool, + /// Whether to allow custom registries + #[serde(default)] + pub custom_registry_allowed: bool, + /// The OAuth client ID for GitHub OAuth + pub github_oauth_client_id: String, +} + +impl IndexConfig { + /// Gets the URL of the index's API + pub fn api(&self) -> &str { + self.api.strip_suffix('/').unwrap_or(&self.api) + } + + /// Gets the URL of the index's download API + pub fn download(&self) -> String { + self.download + .as_ref() + .unwrap_or( + &"{API_URL}/v0/packages/{PACKAGE_AUTHOR}/{PACKAGE_NAME}/{PACKAGE_VERSION}" + .to_string(), + ) + .replace("{API_URL}", self.api()) + } +} + +/// An entry in the index file +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(deny_unknown_fields)] +pub struct IndexFileEntry { + /// The version of the package + pub version: Version, + /// The realm of the package + pub realm: Option, + + /// A description of the package + #[serde(default, skip_serializing_if = "Option::is_none")] + pub description: Option, + /// The license of the package + #[serde(default, skip_serializing_if = "Option::is_none")] + pub license: Option, + /// The authors of the package + #[serde(default, skip_serializing_if = "Option::is_none")] + pub authors: Option>, + + /// The dependencies of the package + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub dependencies: Vec<(DependencySpecifier, DependencyType)>, +} + +impl From for IndexFileEntry { + fn from(manifest: Manifest) -> IndexFileEntry { + let dependencies = manifest.dependencies(); + + IndexFileEntry { + version: manifest.version, + realm: manifest.realm, + + description: manifest.description, + license: manifest.license, + authors: manifest.authors, + + dependencies, + } + } +} + +/// An index file +pub type IndexFile = Vec; diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..242ac6a --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,48 @@ +#![deny(missing_docs)] +//! pesde is a package manager for Roblox that is designed to be feature-rich and easy to use. +//! Currently, pesde is in a very early stage of development, but already supports the following features: +//! - Managing dependencies +//! - Re-exporting types +//! - `bin` exports (ran with Lune) +//! - Patching packages + +/// Resolving, downloading and managing dependencies +pub mod dependencies; +/// Managing the pesde index +pub mod index; +/// Creating linking files ('re-export' modules) +pub mod linking_file; +/// Managing the pesde manifest +pub mod manifest; +/// Multi-threading utilities +pub mod multithread; +/// Creating, parsing, and validating package names +pub mod package_name; +/// Managing patches +pub mod patches; +/// Managing pesde projects +pub mod project; + +/// The folder that contains shared packages +pub const PACKAGES_FOLDER: &str = "packages"; +/// The folder that contains dev packages +pub const DEV_PACKAGES_FOLDER: &str = "dev_packages"; +/// The folder that contains server packages +pub const SERVER_PACKAGES_FOLDER: &str = "server_packages"; +/// The folder that contains the packages index (where every package is stored after being downloaded) +pub const INDEX_FOLDER: &str = "pesde_index"; +/// The name of the manifest file +pub const MANIFEST_FILE_NAME: &str = "pesde.yaml"; +/// The name of the lockfile +pub const LOCKFILE_FILE_NAME: &str = "pesde-lock.yaml"; +/// The name of the patches folder +pub const PATCHES_FOLDER: &str = "patches"; +/// Files to be ignored when publishing +pub const IGNORED_FOLDERS: &[&str] = &[ + PACKAGES_FOLDER, + DEV_PACKAGES_FOLDER, + SERVER_PACKAGES_FOLDER, + ".git", +]; + +const USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")); diff --git a/src/linking_file.rs b/src/linking_file.rs new file mode 100644 index 0000000..937f376 --- /dev/null +++ b/src/linking_file.rs @@ -0,0 +1,284 @@ +use std::{ + fs::{read, write}, + iter, + path::{Component, Path, PathBuf}, + str::from_utf8, +}; + +use full_moon::{ + ast::types::ExportedTypeDeclaration, + parse, + visitors::{Visit, Visitor}, +}; +use log::debug; +use semver::Version; +use thiserror::Error; + +use crate::{ + dependencies::resolution::{packages_folder, ResolvedPackage, ResolvedVersionsMap}, + index::Index, + manifest::{Manifest, ManifestReadError, PathStyle, Realm}, + package_name::PackageName, + project::Project, +}; + +struct TypeVisitor { + pub(crate) types: Vec, +} + +impl Visitor for TypeVisitor { + fn visit_exported_type_declaration(&mut self, node: &ExportedTypeDeclaration) { + let name = node.type_declaration().type_name().to_string(); + + let (declaration_generics, generics) = + if let Some(declaration) = node.type_declaration().generics() { + let mut declaration_generics = vec![]; + let mut generics = vec![]; + + for generic in declaration.generics().iter() { + declaration_generics.push(generic.to_string()); + + if generic.default_type().is_some() { + generics.push(generic.parameter().to_string()) + } else { + generics.push(generic.to_string()) + } + } + + ( + format!("<{}>", declaration_generics.join(", ")), + format!("<{}>", generics.join(", ")), + ) + } else { + ("".to_string(), "".to_string()) + }; + + self.types.push(format!( + "export type {name}{declaration_generics} = module.{name}{generics}\n" + )); + } +} + +/// Generates the contents of a linking file, given the require path, and the contents of the target file +/// The contents will be scanned for type exports, and the linking file will be generated accordingly +pub fn linking_file(content: &str, path: &str) -> Result { + let mut linker = format!("local module = require({path})\n"); + let mut visitor = TypeVisitor { types: vec![] }; + + parse(content)?.nodes().visit(&mut visitor); + + for ty in visitor.types { + linker.push_str(&ty); + } + + linker.push_str("return module"); + + Ok(linker) +} + +#[derive(Debug, Error)] +/// An error that occurred while linking dependencies +pub enum LinkingError { + #[error("error interacting with the file system")] + /// An error that occurred while interacting with the file system + Io(#[from] std::io::Error), + + #[error("failed getting file name from {0}")] + /// An error that occurred while getting a file name + FileNameFail(PathBuf), + + #[error("failed converting file name to string")] + /// An error that occurred while converting a file name to a string + FileNameToStringFail, + + #[error("failed getting relative path from {0} to {1}")] + /// An error that occurred while getting a relative path + RelativePathFail(PathBuf, PathBuf), + + #[error("failed getting path parent of {0}")] + /// An error that occurred while getting a path parent + ParentFail(PathBuf), + + #[error("failed to convert path component to string")] + /// An error that occurred while converting a path component to a string + ComponentToStringFail, + + #[error("failed to get path string")] + /// An error that occurred while getting a path string + PathToStringFail, + + #[error("error encoding utf-8 string")] + /// An error that occurred while converting a byte slice to a string + Utf8(#[from] std::str::Utf8Error), + + #[error("error reading manifest")] + /// An error that occurred while reading the manifest of a package + ManifestRead(#[from] ManifestReadError), + + #[error("missing realm {0} in-game path")] + /// An error that occurred while getting the in-game path for a realm + MissingRealmInGamePath(Realm), + + #[error("library source is not valid Luau")] + /// An error that occurred because the library source is not valid Luau + InvalidLuau(#[from] full_moon::Error), +} + +pub(crate) fn link, Q: AsRef, I: Index>( + project: &Project, + resolved_pkg: &ResolvedPackage, + destination_dir: P, + parent_dependency_packages_dir: Q, +) -> Result<(), LinkingError> { + let (_, source_dir) = resolved_pkg.directory(project.path()); + let file = Manifest::from_path(&source_dir)?; + + let Some(lib_export) = file.exports.lib else { + return Ok(()); + }; + + let lib_export = lib_export.to_path(&source_dir); + + let path_style = &project.manifest().path_style; + let PathStyle::Roblox { place } = &path_style; + + debug!("linking {resolved_pkg} using `{}` path style", path_style); + + let name = resolved_pkg.pkg_ref.name().name(); + + let destination_dir = if resolved_pkg.is_root { + project.path().join(packages_folder( + &resolved_pkg.specifier.realm().cloned().unwrap_or_default(), + )) + } else { + destination_dir.as_ref().to_path_buf() + }; + + let destination_file = destination_dir.join(format!("{name}.lua")); + + let realm_folder = project.path().join(resolved_pkg.packages_folder()); + let in_different_folders = realm_folder != parent_dependency_packages_dir.as_ref(); + + let mut path = if in_different_folders { + pathdiff::diff_paths(&source_dir, &realm_folder) + .ok_or_else(|| LinkingError::RelativePathFail(source_dir.clone(), realm_folder))? + } else { + pathdiff::diff_paths(&source_dir, &destination_dir).ok_or_else(|| { + LinkingError::RelativePathFail(source_dir.clone(), destination_dir.to_path_buf()) + })? + }; + path.set_extension(""); + + let beginning = if in_different_folders { + place + .get(&resolved_pkg.realm) + .ok_or_else(|| LinkingError::MissingRealmInGamePath(resolved_pkg.realm))? + .clone() + } else if name == "init" { + "script".to_string() + } else { + "script.Parent".to_string() + }; + + let path = iter::once(Ok(beginning)) + .chain(path.components().map(|component| { + Ok(match component { + Component::ParentDir => ".Parent".to_string(), + Component::Normal(part) => format!( + "[{:?}]", + part.to_str().ok_or(LinkingError::ComponentToStringFail)? + ), + _ => unreachable!("invalid path component"), + }) + })) + .collect::>()?; + + debug!( + "writing linking file for {} with import `{path}` to {}", + source_dir.display(), + destination_file.display() + ); + + let raw_file_contents = read(lib_export)?; + let file_contents = from_utf8(&raw_file_contents)?; + + let linking_file_contents = linking_file(file_contents, &path)?; + + write(&destination_file, linking_file_contents)?; + + Ok(()) +} + +#[derive(Debug, Error)] +#[error("error linking {1}@{2} to {3}@{4}")] +/// An error that occurred while linking the dependencies +pub struct LinkingDependenciesError( + #[source] LinkingError, + PackageName, + Version, + PackageName, + Version, +); + +impl Project { + /// Links the dependencies of the project + pub fn link_dependencies( + &self, + map: &ResolvedVersionsMap, + ) -> Result<(), LinkingDependenciesError> { + for (name, versions) in map { + for (version, resolved_pkg) in versions { + let (container_dir, _) = resolved_pkg.directory(self.path()); + + debug!( + "linking package {name}@{version}'s dependencies to directory {}", + container_dir.display() + ); + + for (dep_name, dep_version) in &resolved_pkg.dependencies { + let dep = map + .get(dep_name) + .and_then(|versions| versions.get(dep_version)) + .unwrap(); + + link( + self, + dep, + &container_dir, + &self.path().join(resolved_pkg.packages_folder()), + ) + .map_err(|e| { + LinkingDependenciesError( + e, + dep_name.clone(), + dep_version.clone(), + name.clone(), + version.clone(), + ) + })?; + } + + if resolved_pkg.is_root { + let linking_dir = &self.path().join(resolved_pkg.packages_folder()); + + debug!( + "linking root package {name}@{version} to directory {}", + linking_dir.display() + ); + + link(self, resolved_pkg, linking_dir, linking_dir).map_err(|e| { + LinkingDependenciesError( + e, + name.clone(), + version.clone(), + name.clone(), + version.clone(), + ) + })?; + } + } + } + + Ok(()) + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..6ddf591 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,217 @@ +use std::{ + fs::{create_dir_all, read}, + hash::{DefaultHasher, Hash, Hasher}, + path::PathBuf, +}; + +use auth_git2::GitAuthenticator; +use clap::{Parser, Subcommand}; +use directories::ProjectDirs; +use indicatif::MultiProgress; +use indicatif_log_bridge::LogWrapper; +use keyring::Entry; +use pretty_env_logger::env_logger::Env; +use reqwest::header::{ACCEPT, AUTHORIZATION}; +use serde::{Deserialize, Serialize}; + +use cli::{ + auth::{auth_command, AuthCommand}, + config::{config_command, ConfigCommand}, + root::root_command, +}; +use pesde::index::GitIndex; + +mod cli; + +#[derive(Subcommand)] +pub enum Command { + /// Installs the dependencies of the project + Install { + #[clap(long, short)] + locked: bool, + }, + + /// Runs the `bin` export of the specified package + Run { + #[clap(value_name = "PACKAGE")] + package: String, + + #[clap(last = true)] + args: Vec, + }, + + /// Searches for a package on the registry + Search { + #[clap(value_name = "QUERY")] + query: Option, + }, + + /// Publishes the project to the registry + Publish, + + /// Begins a new patch + Patch { package: String }, + + /// Commits (finished) the patch + PatchCommit { + #[clap(value_name = "DIRECTORY")] + dir: PathBuf, + }, + + /// Auth-related commands + Auth { + #[clap(subcommand)] + command: AuthCommand, + }, + + /// Config-related commands + Config { + #[clap(subcommand)] + command: ConfigCommand, + }, +} + +#[derive(Parser)] +struct Cli { + #[clap(subcommand)] + command: Command, + + #[arg(short, long, value_name = "DIRECTORY")] + directory: Option, +} + +#[derive(Serialize, Deserialize, Clone)] +struct CliConfig { + index_repo_url: String, + cache_dir: Option, +} + +impl CliConfig { + fn cache_dir(&self, directories: &ProjectDirs) -> PathBuf { + self.cache_dir + .clone() + .unwrap_or_else(|| directories.cache_dir().to_path_buf()) + } +} + +struct CliParams { + index: GitIndex, + api_token_entry: Entry, + reqwest_client: reqwest::blocking::Client, + cli_config: CliConfig, + cwd: PathBuf, + multi: MultiProgress, + directories: ProjectDirs, +} + +impl CliConfig { + fn write(&self, directories: &ProjectDirs) -> anyhow::Result<()> { + let cli_config_path = directories.config_dir().join("config.yaml"); + serde_yaml::to_writer( + &mut std::fs::File::create(cli_config_path.as_path())?, + &self, + )?; + + Ok(()) + } +} + +#[macro_export] +macro_rules! send_request { + ($req:expr) => {{ + let res = $req.send()?; + + match res.error_for_status_ref() { + Ok(_) => res, + Err(e) => { + panic!("request failed: {e}\nbody: {}", res.text()?); + } + } + }}; +} + +fn main() -> anyhow::Result<()> { + let logger = pretty_env_logger::formatted_builder() + .parse_env(Env::default().default_filter_or("info")) + .build(); + let multi = MultiProgress::new(); + + LogWrapper::new(multi.clone(), logger).try_init().unwrap(); + + let cli = Cli::parse(); + + let directories = ProjectDirs::from("com", env!("CARGO_BIN_NAME"), env!("CARGO_BIN_NAME")) + .expect("couldn't get home directory"); + + let cli_config_path = directories.config_dir().join("config.yaml"); + let cli_config = if cli_config_path.exists() { + serde_yaml::from_slice(&read(cli_config_path.as_path())?)? + } else { + let config = CliConfig { + index_repo_url: "https://github.com/daimond113/pesde-index".to_string(), + cache_dir: None, + }; + create_dir_all(directories.config_dir())?; + config.write(&directories)?; + config + }; + + let cwd_buf = cli + .directory + .or(std::env::current_dir().ok()) + .ok_or(anyhow::anyhow!("couldn't get current directory"))?; + + let api_token_entry = Entry::new(env!("CARGO_BIN_NAME"), "api_token")?; + + let mut hasher = DefaultHasher::new(); + cli_config.index_repo_url.hash(&mut hasher); + let hash = hasher.finish().to_string(); + + let index = GitIndex::new( + cli_config.cache_dir(&directories).join("index").join(hash), + &cli_config.index_repo_url, + Some(Box::new(|| { + Box::new(|a, b, c| { + let git_authenticator = GitAuthenticator::new(); + let config = git2::Config::open_default().unwrap(); + let mut cred = git_authenticator.credentials(&config); + + cred(a, b, c) + }) + })), + ); + index.refresh()?; + + let mut header_map = reqwest::header::HeaderMap::new(); + header_map.insert(ACCEPT, "application/json".parse()?); + header_map.insert( + AUTHORIZATION, + format!("Bearer {}", api_token_entry.get_password()?).parse()?, + ); + header_map.insert("X-GitHub-Api-Version", "2022-11-28".parse()?); + + let reqwest_client = reqwest::blocking::Client::builder() + .user_agent(concat!( + env!("CARGO_PKG_NAME"), + "/", + env!("CARGO_PKG_VERSION") + )) + .default_headers(header_map) + .build()?; + + let params = CliParams { + index, + api_token_entry, + reqwest_client, + cli_config, + cwd: cwd_buf, + multi, + directories, + }; + + match cli.command { + Command::Auth { command } => auth_command(command, params), + Command::Config { command } => config_command(command, params), + cmd => root_command(cmd, params), + } +} diff --git a/src/manifest.rs b/src/manifest.rs new file mode 100644 index 0000000..50d1b76 --- /dev/null +++ b/src/manifest.rs @@ -0,0 +1,180 @@ +use std::{collections::BTreeMap, fmt::Display, fs::read}; + +use relative_path::RelativePathBuf; +use semver::Version; +use serde::{Deserialize, Serialize}; +use thiserror::Error; + +use crate::{dependencies::DependencySpecifier, package_name::PackageName, MANIFEST_FILE_NAME}; + +/// The files exported by the package +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +#[serde(deny_unknown_fields)] +pub struct Exports { + /// Points to the file which exports the package. As of currently this is only used for re-exporting types. + /// Libraries must have a structure in Roblox where the main file becomes the folder, for example: + /// A package called pesde/lib has a file called src/main.lua. + /// Pesde puts this package in a folder called pesde_lib. + /// The package has to have set up configuration for file-syncing tools such as Rojo so that src/main.lua becomes the pesde_lib and turns it into a ModuleScript + #[serde(default, skip_serializing_if = "Option::is_none")] + pub lib: Option, + + /// Points to the file that will be executed with Lune + #[serde(default, skip_serializing_if = "Option::is_none")] + pub bin: Option, +} + +/// The path style used by the package +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "snake_case", deny_unknown_fields)] +pub enum PathStyle { + /// The path style used by Roblox (e.g. `script.Parent` or `script.Parent.Parent`) + Roblox { + /// A map of realm to in-game package folder location (used for linking between packages in different realms) + #[serde(default)] + place: BTreeMap, + }, +} + +impl Default for PathStyle { + fn default() -> Self { + PathStyle::Roblox { + place: BTreeMap::new(), + } + } +} + +impl Display for PathStyle { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + PathStyle::Roblox { .. } => write!(f, "roblox"), + } + } +} + +/// The realm of the package +#[derive( + Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Default, +)] +#[serde(rename_all = "snake_case", deny_unknown_fields)] +pub enum Realm { + /// The package is shared (usually ReplicatedStorage) + #[default] + Shared, + /// The package is server only (usually ServerScriptService/ServerStorage) + Server, + /// The package is development only + Development, +} + +impl Realm { + /// Returns the most restrictive realm + pub fn or<'a>(&'a self, other: &'a Self) -> &'a Self { + match self { + Realm::Shared => other, + _ => self, + } + } +} + +impl Display for Realm { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Realm::Shared => write!(f, "shared"), + Realm::Server => write!(f, "server"), + Realm::Development => write!(f, "development"), + } + } +} + +/// The manifest of a package +#[derive(Serialize, Deserialize, Debug, Clone)] +// #[serde(deny_unknown_fields)] +pub struct Manifest { + /// The name of the package + pub name: PackageName, + /// The version of the package. Must be [semver](https://semver.org) compatible. The registry will not accept non-semver versions and the CLI will not handle such packages + pub version: Version, + /// The files exported by the package + #[serde(default)] + pub exports: Exports, + /// The path style to use for linking modules + #[serde(default)] + pub path_style: PathStyle, + /// Whether the package is private (it should not be published) + #[serde(default)] + pub private: bool, + /// The realm of the package + pub realm: Option, + + /// The dependencies of the package + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub dependencies: Vec, + /// The peer dependencies of the package + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub peer_dependencies: Vec, + + /// A short description of the package + #[serde(default, skip_serializing_if = "Option::is_none")] + pub description: Option, + /// The license of the package + #[serde(default, skip_serializing_if = "Option::is_none")] + pub license: Option, + /// The authors of the package + #[serde(default, skip_serializing_if = "Option::is_none")] + pub authors: Option>, +} + +/// An error that occurred while reading the manifest +#[derive(Debug, Error)] +pub enum ManifestReadError { + /// An error that occurred while interacting with the file system + #[error("error interacting with the file system")] + Io(#[from] std::io::Error), + + /// An error that occurred while deserializing the manifest + #[error("error deserializing manifest")] + ManifestDeser(#[source] serde_yaml::Error), +} + +/// The type of dependency +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +#[serde(rename_all = "snake_case")] +pub enum DependencyType { + /// A normal dependency + #[default] + Normal, + /// A peer dependency + Peer, +} + +impl Manifest { + /// Reads a manifest from a path (if the path is a directory, it will look for the manifest file inside it, otherwise it will read the file directly) + pub fn from_path>(path: P) -> Result { + let path = path.as_ref(); + let path = if path.file_name() == Some(MANIFEST_FILE_NAME.as_ref()) { + path.to_path_buf() + } else { + path.join(MANIFEST_FILE_NAME) + }; + + let raw_contents = read(path)?; + let manifest = + serde_yaml::from_slice(&raw_contents).map_err(ManifestReadError::ManifestDeser)?; + + Ok(manifest) + } + + /// Returns all dependencies + pub fn dependencies(&self) -> Vec<(DependencySpecifier, DependencyType)> { + self.dependencies + .iter() + .map(|dep| (dep.clone(), DependencyType::Normal)) + .chain( + self.peer_dependencies + .iter() + .map(|dep| (dep.clone(), DependencyType::Peer)), + ) + .collect() + } +} diff --git a/src/multithread.rs b/src/multithread.rs new file mode 100644 index 0000000..d1f7e1e --- /dev/null +++ b/src/multithread.rs @@ -0,0 +1,33 @@ +use std::sync::mpsc::Receiver; +use threadpool::ThreadPool; + +/// A multithreaded job +pub struct MultithreadedJob { + pub(crate) progress: Receiver>, + pub(crate) pool: ThreadPool, +} + +impl MultithreadedJob { + pub(crate) fn new() -> (Self, std::sync::mpsc::Sender>) { + let (tx, rx) = std::sync::mpsc::channel(); + let pool = ThreadPool::new(6); + + (Self { progress: rx, pool }, tx) + } + + /// Returns the progress of the job + pub fn progress(&self) -> &Receiver> { + &self.progress + } + + /// Waits for the job to finish + pub fn wait(self) -> Result<(), E> { + self.pool.join(); + + for result in self.progress { + result?; + } + + Ok(()) + } +} diff --git a/src/package_name.rs b/src/package_name.rs new file mode 100644 index 0000000..57bd899 --- /dev/null +++ b/src/package_name.rs @@ -0,0 +1,151 @@ +use std::{fmt::Display, str::FromStr}; + +use serde::{de::Visitor, Deserialize, Serialize}; +use thiserror::Error; + +/// A package name +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct PackageName(String, String); + +/// An error that occurred while validating a package name part (scope or name) +#[derive(Debug, Error)] +pub enum PackageNameValidationError { + /// The package name part is empty + #[error("package name part cannot be empty")] + EmptyPart, + /// The package name part contains invalid characters (only lowercase ASCII characters, numbers, and underscores are allowed) + #[error("package name {0} part can only contain lowercase ASCII characters, numbers, and underscores")] + InvalidPart(String), + /// The package name part is too long (it cannot be longer than 24 characters) + #[error("package name {0} part cannot be longer than 24 characters")] + PartTooLong(String), +} + +/// Validates a package name part (scope or name) +pub fn validate_part(part: &str) -> Result<(), PackageNameValidationError> { + if part.is_empty() { + return Err(PackageNameValidationError::EmptyPart); + } + + if !part + .chars() + .all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_') + { + return Err(PackageNameValidationError::InvalidPart(part.to_string())); + } + + if part.len() > 24 { + return Err(PackageNameValidationError::PartTooLong(part.to_string())); + } + + Ok(()) +} + +const SEPARATOR: char = '/'; +const ESCAPED_SEPARATOR: char = '-'; + +/// An error that occurred while parsing an escaped package name +#[derive(Debug, Error)] +pub enum EscapedPackageNameError { + /// This is not a valid escaped package name + #[error("package name is not in the format `scope{ESCAPED_SEPARATOR}name`")] + Invalid, + + /// The package name is invalid + #[error("invalid package name")] + InvalidName(#[from] PackageNameValidationError), +} + +impl PackageName { + /// Creates a new package name + pub fn new(scope: &str, name: &str) -> Result { + validate_part(scope)?; + validate_part(name)?; + + Ok(Self(scope.to_string(), name.to_string())) + } + + /// Parses an escaped package name + pub fn from_escaped(s: &str) -> Result { + let (scope, name) = s + .split_once(ESCAPED_SEPARATOR) + .ok_or(EscapedPackageNameError::Invalid)?; + Ok(Self::new(scope, name)?) + } + + /// Gets the scope of the package name + pub fn scope(&self) -> &str { + &self.0 + } + + /// Gets the name of the package name + pub fn name(&self) -> &str { + &self.1 + } + + /// Gets the escaped form (for use in file names, etc.) of the package name + pub fn escaped(&self) -> String { + format!("{}{ESCAPED_SEPARATOR}{}", self.0, self.1) + } + + /// Gets the parts of the package name + pub fn parts(&self) -> (&str, &str) { + (&self.0, &self.1) + } +} + +impl Display for PackageName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}{SEPARATOR}{}", self.0, self.1) + } +} + +/// An error that occurred while parsing a package name +#[derive(Debug, Error)] +pub enum FromStrPackageNameParseError { + /// This is not a valid package name + #[error("package name is not in the format `scope{SEPARATOR}name`")] + Invalid, + /// The package name is invalid + #[error("invalid name part")] + InvalidPart(#[from] PackageNameValidationError), +} + +impl FromStr for PackageName { + type Err = FromStrPackageNameParseError; + + fn from_str(s: &str) -> Result { + let parts: Vec<&str> = s.split(SEPARATOR).collect(); + if parts.len() != 2 { + return Err(FromStrPackageNameParseError::Invalid); + } + + Ok(PackageName::new(parts[0], parts[1])?) + } +} + +impl Serialize for PackageName { + fn serialize(&self, serializer: S) -> Result { + serializer.serialize_str(&self.to_string()) + } +} + +struct PackageNameVisitor; + +impl<'de> Visitor<'de> for PackageNameVisitor { + type Value = PackageName; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(formatter, "a string in the format `scope{SEPARATOR}name`") + } + + fn visit_str(self, v: &str) -> Result { + v.parse().map_err(|e| E::custom(e)) + } +} + +impl<'de> Deserialize<'de> for PackageName { + fn deserialize>(deserializer: D) -> Result { + deserializer.deserialize_str(PackageNameVisitor) + } +} diff --git a/src/patches.rs b/src/patches.rs new file mode 100644 index 0000000..d56e60e --- /dev/null +++ b/src/patches.rs @@ -0,0 +1,210 @@ +use std::{ + fs::{read, read_dir}, + path::{Path, PathBuf}, +}; + +use git2::{ApplyLocation, Diff, DiffFormat, DiffLineType, Repository, Signature}; +use log::debug; +use semver::Version; +use thiserror::Error; + +use crate::{ + dependencies::resolution::ResolvedVersionsMap, index::Index, package_name::PackageName, + project::Project, PATCHES_FOLDER, +}; + +fn make_signature<'a>() -> Result, git2::Error> { + Signature::now( + env!("CARGO_PKG_NAME"), + concat!(env!("CARGO_PKG_NAME"), "@localhost"), + ) +} + +/// Sets up a patches repository in the specified directory +pub fn setup_patches_repo>(dir: P) -> Result { + let repo = Repository::init(&dir)?; + + { + let signature = make_signature()?; + let mut index = repo.index()?; + index.add_all(["*"].iter(), git2::IndexAddOption::DEFAULT, None)?; + index.write()?; + + let oid = index.write_tree()?; + let tree = repo.find_tree(oid)?; + + repo.commit(Some("HEAD"), &signature, &signature, "original", &tree, &[])?; + } + + Ok(repo) +} + +/// An error that occurred while creating patches +#[derive(Debug, Error)] +pub enum CreatePatchError { + /// An error that occurred while interacting with the file system + #[error("error interacting with the file system")] + Io(#[from] std::io::Error), + + /// An error that occurred while interacting with git + #[error("error interacting with git")] + Git(#[from] git2::Error), + + /// An error that occurred while getting a file name + #[error("failed to get file name from {0}")] + FileNameFail(PathBuf), + + /// An error that occurred while stripping a prefix + #[error("error stripping prefix {1} from path {2}")] + StripPrefixFail(#[source] std::path::StripPrefixError, PathBuf, PathBuf), +} + +/// Creates a patch for the package in the specified directory +pub fn create_patch>(dir: P) -> Result, CreatePatchError> { + let mut patches = vec![]; + let repo = Repository::open(dir.as_ref())?; + + let original = repo.head()?.peel_to_tree()?; + let diff = repo.diff_tree_to_workdir(Some(&original), None)?; + + diff.print(DiffFormat::Patch, |_delta, _hunk, line| { + match line.origin_value() { + DiffLineType::Context | DiffLineType::Addition | DiffLineType::Deletion => { + let origin = line.origin(); + let mut buffer = vec![0; origin.len_utf8()]; + origin.encode_utf8(&mut buffer); + patches.extend(buffer); + } + _ => {} + } + patches.extend(line.content()); + + true + })?; + + Ok(patches) +} + +/// An error that occurred while applying patches +#[derive(Debug, Error)] +pub enum ApplyPatchesError { + /// An error that occurred while interacting with the file system + #[error("error interacting with the file system")] + Io(#[from] std::io::Error), + + /// An error that occurred while interacting with git + #[error("error interacting with git")] + Git(#[from] git2::Error), + + /// An error that occurred while getting a file name + #[error("failed to get file name from {0}")] + FileNameFail(PathBuf), + + /// An error that occurred while converting a path to a string + #[error("failed to convert path to string")] + ToStringFail, + + /// An error that occurred because a patch name was malformed + #[error("malformed patch name {0}")] + MalformedPatch(String), + + /// An error that occurred while parsing a package name + #[error("failed to parse package name {0}")] + PackageNameParse(#[from] crate::package_name::EscapedPackageNameError), + + /// An error that occurred while getting a file stem + #[error("failed to get file stem")] + FileStemFail, + + /// An error that occurred while reading a file + #[error("failed to read file")] + ReadFail, + + /// An error that occurred because a package was not found in the dependencies + #[error("package {0} not found in the lockfile")] + PackageNotFound(PackageName), + + /// An error that occurred because a version was not found for a package + #[error("version {0} not found for package {1}")] + VersionNotFound(Version, PackageName), + + /// An error that occurred while parsing a version + #[error("failed to parse version")] + VersionParse(#[from] semver::Error), + + /// An error that occurred while stripping a prefix + #[error("strip prefix error")] + StripPrefixFail(#[from] std::path::StripPrefixError), +} + +impl Project { + /// Applies patches for the project + pub fn apply_patches(&self, map: &ResolvedVersionsMap) -> Result<(), ApplyPatchesError> { + let patches_dir = self.path().join(PATCHES_FOLDER); + if !patches_dir.exists() { + return Ok(()); + } + + for file in read_dir(&patches_dir)? { + let file = file?; + if !file.file_type()?.is_file() { + continue; + } + + let path = file.path(); + + let dir_name = path + .file_name() + .ok_or_else(|| ApplyPatchesError::FileNameFail(path.clone()))?; + let dir_name = dir_name.to_str().ok_or(ApplyPatchesError::ToStringFail)?; + + let (package_name, version) = dir_name + .strip_suffix(".patch") + .unwrap_or(dir_name) + .split_once('@') + .ok_or_else(|| ApplyPatchesError::MalformedPatch(dir_name.to_string()))?; + + let package_name = PackageName::from_escaped(package_name)?; + let version = Version::parse(version)?; + + let versions = map + .get(&package_name) + .ok_or_else(|| ApplyPatchesError::PackageNotFound(package_name.clone()))?; + + let resolved_pkg = versions.get(&version).ok_or_else(|| { + ApplyPatchesError::VersionNotFound(version.clone(), package_name.clone()) + })?; + + debug!("resolved package {package_name}@{version} to {resolved_pkg}"); + + let (_, source_path) = resolved_pkg.directory(self.path()); + let diff = Diff::from_buffer(&read(&path)?)?; + + let repo = match Repository::open(&source_path) { + Ok(repo) => repo, + Err(_) => setup_patches_repo(&source_path)?, + }; + + repo.apply(&diff, ApplyLocation::Both, None)?; + + let mut index = repo.index()?; + index.add_all(["*"].iter(), git2::IndexAddOption::DEFAULT, None)?; + index.write()?; + + let signature = make_signature()?; + let tree_id = index.write_tree()?; + let tree = repo.find_tree(tree_id)?; + let parent = repo.head()?.peel_to_commit()?; + repo.commit( + Some("HEAD"), + &signature, + &signature, + "applied patches", + &tree, + &[&parent], + )?; + } + + Ok(()) + } +} diff --git a/src/project.rs b/src/project.rs new file mode 100644 index 0000000..cfdf724 --- /dev/null +++ b/src/project.rs @@ -0,0 +1,219 @@ +use std::{ + fmt::Debug, + fs::{read, File}, + path::{Path, PathBuf}, +}; +use thiserror::Error; + +use crate::dependencies::DownloadError; +use crate::index::Index; +use crate::linking_file::LinkingDependenciesError; +use crate::{ + dependencies::resolution::ResolvedVersionsMap, + manifest::{Manifest, ManifestReadError}, + LOCKFILE_FILE_NAME, +}; + +/// A pesde project +#[derive(Clone, Debug)] +pub struct Project { + path: PathBuf, + cache_path: PathBuf, + index: I, + manifest: Manifest, + registry_auth_token: Option, +} + +/// Options for installing a project +pub struct InstallOptions { + locked: bool, + auto_download: bool, + resolved_versions_map: Option, +} + +impl Default for InstallOptions { + fn default() -> Self { + Self { + locked: false, + auto_download: true, + resolved_versions_map: None, + } + } +} + +impl InstallOptions { + /// Creates a new set of install options (uses the Default implementation) + pub fn new() -> Self { + Self::default() + } + + /// Makes the installation to use the lockfile, and ensure that the lockfile is up-to-date + pub fn locked(&self, locked: bool) -> Self { + Self { + locked, + resolved_versions_map: self.resolved_versions_map.clone(), + ..*self + } + } + + /// Makes the installation to automatically download the dependencies + /// Having this set to false is only useful if you want to download the dependencies yourself. An example of this is the CLI's progress bar + pub fn auto_download(&self, auto_download: bool) -> Self { + Self { + auto_download, + resolved_versions_map: self.resolved_versions_map.clone(), + ..*self + } + } + + /// Makes the installation to use the given resolved versions map + /// Having this set to Some is only useful if you're using auto_download = false + pub fn resolved_versions_map(&self, resolved_versions_map: ResolvedVersionsMap) -> Self { + Self { + resolved_versions_map: Some(resolved_versions_map), + ..*self + } + } +} + +/// An error that occurred while reading the lockfile +#[derive(Debug, Error)] +pub enum ReadLockfileError { + /// An error that occurred while interacting with the file system + #[error("error interacting with the file system")] + Io(#[from] std::io::Error), + + /// An error that occurred while deserializing the lockfile + #[error("error deserializing lockfile")] + LockfileDeser(#[source] serde_yaml::Error), +} + +/// An error that occurred while downloading a project +#[derive(Debug, Error)] +pub enum InstallProjectError { + /// An error that occurred while resolving the dependency tree + #[error("failed to resolve dependency tree")] + ResolveTree(#[from] crate::dependencies::resolution::ResolveError), + + /// An error that occurred while downloading a package + #[error("failed to download package")] + DownloadPackage(#[from] DownloadError), + + /// An error that occurred while applying patches + #[error("error applying patches")] + ApplyPatches(#[from] crate::patches::ApplyPatchesError), + + /// An error that occurred while linking dependencies + #[error("failed to link dependencies")] + Linking(#[from] LinkingDependenciesError), + + /// An error that occurred while interacting with the file system + #[error("error interacting with the file system")] + Io(#[from] std::io::Error), + + /// An error that occurred while writing the lockfile + #[error("failed to write lockfile")] + LockfileSer(#[source] serde_yaml::Error), +} + +impl Project { + /// Creates a new project + pub fn new, Q: AsRef>( + path: P, + cache_path: Q, + index: I, + manifest: Manifest, + registry_auth_token: Option, + ) -> Self { + Self { + path: path.as_ref().to_path_buf(), + cache_path: cache_path.as_ref().to_path_buf(), + index, + manifest, + registry_auth_token, + } + } + + /// Creates a new project from a path (manifest will be read from the path) + pub fn from_path, Q: AsRef>( + path: P, + cache_path: Q, + index: I, + registry_auth_token: Option, + ) -> Result { + let manifest = Manifest::from_path(path.as_ref())?; + + Ok(Self::new( + path, + cache_path, + index, + manifest, + registry_auth_token, + )) + } + + /// Returns the index of the project + pub fn index(&self) -> &I { + &self.index + } + + /// Returns the manifest of the project + pub fn manifest(&self) -> &Manifest { + &self.manifest + } + + /// Returns the cache directory of the project + pub fn cache_dir(&self) -> &Path { + &self.cache_path + } + + /// Returns the path of the project + pub fn path(&self) -> &Path { + &self.path + } + + /// Returns the registry auth token of the project + pub fn registry_auth_token(&self) -> Option<&String> { + self.registry_auth_token.as_ref() + } + + /// Returns the lockfile of the project + pub fn lockfile(&self) -> Result, ReadLockfileError> { + let lockfile_path = self.path.join(LOCKFILE_FILE_NAME); + + Ok(if lockfile_path.exists() { + let lockfile_contents = read(&lockfile_path)?; + let lockfile: ResolvedVersionsMap = serde_yaml::from_slice(&lockfile_contents) + .map_err(ReadLockfileError::LockfileDeser)?; + + Some(lockfile) + } else { + None + }) + } + + /// Downloads the project's dependencies, applies patches, and links the dependencies + pub fn install(&self, install_options: InstallOptions) -> Result<(), InstallProjectError> { + let map = match install_options.resolved_versions_map { + Some(map) => map, + None => self + .manifest + .dependency_tree(self, install_options.locked)?, + }; + + if install_options.auto_download { + self.download(&map)?.wait()?; + } + + self.apply_patches(&map)?; + + self.link_dependencies(&map)?; + + if !install_options.locked { + serde_yaml::to_writer(File::create(self.path.join(LOCKFILE_FILE_NAME))?, &map) + .map_err(InstallProjectError::LockfileSer)?; + } + + Ok(()) + } +} diff --git a/tests/prelude.rs b/tests/prelude.rs new file mode 100644 index 0000000..4072f3b --- /dev/null +++ b/tests/prelude.rs @@ -0,0 +1,99 @@ +use std::{ + collections::{BTreeSet, HashMap}, + sync::Arc, +}; + +use pesde::{ + index::{ + ConfigError, CreatePackageVersionError, CredentialsFn, Index, IndexConfig, IndexFile, + IndexFileEntry, IndexPackageError, ScopeOwners, ScopeOwnersError, + }, + manifest::Manifest, + package_name::PackageName, +}; + +/// An in-memory implementation of the [`Index`] trait. Used for testing. +#[derive(Debug, Clone, Default)] +pub struct InMemoryIndex { + packages: HashMap, IndexFile)>, +} + +impl InMemoryIndex { + pub fn new() -> Self { + Self::default() + } + + pub fn with_scope(mut self, scope: &str, owners: BTreeSet) -> Self { + self.packages + .insert(scope.to_string(), (owners, IndexFile::default())); + self + } + + pub fn with_package(mut self, scope: &str, index_file: IndexFileEntry) -> Self { + self.packages + .entry(scope.to_string()) + .or_insert_with(|| (BTreeSet::new(), IndexFile::default())) + .1 + .push(index_file); + self + } +} + +impl Index for InMemoryIndex { + fn scope_owners(&self, scope: &str) -> Result, ScopeOwnersError> { + Ok(self.packages.get(scope).map(|(owners, _)| owners).cloned()) + } + + fn create_scope_for( + &mut self, + scope: &str, + owners: &ScopeOwners, + ) -> Result { + self.packages + .insert(scope.to_string(), (owners.clone(), IndexFile::default())); + Ok(true) + } + + fn package(&self, name: &PackageName) -> Result, IndexPackageError> { + Ok(self + .packages + .get(name.scope()) + .map(|(_, file)| file.clone())) + } + + fn create_package_version( + &mut self, + manifest: &Manifest, + uploader: &u64, + ) -> Result { + let scope = manifest.name.scope(); + + if let Some(owners) = self.scope_owners(scope)? { + if !owners.contains(uploader) { + return Err(CreatePackageVersionError::MissingScopeOwnership); + } + } else if !self.create_scope_for(scope, &BTreeSet::from([*uploader]))? { + return Err(CreatePackageVersionError::MissingScopeOwnership); + } + + let package = self.packages.get_mut(scope).unwrap(); + + package.1.push(manifest.clone().into()); + + Ok(true) + } + + fn config(&self) -> Result { + Ok(IndexConfig { + download: None, + api: "http://127.0.0.1:8080".to_string(), + github_oauth_client_id: "".to_string(), + custom_registry_allowed: false, + git_allowed: false, + }) + } + + fn credentials_fn(&self) -> Option<&Arc> { + None + } +} diff --git a/tests/resolver.rs b/tests/resolver.rs new file mode 100644 index 0000000..3bfb6e5 --- /dev/null +++ b/tests/resolver.rs @@ -0,0 +1,118 @@ +use std::collections::BTreeSet; + +use semver::Version; +use tempfile::tempdir; + +use pesde::{ + dependencies::{ + registry::{RegistryDependencySpecifier, RegistryPackageRef}, + resolution::ResolvedPackage, + DependencySpecifier, PackageRef, + }, + manifest::{DependencyType, Manifest, Realm}, + package_name::PackageName, + project::Project, +}; +use prelude::*; + +mod prelude; + +#[test] +fn test_resolves_package() { + let dir = tempdir().unwrap(); + let dir_path = dir.path().to_path_buf(); + let index = InMemoryIndex::new(); + + let version_str = "0.1.0"; + let version: Version = version_str.parse().unwrap(); + let version_2_str = "0.1.1"; + let version_2: Version = version_2_str.parse().unwrap(); + + let description = "test package"; + + let pkg_name = PackageName::new("test", "test").unwrap(); + + let pkg_manifest = Manifest { + name: pkg_name.clone(), + version: version.clone(), + exports: Default::default(), + path_style: Default::default(), + private: true, + realm: None, + dependencies: vec![], + peer_dependencies: vec![], + description: Some(description.to_string()), + license: None, + authors: None, + }; + + let mut pkg_2_manifest = pkg_manifest.clone(); + pkg_2_manifest.version = version_2.clone(); + + let index = index + .with_scope(pkg_name.scope(), BTreeSet::from([0])) + .with_package(pkg_name.scope(), pkg_manifest.into()) + .with_package(pkg_name.scope(), pkg_2_manifest.into()); + + let specifier = DependencySpecifier::Registry(RegistryDependencySpecifier { + name: pkg_name.clone(), + version: format!("={version_str}").parse().unwrap(), + realm: None, + }); + let specifier_2 = DependencySpecifier::Registry(RegistryDependencySpecifier { + name: pkg_name.clone(), + version: format!(">{version_str}").parse().unwrap(), + realm: None, + }); + + let user_manifest = Manifest { + name: "test/user".parse().unwrap(), + version: version.clone(), + exports: Default::default(), + path_style: Default::default(), + private: true, + realm: None, + dependencies: vec![specifier.clone()], + peer_dependencies: vec![specifier_2.clone()], + description: Some(description.to_string()), + license: None, + authors: None, + }; + + let project = Project::new(&dir_path, &dir_path, index, user_manifest, None); + + let tree = project.manifest().dependency_tree(&project, false).unwrap(); + assert_eq!(tree.len(), 1); + let versions = tree.get(&pkg_name).unwrap(); + assert_eq!(versions.len(), 2); + let resolved_pkg = versions.get(&version).unwrap(); + assert_eq!( + resolved_pkg, + &ResolvedPackage { + pkg_ref: PackageRef::Registry(RegistryPackageRef { + name: pkg_name.clone(), + version: version.clone(), + }), + specifier, + dependencies: Default::default(), + is_root: true, + realm: Realm::Shared, + dep_type: DependencyType::Normal, + } + ); + let resolved_pkg_2 = versions.get(&version_2).unwrap(); + assert_eq!( + resolved_pkg_2, + &ResolvedPackage { + pkg_ref: PackageRef::Registry(RegistryPackageRef { + name: pkg_name.clone(), + version: version_2.clone(), + }), + specifier: specifier_2, + dependencies: Default::default(), + is_root: true, + realm: Realm::Shared, + dep_type: DependencyType::Normal, + } + ); +}