├── .bin └── chim ├── .config └── nextest.toml ├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ └── chim.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Cross.toml ├── LICENSE ├── README.md ├── RELEASING.md ├── example ├── .bin │ ├── shellcheck-linux-x64 │ └── shellcheck-macos-x64 ├── .multiarch │ ├── linux │ └── macos ├── abs ├── err ├── gcs ├── gz ├── hooks ├── jq ├── multiarch ├── node ├── node.bat ├── s3 ├── scp ├── shellcheck ├── shfmt └── xz ├── packaging ├── chimstrap │ └── chimstrap.envsubst ├── deb │ ├── Dockerfile │ └── generate-release.sh ├── macos │ └── homebrew.rb ├── rpm │ ├── Dockerfile │ ├── chim.repo │ ├── chim.spec │ └── rpmmacros └── win │ ├── environment.iss │ └── setup.iss ├── scripts ├── build-deb.sh ├── build-rpm.sh ├── build-tarball.sh ├── build-windows.ps1 ├── get-version.sh ├── release.sh ├── render-chimstrap.sh └── render-homebrew.sh ├── src ├── app.rs ├── archive.rs ├── bin.rs ├── checksum.rs ├── chim_file.rs ├── cli │ ├── checksums.rs │ ├── mod.rs │ ├── run.rs │ └── version.rs ├── config.rs ├── env.rs ├── fetchers │ ├── abs.rs │ ├── gcs.rs │ ├── http.rs │ ├── mod.rs │ ├── s3.rs │ └── scp.rs ├── hooks.rs ├── logger.rs ├── main.rs └── platform.rs └── test └── fixtures └── hooks /.bin/chim: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # add this directory to `$PATH` to automatically build/run chim 4 | # when chims are called in shebangs 5 | 6 | cargo run -- "$@" 7 | -------------------------------------------------------------------------------- /.config/nextest.toml: -------------------------------------------------------------------------------- 1 | [profile.ci] 2 | # Print out output for failing tests as soon as they fail, and also at the end 3 | # of the run (for easy scrollability). 4 | failure-output = "immediate-final" 5 | # Do not cancel the test run on the first failure. 6 | fail-fast = false 7 | retries = 2 8 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | example/.bin filter=lfs diff=lfs merge=lfs -text 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: / 5 | schedule: 6 | interval: weekly 7 | 8 | - package-ecosystem: cargo 9 | directory: / 10 | schedule: 11 | interval: weekly 12 | -------------------------------------------------------------------------------- /.github/workflows/chim.yml: -------------------------------------------------------------------------------- 1 | name: chim 2 | 3 | on: 4 | push: 5 | branches: ["main"] 6 | tags: ["v*"] 7 | pull_request: 8 | branches: ["main"] 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | env: 13 | CARGO_TERM_COLOR: always 14 | 15 | jobs: 16 | unit: 17 | runs-on: ubuntu-22.04 18 | steps: 19 | - uses: actions/checkout@v3 20 | - uses: Swatinem/rust-cache@v2 21 | - name: Install latest nextest release 22 | uses: taiki-e/install-action@nextest 23 | - name: Test with latest nextest release 24 | uses: actions-rs/cargo@v1 25 | with: 26 | command: nextest 27 | args: run --all-features --profile ci 28 | 29 | lint: 30 | runs-on: ubuntu-22.04 31 | env: 32 | RUSTFLAGS: -D warnings 33 | steps: 34 | - uses: actions/checkout@v3 35 | - uses: Swatinem/rust-cache@v2 36 | - uses: actions-rs/toolchain@v1 37 | with: 38 | toolchain: stable 39 | override: true 40 | components: rustfmt, clippy 41 | - uses: actions-rs/clippy-check@v1 42 | with: 43 | token: ${{ secrets.GITHUB_TOKEN }} 44 | args: --all-features 45 | - uses: actions-rs/cargo@v1 46 | with: 47 | command: fmt 48 | args: --all -- --check 49 | - uses: actions-rs/audit-check@v1 50 | with: 51 | token: ${{ secrets.GITHUB_TOKEN }} 52 | 53 | e2e-linux: 54 | runs-on: ubuntu-22.04 55 | needs: [build] 56 | env: 57 | AWS_ACCESS_KEY_ID: "${{ secrets.AWS_ACCESS_KEY_ID }}" 58 | AWS_SECRET_ACCESS_KEY: "${{ secrets.AWS_SECRET_ACCESS_KEY }}" 59 | AWS_DEFAULT_REGION: us-east-1 60 | steps: 61 | - uses: actions/checkout@v3 62 | - uses: "google-github-actions/auth@v1" 63 | if: github.event_name != 'pull_request' 64 | with: 65 | credentials_json: "${{ secrets.GCP_CREDENTIALS }}" 66 | service_account: "chim-test@chim-361015.iam.gserviceaccount.com" 67 | continue-on-error: true 68 | - uses: "google-github-actions/setup-gcloud@v1" 69 | - uses: actions/download-artifact@v3 70 | with: 71 | name: tarball-x86_64-unknown-linux-gnu 72 | path: dist 73 | - run: tar -C "$HOME" -xvJf dist/chim-$(./scripts/get-version.sh)-linux-x64.tar.xz 74 | - run: echo "$HOME/chim/bin" >> $GITHUB_PATH 75 | - run: chim -v 76 | - name: shellcheck 77 | if: success() || failure() 78 | run: | 79 | ./example/shellcheck \ 80 | packaging/chimstrap/chimstrap.envsubst \ 81 | scripts/*.sh 82 | - name: shfmt 83 | if: success() || failure() 84 | run: | 85 | ./example/shfmt \ 86 | packaging/chimstrap/chimstrap.envsubst \ 87 | scripts/*.sh 88 | - run: ./example/multiarch abc123 89 | if: success() || failure() 90 | - run: ./example/node -v 91 | if: success() || failure() 92 | - run: ./example/gz -v 93 | if: success() || failure() 94 | - run: ./example/xz -v 95 | if: success() || failure() 96 | - run: ./example/abs -v 97 | if: success() || failure() 98 | - run: ./example/jq -V 99 | if: success() || failure() 100 | - run: ./example/s3 -v 101 | if: github.event_name != 'pull_request' 102 | - run: ./example/gcs -v 103 | if: github.event_name != 'pull_request' 104 | 105 | e2e-macos: 106 | runs-on: macos-12 107 | needs: [build-macos] 108 | env: 109 | AWS_ACCESS_KEY_ID: "${{ secrets.AWS_ACCESS_KEY_ID }}" 110 | AWS_SECRET_ACCESS_KEY: "${{ secrets.AWS_SECRET_ACCESS_KEY }}" 111 | AWS_DEFAULT_REGION: us-east-1 112 | steps: 113 | - uses: actions/checkout@v3 114 | - uses: "google-github-actions/auth@v1" 115 | if: github.event_name != 'pull_request' 116 | continue-on-error: true 117 | with: 118 | credentials_json: "${{ secrets.GCP_CREDENTIALS }}" 119 | service_account: "chim-test@chim-361015.iam.gserviceaccount.com" 120 | - uses: "google-github-actions/setup-gcloud@v1" 121 | - uses: actions/download-artifact@v3 122 | with: 123 | name: tarball-x86_64-apple-darwin 124 | path: dist 125 | - run: tar -C "$HOME" -xvJf dist/chim-$(./scripts/get-version.sh)-macos-x64.tar.xz 126 | - run: echo "$HOME/chim/bin" >> $GITHUB_PATH 127 | - run: chim -v 128 | - name: shellcheck 129 | run: | 130 | ./example/shellcheck \ 131 | packaging/chimstrap/chimstrap.envsubst \ 132 | scripts/*.sh 133 | if: success() || failure() 134 | - run: ./example/multiarch abc123 135 | if: success() || failure() 136 | - run: ./example/node -v 137 | if: success() || failure() 138 | - run: ./example/gz -v 139 | if: success() || failure() 140 | - run: ./example/xz -v 141 | if: success() || failure() 142 | - run: ./example/abs -v 143 | if: success() || failure() 144 | - run: ./example/jq -V 145 | if: success() || failure() 146 | - run: ./example/s3 -v 147 | if: github.event_name != 'pull_request' 148 | - run: ./example/gcs -v 149 | if: github.event_name != 'pull_request' 150 | 151 | e2e-win: 152 | runs-on: windows-latest 153 | needs: [build-x86_64-pc-windows-gnu] 154 | steps: 155 | - uses: actions/checkout@v3 156 | - uses: actions/download-artifact@v3 157 | with: 158 | name: setup-x86_64-pc-windows-gnu 159 | path: dist 160 | - run: dist\chim-setup.exe /SILENT 161 | - run: echo "C:\Program Files (x86)\chim\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 162 | - run: chim -v 163 | - run: .\example\node -v 164 | 165 | e2e-chimstrap: 166 | runs-on: ubuntu-22.04 167 | needs: [build] 168 | steps: 169 | - uses: actions/checkout@v3 170 | - uses: actions/download-artifact@v3 171 | with: 172 | name: tarball-x86_64-unknown-linux-gnu 173 | path: dist 174 | - name: Build and run chimstrap 175 | run: | 176 | set -x 177 | export CHIM_VERSION=$(./scripts/get-version.sh) 178 | export CHIMSTRAP_URL="http://localhost:3000/dist/chim-$CHIM_VERSION-linux-x64.tar.gz" 179 | python3 -m http.server 3000 & 180 | sleep 1 181 | ./packaging/chimstrap/chimstrap.envsubst ./example/node -v 182 | 183 | coverage: 184 | runs-on: ubuntu-22.04 185 | needs: [unit, lint] 186 | container: 187 | image: xd009642/tarpaulin:develop-nightly 188 | options: --security-opt seccomp=unconfined 189 | steps: 190 | - uses: actions/checkout@v3 191 | - uses: Swatinem/rust-cache@v2 192 | - name: Generate code coverage 193 | run: | 194 | cargo +nightly tarpaulin \ 195 | --all-features --workspace \ 196 | --timeout 120 --out Xml --ignore-tests \ 197 | --exclude-files 'src/fetchers/*' 198 | - name: Upload to codecov.io 199 | uses: codecov/codecov-action@v3 200 | with: 201 | fail_ci_if_error: false 202 | 203 | build: 204 | name: build-${{matrix.target}} 205 | runs-on: ubuntu-22.04 206 | needs: [unit, lint] 207 | strategy: 208 | fail-fast: false 209 | matrix: 210 | target: 211 | - aarch64-unknown-linux-gnu 212 | - x86_64-unknown-linux-gnu 213 | steps: 214 | - uses: actions/checkout@v3 215 | - uses: actions-rs/toolchain@v1 216 | with: 217 | toolchain: stable 218 | target: ${{matrix.target}} 219 | override: true 220 | - uses: Swatinem/rust-cache@v2 221 | with: { key: "${{matrix.target}}" } 222 | - uses: actions-rs/cargo@v1 223 | with: 224 | use-cross: true 225 | command: build 226 | args: --release --target ${{matrix.target}} 227 | - run: scripts/build-tarball.sh ${{matrix.target}} 228 | - uses: actions/upload-artifact@v3 229 | with: 230 | name: tarball-${{matrix.target}} 231 | path: | 232 | dist/chim-*.tar.xz 233 | dist/chim-*.tar.gz 234 | if-no-files-found: error 235 | 236 | build-macos: 237 | name: build-${{matrix.target}} 238 | runs-on: macos-12 239 | needs: [unit, lint] 240 | strategy: 241 | fail-fast: false 242 | matrix: 243 | target: 244 | - x86_64-apple-darwin 245 | - aarch64-apple-darwin 246 | steps: 247 | - uses: actions/checkout@v3 248 | - uses: actions-rs/toolchain@v1 249 | with: 250 | toolchain: stable 251 | target: ${{matrix.target}} 252 | override: true 253 | - uses: Swatinem/rust-cache@v2 254 | with: { key: "${{matrix.target}}" } 255 | - run: cargo build --release --target ${{matrix.target}} 256 | - run: scripts/build-tarball.sh ${{matrix.target}} 257 | - uses: actions/upload-artifact@v3 258 | with: 259 | name: tarball-${{matrix.target}} 260 | path: | 261 | dist/chim-*.tar.xz 262 | dist/chim-*.tar.gz 263 | if-no-files-found: error 264 | 265 | build-x86_64-pc-windows-gnu: 266 | runs-on: windows-2022 267 | needs: [unit, lint] 268 | steps: 269 | - uses: actions/checkout@v3 270 | - uses: Swatinem/rust-cache@v2 271 | - uses: actions-rs/cargo@v1 272 | with: 273 | command: build 274 | args: --no-default-features --release 275 | - run: Invoke-Expression "cargo install cargo-get" -ErrorAction SilentlyContinue 276 | - run: scripts/build-windows.ps1 277 | - run: iscc packaging\win\setup.iss 278 | - uses: actions/upload-artifact@v3 279 | with: 280 | name: tarball-x86_64-pc-windows-gnu 281 | path: dist/chim-*.zip 282 | if-no-files-found: error 283 | - uses: actions/upload-artifact@v3 284 | with: 285 | name: setup-x86_64-pc-windows-gnu 286 | path: dist/chim-setup.exe 287 | if-no-files-found: error 288 | 289 | rpm: 290 | runs-on: ubuntu-22.04 291 | needs: [build] 292 | container: jdxcode/chim:rpm 293 | if: github.event_name != 'pull_request' 294 | steps: 295 | - uses: actions/checkout@v3 296 | - uses: crazy-max/ghaction-import-gpg@v5 297 | with: 298 | gpg_private_key: ${{ secrets.GPG_KEY }} 299 | - uses: actions/download-artifact@v3 300 | with: 301 | name: tarball-x86_64-unknown-linux-gnu 302 | path: dist 303 | - uses: actions/download-artifact@v3 304 | with: 305 | name: tarball-aarch64-unknown-linux-gnu 306 | path: dist 307 | - run: scripts/build-rpm.sh 308 | - uses: actions/upload-artifact@v3 309 | with: 310 | name: rpm 311 | path: dist/rpmrepo 312 | if-no-files-found: error 313 | 314 | deb: 315 | runs-on: ubuntu-22.04 316 | container: jdxcode/chim:deb 317 | if: github.event_name != 'pull_request' 318 | needs: [build] 319 | steps: 320 | - uses: actions/checkout@v3 321 | - uses: crazy-max/ghaction-import-gpg@v5 322 | with: 323 | gpg_private_key: ${{ secrets.GPG_KEY }} 324 | - uses: actions/download-artifact@v3 325 | with: 326 | name: tarball-x86_64-unknown-linux-gnu 327 | path: dist 328 | - uses: actions/download-artifact@v3 329 | with: 330 | name: tarball-aarch64-unknown-linux-gnu 331 | path: dist 332 | - run: scripts/build-deb.sh 333 | - uses: actions/upload-artifact@v3 334 | with: 335 | name: deb 336 | path: dist/deb 337 | if-no-files-found: error 338 | 339 | release: 340 | runs-on: ubuntu-22.04 341 | if: startsWith(github.event.ref, 'refs/tags/v') 342 | needs: 343 | - e2e-linux 344 | - e2e-win 345 | - e2e-macos 346 | - e2e-chimstrap 347 | - rpm 348 | - deb 349 | steps: 350 | - uses: actions/checkout@v3 351 | with: 352 | path: chim 353 | - uses: actions/checkout@v3 354 | with: 355 | repository: jdxcode/chim.sh 356 | path: chim.sh 357 | token: ${{ secrets.CHIM_GITHUB_BOT_TOKEN }} 358 | - uses: actions/checkout@v3 359 | with: 360 | repository: jdxcode/homebrew-tap 361 | path: homebrew-tap 362 | token: ${{ secrets.CHIM_GITHUB_BOT_TOKEN }} 363 | - uses: crazy-max/ghaction-import-gpg@v5 364 | with: 365 | gpg_private_key: ${{ secrets.GPG_KEY }} 366 | git_user_signingkey: true 367 | git_commit_gpgsign: true 368 | workdir: chim.sh 369 | - uses: actions/download-artifact@v3 370 | with: { path: artifacts } 371 | - run: chim/scripts/release.sh 372 | - name: chim.sh push 373 | run: git push 374 | working-directory: chim.sh 375 | - name: homebrew-tap push 376 | run: git push 377 | working-directory: homebrew-tap 378 | 379 | - name: GitHub Release Assets 380 | uses: softprops/action-gh-release@v1 381 | if: startsWith(github.event.ref, 'refs/tags/v') 382 | with: 383 | fail_on_unmatched_files: true 384 | draft: true 385 | files: chim.sh/static/releases/${{github.ref_name}}/* 386 | generate_release_notes: true 387 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/*.rs.bk 2 | 3 | /.idea/ 4 | /target/ 5 | /dist/ 6 | /.gpgkey 7 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.17.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "aho-corasick" 22 | version = "0.7.19" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" 25 | dependencies = [ 26 | "memchr", 27 | ] 28 | 29 | [[package]] 30 | name = "anstream" 31 | version = "0.3.0" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "9e579a7752471abc2a8268df8b20005e3eadd975f585398f17efcfd8d4927371" 34 | dependencies = [ 35 | "anstyle", 36 | "anstyle-parse", 37 | "anstyle-query", 38 | "anstyle-wincon", 39 | "colorchoice", 40 | "is-terminal", 41 | "utf8parse", 42 | ] 43 | 44 | [[package]] 45 | name = "anstyle" 46 | version = "1.0.0" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" 49 | 50 | [[package]] 51 | name = "anstyle-parse" 52 | version = "0.2.0" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" 55 | dependencies = [ 56 | "utf8parse", 57 | ] 58 | 59 | [[package]] 60 | name = "anstyle-query" 61 | version = "1.0.0" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" 64 | dependencies = [ 65 | "windows-sys 0.48.0", 66 | ] 67 | 68 | [[package]] 69 | name = "anstyle-wincon" 70 | version = "1.0.0" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | checksum = "4bcd8291a340dd8ac70e18878bc4501dd7b4ff970cfa21c207d36ece51ea88fd" 73 | dependencies = [ 74 | "anstyle", 75 | "windows-sys 0.48.0", 76 | ] 77 | 78 | [[package]] 79 | name = "autocfg" 80 | version = "1.1.0" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 83 | 84 | [[package]] 85 | name = "backtrace" 86 | version = "0.3.66" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" 89 | dependencies = [ 90 | "addr2line", 91 | "cc", 92 | "cfg-if", 93 | "libc", 94 | "miniz_oxide 0.5.4", 95 | "object", 96 | "rustc-demangle", 97 | ] 98 | 99 | [[package]] 100 | name = "base64" 101 | version = "0.13.0" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 104 | 105 | [[package]] 106 | name = "base64" 107 | version = "0.21.0" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" 110 | 111 | [[package]] 112 | name = "bitflags" 113 | version = "1.3.2" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 116 | 117 | [[package]] 118 | name = "block-buffer" 119 | version = "0.10.3" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" 122 | dependencies = [ 123 | "generic-array", 124 | ] 125 | 126 | [[package]] 127 | name = "bumpalo" 128 | version = "3.12.0" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" 131 | 132 | [[package]] 133 | name = "byteorder" 134 | version = "1.4.3" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 137 | 138 | [[package]] 139 | name = "bytes" 140 | version = "1.2.1" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" 143 | 144 | [[package]] 145 | name = "bzip2" 146 | version = "0.4.4" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" 149 | dependencies = [ 150 | "bzip2-sys", 151 | "libc", 152 | ] 153 | 154 | [[package]] 155 | name = "bzip2-sys" 156 | version = "0.1.11+1.0.8" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" 159 | dependencies = [ 160 | "cc", 161 | "libc", 162 | "pkg-config", 163 | ] 164 | 165 | [[package]] 166 | name = "cc" 167 | version = "1.0.73" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" 170 | 171 | [[package]] 172 | name = "cfg-if" 173 | version = "1.0.0" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 176 | 177 | [[package]] 178 | name = "chim" 179 | version = "1.1.1" 180 | dependencies = [ 181 | "bzip2", 182 | "clap", 183 | "color-eyre", 184 | "dirs", 185 | "env_logger", 186 | "exec", 187 | "flate2", 188 | "hex", 189 | "indicatif", 190 | "itertools", 191 | "log", 192 | "pretty_assertions", 193 | "rand", 194 | "reqwest", 195 | "serde", 196 | "serde_derive", 197 | "sha2", 198 | "tar", 199 | "tempfile", 200 | "test-case", 201 | "tokio", 202 | "toml", 203 | "toml_edit", 204 | "xz", 205 | "zip", 206 | ] 207 | 208 | [[package]] 209 | name = "clap" 210 | version = "4.3.8" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "d9394150f5b4273a1763355bd1c2ec54cc5a2593f790587bcd6b2c947cfa9211" 213 | dependencies = [ 214 | "clap_builder", 215 | "clap_derive", 216 | "once_cell", 217 | ] 218 | 219 | [[package]] 220 | name = "clap_builder" 221 | version = "4.3.8" 222 | source = "registry+https://github.com/rust-lang/crates.io-index" 223 | checksum = "9a78fbdd3cc2914ddf37ba444114bc7765bbdcb55ec9cbe6fa054f0137400717" 224 | dependencies = [ 225 | "anstream", 226 | "anstyle", 227 | "bitflags", 228 | "clap_lex", 229 | "strsim", 230 | ] 231 | 232 | [[package]] 233 | name = "clap_derive" 234 | version = "4.3.2" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" 237 | dependencies = [ 238 | "heck", 239 | "proc-macro2", 240 | "quote", 241 | "syn 2.0.10", 242 | ] 243 | 244 | [[package]] 245 | name = "clap_lex" 246 | version = "0.5.0" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" 249 | 250 | [[package]] 251 | name = "color-eyre" 252 | version = "0.6.2" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204" 255 | dependencies = [ 256 | "backtrace", 257 | "color-spantrace", 258 | "eyre", 259 | "indenter", 260 | "once_cell", 261 | "owo-colors", 262 | "tracing-error", 263 | ] 264 | 265 | [[package]] 266 | name = "color-spantrace" 267 | version = "0.2.0" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce" 270 | dependencies = [ 271 | "once_cell", 272 | "owo-colors", 273 | "tracing-core", 274 | "tracing-error", 275 | ] 276 | 277 | [[package]] 278 | name = "colorchoice" 279 | version = "1.0.0" 280 | source = "registry+https://github.com/rust-lang/crates.io-index" 281 | checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" 282 | 283 | [[package]] 284 | name = "console" 285 | version = "0.15.1" 286 | source = "registry+https://github.com/rust-lang/crates.io-index" 287 | checksum = "89eab4d20ce20cea182308bca13088fecea9c05f6776cf287205d41a0ed3c847" 288 | dependencies = [ 289 | "encode_unicode", 290 | "libc", 291 | "once_cell", 292 | "terminal_size", 293 | "unicode-width", 294 | "winapi", 295 | ] 296 | 297 | [[package]] 298 | name = "cpufeatures" 299 | version = "0.2.5" 300 | source = "registry+https://github.com/rust-lang/crates.io-index" 301 | checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" 302 | dependencies = [ 303 | "libc", 304 | ] 305 | 306 | [[package]] 307 | name = "crc32fast" 308 | version = "1.3.2" 309 | source = "registry+https://github.com/rust-lang/crates.io-index" 310 | checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" 311 | dependencies = [ 312 | "cfg-if", 313 | ] 314 | 315 | [[package]] 316 | name = "crossbeam-utils" 317 | version = "0.8.11" 318 | source = "registry+https://github.com/rust-lang/crates.io-index" 319 | checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" 320 | dependencies = [ 321 | "cfg-if", 322 | "once_cell", 323 | ] 324 | 325 | [[package]] 326 | name = "crypto-common" 327 | version = "0.1.6" 328 | source = "registry+https://github.com/rust-lang/crates.io-index" 329 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 330 | dependencies = [ 331 | "generic-array", 332 | "typenum", 333 | ] 334 | 335 | [[package]] 336 | name = "ctor" 337 | version = "0.1.23" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | checksum = "cdffe87e1d521a10f9696f833fe502293ea446d7f256c06128293a4119bdf4cb" 340 | dependencies = [ 341 | "quote", 342 | "syn 1.0.105", 343 | ] 344 | 345 | [[package]] 346 | name = "diff" 347 | version = "0.1.13" 348 | source = "registry+https://github.com/rust-lang/crates.io-index" 349 | checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" 350 | 351 | [[package]] 352 | name = "digest" 353 | version = "0.10.7" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 356 | dependencies = [ 357 | "block-buffer", 358 | "crypto-common", 359 | ] 360 | 361 | [[package]] 362 | name = "dirs" 363 | version = "5.0.1" 364 | source = "registry+https://github.com/rust-lang/crates.io-index" 365 | checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" 366 | dependencies = [ 367 | "dirs-sys", 368 | ] 369 | 370 | [[package]] 371 | name = "dirs-sys" 372 | version = "0.4.1" 373 | source = "registry+https://github.com/rust-lang/crates.io-index" 374 | checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" 375 | dependencies = [ 376 | "libc", 377 | "option-ext", 378 | "redox_users", 379 | "windows-sys 0.48.0", 380 | ] 381 | 382 | [[package]] 383 | name = "either" 384 | version = "1.8.0" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" 387 | 388 | [[package]] 389 | name = "encode_unicode" 390 | version = "0.3.6" 391 | source = "registry+https://github.com/rust-lang/crates.io-index" 392 | checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 393 | 394 | [[package]] 395 | name = "encoding_rs" 396 | version = "0.8.31" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" 399 | dependencies = [ 400 | "cfg-if", 401 | ] 402 | 403 | [[package]] 404 | name = "env_logger" 405 | version = "0.10.0" 406 | source = "registry+https://github.com/rust-lang/crates.io-index" 407 | checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" 408 | dependencies = [ 409 | "humantime", 410 | "is-terminal", 411 | "log", 412 | "regex", 413 | "termcolor", 414 | ] 415 | 416 | [[package]] 417 | name = "errno" 418 | version = "0.2.8" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" 421 | dependencies = [ 422 | "errno-dragonfly", 423 | "libc", 424 | "winapi", 425 | ] 426 | 427 | [[package]] 428 | name = "errno" 429 | version = "0.3.1" 430 | source = "registry+https://github.com/rust-lang/crates.io-index" 431 | checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" 432 | dependencies = [ 433 | "errno-dragonfly", 434 | "libc", 435 | "windows-sys 0.48.0", 436 | ] 437 | 438 | [[package]] 439 | name = "errno-dragonfly" 440 | version = "0.1.2" 441 | source = "registry+https://github.com/rust-lang/crates.io-index" 442 | checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" 443 | dependencies = [ 444 | "cc", 445 | "libc", 446 | ] 447 | 448 | [[package]] 449 | name = "exec" 450 | version = "0.3.1" 451 | source = "registry+https://github.com/rust-lang/crates.io-index" 452 | checksum = "886b70328cba8871bfc025858e1de4be16b1d5088f2ba50b57816f4210672615" 453 | dependencies = [ 454 | "errno 0.2.8", 455 | "libc", 456 | ] 457 | 458 | [[package]] 459 | name = "eyre" 460 | version = "0.6.8" 461 | source = "registry+https://github.com/rust-lang/crates.io-index" 462 | checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" 463 | dependencies = [ 464 | "indenter", 465 | "once_cell", 466 | ] 467 | 468 | [[package]] 469 | name = "fastrand" 470 | version = "1.8.0" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" 473 | dependencies = [ 474 | "instant", 475 | ] 476 | 477 | [[package]] 478 | name = "filetime" 479 | version = "0.2.17" 480 | source = "registry+https://github.com/rust-lang/crates.io-index" 481 | checksum = "e94a7bbaa59354bc20dd75b67f23e2797b4490e9d6928203fb105c79e448c86c" 482 | dependencies = [ 483 | "cfg-if", 484 | "libc", 485 | "redox_syscall 0.2.16", 486 | "windows-sys 0.36.1", 487 | ] 488 | 489 | [[package]] 490 | name = "flate2" 491 | version = "1.0.26" 492 | source = "registry+https://github.com/rust-lang/crates.io-index" 493 | checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" 494 | dependencies = [ 495 | "crc32fast", 496 | "miniz_oxide 0.7.1", 497 | ] 498 | 499 | [[package]] 500 | name = "fnv" 501 | version = "1.0.7" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 504 | 505 | [[package]] 506 | name = "form_urlencoded" 507 | version = "1.0.1" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" 510 | dependencies = [ 511 | "matches", 512 | "percent-encoding", 513 | ] 514 | 515 | [[package]] 516 | name = "futures-channel" 517 | version = "0.3.24" 518 | source = "registry+https://github.com/rust-lang/crates.io-index" 519 | checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050" 520 | dependencies = [ 521 | "futures-core", 522 | ] 523 | 524 | [[package]] 525 | name = "futures-core" 526 | version = "0.3.24" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf" 529 | 530 | [[package]] 531 | name = "futures-sink" 532 | version = "0.3.24" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56" 535 | 536 | [[package]] 537 | name = "futures-task" 538 | version = "0.3.24" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1" 541 | 542 | [[package]] 543 | name = "futures-util" 544 | version = "0.3.24" 545 | source = "registry+https://github.com/rust-lang/crates.io-index" 546 | checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90" 547 | dependencies = [ 548 | "futures-core", 549 | "futures-task", 550 | "pin-project-lite", 551 | "pin-utils", 552 | ] 553 | 554 | [[package]] 555 | name = "generic-array" 556 | version = "0.14.6" 557 | source = "registry+https://github.com/rust-lang/crates.io-index" 558 | checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" 559 | dependencies = [ 560 | "typenum", 561 | "version_check", 562 | ] 563 | 564 | [[package]] 565 | name = "getrandom" 566 | version = "0.2.7" 567 | source = "registry+https://github.com/rust-lang/crates.io-index" 568 | checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" 569 | dependencies = [ 570 | "cfg-if", 571 | "libc", 572 | "wasi", 573 | ] 574 | 575 | [[package]] 576 | name = "gimli" 577 | version = "0.26.2" 578 | source = "registry+https://github.com/rust-lang/crates.io-index" 579 | checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" 580 | 581 | [[package]] 582 | name = "h2" 583 | version = "0.3.17" 584 | source = "registry+https://github.com/rust-lang/crates.io-index" 585 | checksum = "66b91535aa35fea1523ad1b86cb6b53c28e0ae566ba4a460f4457e936cad7c6f" 586 | dependencies = [ 587 | "bytes", 588 | "fnv", 589 | "futures-core", 590 | "futures-sink", 591 | "futures-util", 592 | "http", 593 | "indexmap", 594 | "slab", 595 | "tokio", 596 | "tokio-util", 597 | "tracing", 598 | ] 599 | 600 | [[package]] 601 | name = "hashbrown" 602 | version = "0.12.3" 603 | source = "registry+https://github.com/rust-lang/crates.io-index" 604 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 605 | 606 | [[package]] 607 | name = "heck" 608 | version = "0.4.0" 609 | source = "registry+https://github.com/rust-lang/crates.io-index" 610 | checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" 611 | 612 | [[package]] 613 | name = "hermit-abi" 614 | version = "0.1.19" 615 | source = "registry+https://github.com/rust-lang/crates.io-index" 616 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 617 | dependencies = [ 618 | "libc", 619 | ] 620 | 621 | [[package]] 622 | name = "hermit-abi" 623 | version = "0.3.1" 624 | source = "registry+https://github.com/rust-lang/crates.io-index" 625 | checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" 626 | 627 | [[package]] 628 | name = "hex" 629 | version = "0.4.3" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 632 | 633 | [[package]] 634 | name = "http" 635 | version = "0.2.8" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" 638 | dependencies = [ 639 | "bytes", 640 | "fnv", 641 | "itoa", 642 | ] 643 | 644 | [[package]] 645 | name = "http-body" 646 | version = "0.4.5" 647 | source = "registry+https://github.com/rust-lang/crates.io-index" 648 | checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" 649 | dependencies = [ 650 | "bytes", 651 | "http", 652 | "pin-project-lite", 653 | ] 654 | 655 | [[package]] 656 | name = "httparse" 657 | version = "1.8.0" 658 | source = "registry+https://github.com/rust-lang/crates.io-index" 659 | checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" 660 | 661 | [[package]] 662 | name = "httpdate" 663 | version = "1.0.2" 664 | source = "registry+https://github.com/rust-lang/crates.io-index" 665 | checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" 666 | 667 | [[package]] 668 | name = "humantime" 669 | version = "2.1.0" 670 | source = "registry+https://github.com/rust-lang/crates.io-index" 671 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 672 | 673 | [[package]] 674 | name = "hyper" 675 | version = "0.14.20" 676 | source = "registry+https://github.com/rust-lang/crates.io-index" 677 | checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" 678 | dependencies = [ 679 | "bytes", 680 | "futures-channel", 681 | "futures-core", 682 | "futures-util", 683 | "h2", 684 | "http", 685 | "http-body", 686 | "httparse", 687 | "httpdate", 688 | "itoa", 689 | "pin-project-lite", 690 | "socket2", 691 | "tokio", 692 | "tower-service", 693 | "tracing", 694 | "want", 695 | ] 696 | 697 | [[package]] 698 | name = "hyper-rustls" 699 | version = "0.24.0" 700 | source = "registry+https://github.com/rust-lang/crates.io-index" 701 | checksum = "0646026eb1b3eea4cd9ba47912ea5ce9cc07713d105b1a14698f4e6433d348b7" 702 | dependencies = [ 703 | "http", 704 | "hyper", 705 | "rustls", 706 | "tokio", 707 | "tokio-rustls", 708 | ] 709 | 710 | [[package]] 711 | name = "idna" 712 | version = "0.2.3" 713 | source = "registry+https://github.com/rust-lang/crates.io-index" 714 | checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" 715 | dependencies = [ 716 | "matches", 717 | "unicode-bidi", 718 | "unicode-normalization", 719 | ] 720 | 721 | [[package]] 722 | name = "indenter" 723 | version = "0.3.3" 724 | source = "registry+https://github.com/rust-lang/crates.io-index" 725 | checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" 726 | 727 | [[package]] 728 | name = "indexmap" 729 | version = "1.9.1" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" 732 | dependencies = [ 733 | "autocfg", 734 | "hashbrown", 735 | ] 736 | 737 | [[package]] 738 | name = "indicatif" 739 | version = "0.17.5" 740 | source = "registry+https://github.com/rust-lang/crates.io-index" 741 | checksum = "8ff8cc23a7393a397ed1d7f56e6365cba772aba9f9912ab968b03043c395d057" 742 | dependencies = [ 743 | "console", 744 | "instant", 745 | "number_prefix", 746 | "portable-atomic", 747 | "unicode-width", 748 | ] 749 | 750 | [[package]] 751 | name = "instant" 752 | version = "0.1.12" 753 | source = "registry+https://github.com/rust-lang/crates.io-index" 754 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 755 | dependencies = [ 756 | "cfg-if", 757 | ] 758 | 759 | [[package]] 760 | name = "io-lifetimes" 761 | version = "1.0.11" 762 | source = "registry+https://github.com/rust-lang/crates.io-index" 763 | checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" 764 | dependencies = [ 765 | "hermit-abi 0.3.1", 766 | "libc", 767 | "windows-sys 0.48.0", 768 | ] 769 | 770 | [[package]] 771 | name = "ipnet" 772 | version = "2.5.0" 773 | source = "registry+https://github.com/rust-lang/crates.io-index" 774 | checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" 775 | 776 | [[package]] 777 | name = "is-terminal" 778 | version = "0.4.6" 779 | source = "registry+https://github.com/rust-lang/crates.io-index" 780 | checksum = "256017f749ab3117e93acb91063009e1f1bb56d03965b14c2c8df4eb02c524d8" 781 | dependencies = [ 782 | "hermit-abi 0.3.1", 783 | "io-lifetimes", 784 | "rustix", 785 | "windows-sys 0.45.0", 786 | ] 787 | 788 | [[package]] 789 | name = "itertools" 790 | version = "0.10.5" 791 | source = "registry+https://github.com/rust-lang/crates.io-index" 792 | checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" 793 | dependencies = [ 794 | "either", 795 | ] 796 | 797 | [[package]] 798 | name = "itoa" 799 | version = "1.0.3" 800 | source = "registry+https://github.com/rust-lang/crates.io-index" 801 | checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" 802 | 803 | [[package]] 804 | name = "js-sys" 805 | version = "0.3.59" 806 | source = "registry+https://github.com/rust-lang/crates.io-index" 807 | checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" 808 | dependencies = [ 809 | "wasm-bindgen", 810 | ] 811 | 812 | [[package]] 813 | name = "lazy_static" 814 | version = "1.4.0" 815 | source = "registry+https://github.com/rust-lang/crates.io-index" 816 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 817 | 818 | [[package]] 819 | name = "libc" 820 | version = "0.2.146" 821 | source = "registry+https://github.com/rust-lang/crates.io-index" 822 | checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" 823 | 824 | [[package]] 825 | name = "linux-raw-sys" 826 | version = "0.3.8" 827 | source = "registry+https://github.com/rust-lang/crates.io-index" 828 | checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" 829 | 830 | [[package]] 831 | name = "lock_api" 832 | version = "0.4.8" 833 | source = "registry+https://github.com/rust-lang/crates.io-index" 834 | checksum = "9f80bf5aacaf25cbfc8210d1cfb718f2bf3b11c4c54e5afe36c236853a8ec390" 835 | dependencies = [ 836 | "autocfg", 837 | "scopeguard", 838 | ] 839 | 840 | [[package]] 841 | name = "log" 842 | version = "0.4.19" 843 | source = "registry+https://github.com/rust-lang/crates.io-index" 844 | checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" 845 | 846 | [[package]] 847 | name = "lzma-sys" 848 | version = "0.1.19" 849 | source = "registry+https://github.com/rust-lang/crates.io-index" 850 | checksum = "e06754c4acf47d49c727d5665ca9fb828851cda315ed3bd51edd148ef78a8772" 851 | dependencies = [ 852 | "cc", 853 | "libc", 854 | "pkg-config", 855 | ] 856 | 857 | [[package]] 858 | name = "matches" 859 | version = "0.1.9" 860 | source = "registry+https://github.com/rust-lang/crates.io-index" 861 | checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" 862 | 863 | [[package]] 864 | name = "memchr" 865 | version = "2.5.0" 866 | source = "registry+https://github.com/rust-lang/crates.io-index" 867 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 868 | 869 | [[package]] 870 | name = "mime" 871 | version = "0.3.16" 872 | source = "registry+https://github.com/rust-lang/crates.io-index" 873 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" 874 | 875 | [[package]] 876 | name = "miniz_oxide" 877 | version = "0.5.4" 878 | source = "registry+https://github.com/rust-lang/crates.io-index" 879 | checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" 880 | dependencies = [ 881 | "adler", 882 | ] 883 | 884 | [[package]] 885 | name = "miniz_oxide" 886 | version = "0.7.1" 887 | source = "registry+https://github.com/rust-lang/crates.io-index" 888 | checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" 889 | dependencies = [ 890 | "adler", 891 | ] 892 | 893 | [[package]] 894 | name = "mio" 895 | version = "0.8.4" 896 | source = "registry+https://github.com/rust-lang/crates.io-index" 897 | checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" 898 | dependencies = [ 899 | "libc", 900 | "log", 901 | "wasi", 902 | "windows-sys 0.36.1", 903 | ] 904 | 905 | [[package]] 906 | name = "num_cpus" 907 | version = "1.13.1" 908 | source = "registry+https://github.com/rust-lang/crates.io-index" 909 | checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" 910 | dependencies = [ 911 | "hermit-abi 0.1.19", 912 | "libc", 913 | ] 914 | 915 | [[package]] 916 | name = "number_prefix" 917 | version = "0.4.0" 918 | source = "registry+https://github.com/rust-lang/crates.io-index" 919 | checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" 920 | 921 | [[package]] 922 | name = "object" 923 | version = "0.29.0" 924 | source = "registry+https://github.com/rust-lang/crates.io-index" 925 | checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" 926 | dependencies = [ 927 | "memchr", 928 | ] 929 | 930 | [[package]] 931 | name = "once_cell" 932 | version = "1.14.0" 933 | source = "registry+https://github.com/rust-lang/crates.io-index" 934 | checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" 935 | 936 | [[package]] 937 | name = "option-ext" 938 | version = "0.2.0" 939 | source = "registry+https://github.com/rust-lang/crates.io-index" 940 | checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" 941 | 942 | [[package]] 943 | name = "output_vt100" 944 | version = "0.1.3" 945 | source = "registry+https://github.com/rust-lang/crates.io-index" 946 | checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" 947 | dependencies = [ 948 | "winapi", 949 | ] 950 | 951 | [[package]] 952 | name = "owo-colors" 953 | version = "3.5.0" 954 | source = "registry+https://github.com/rust-lang/crates.io-index" 955 | checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" 956 | 957 | [[package]] 958 | name = "parking_lot" 959 | version = "0.12.1" 960 | source = "registry+https://github.com/rust-lang/crates.io-index" 961 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" 962 | dependencies = [ 963 | "lock_api", 964 | "parking_lot_core", 965 | ] 966 | 967 | [[package]] 968 | name = "parking_lot_core" 969 | version = "0.9.3" 970 | source = "registry+https://github.com/rust-lang/crates.io-index" 971 | checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" 972 | dependencies = [ 973 | "cfg-if", 974 | "libc", 975 | "redox_syscall 0.2.16", 976 | "smallvec", 977 | "windows-sys 0.36.1", 978 | ] 979 | 980 | [[package]] 981 | name = "percent-encoding" 982 | version = "2.1.0" 983 | source = "registry+https://github.com/rust-lang/crates.io-index" 984 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 985 | 986 | [[package]] 987 | name = "pin-project-lite" 988 | version = "0.2.9" 989 | source = "registry+https://github.com/rust-lang/crates.io-index" 990 | checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" 991 | 992 | [[package]] 993 | name = "pin-utils" 994 | version = "0.1.0" 995 | source = "registry+https://github.com/rust-lang/crates.io-index" 996 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 997 | 998 | [[package]] 999 | name = "pkg-config" 1000 | version = "0.3.25" 1001 | source = "registry+https://github.com/rust-lang/crates.io-index" 1002 | checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" 1003 | 1004 | [[package]] 1005 | name = "portable-atomic" 1006 | version = "1.3.2" 1007 | source = "registry+https://github.com/rust-lang/crates.io-index" 1008 | checksum = "dc59d1bcc64fc5d021d67521f818db868368028108d37f0e98d74e33f68297b5" 1009 | 1010 | [[package]] 1011 | name = "ppv-lite86" 1012 | version = "0.2.16" 1013 | source = "registry+https://github.com/rust-lang/crates.io-index" 1014 | checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" 1015 | 1016 | [[package]] 1017 | name = "pretty_assertions" 1018 | version = "1.3.0" 1019 | source = "registry+https://github.com/rust-lang/crates.io-index" 1020 | checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" 1021 | dependencies = [ 1022 | "ctor", 1023 | "diff", 1024 | "output_vt100", 1025 | "yansi", 1026 | ] 1027 | 1028 | [[package]] 1029 | name = "proc-macro-error" 1030 | version = "1.0.4" 1031 | source = "registry+https://github.com/rust-lang/crates.io-index" 1032 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 1033 | dependencies = [ 1034 | "proc-macro-error-attr", 1035 | "proc-macro2", 1036 | "quote", 1037 | "syn 1.0.105", 1038 | "version_check", 1039 | ] 1040 | 1041 | [[package]] 1042 | name = "proc-macro-error-attr" 1043 | version = "1.0.4" 1044 | source = "registry+https://github.com/rust-lang/crates.io-index" 1045 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 1046 | dependencies = [ 1047 | "proc-macro2", 1048 | "quote", 1049 | "version_check", 1050 | ] 1051 | 1052 | [[package]] 1053 | name = "proc-macro2" 1054 | version = "1.0.54" 1055 | source = "registry+https://github.com/rust-lang/crates.io-index" 1056 | checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534" 1057 | dependencies = [ 1058 | "unicode-ident", 1059 | ] 1060 | 1061 | [[package]] 1062 | name = "quote" 1063 | version = "1.0.26" 1064 | source = "registry+https://github.com/rust-lang/crates.io-index" 1065 | checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" 1066 | dependencies = [ 1067 | "proc-macro2", 1068 | ] 1069 | 1070 | [[package]] 1071 | name = "rand" 1072 | version = "0.8.5" 1073 | source = "registry+https://github.com/rust-lang/crates.io-index" 1074 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1075 | dependencies = [ 1076 | "libc", 1077 | "rand_chacha", 1078 | "rand_core", 1079 | ] 1080 | 1081 | [[package]] 1082 | name = "rand_chacha" 1083 | version = "0.3.1" 1084 | source = "registry+https://github.com/rust-lang/crates.io-index" 1085 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1086 | dependencies = [ 1087 | "ppv-lite86", 1088 | "rand_core", 1089 | ] 1090 | 1091 | [[package]] 1092 | name = "rand_core" 1093 | version = "0.6.3" 1094 | source = "registry+https://github.com/rust-lang/crates.io-index" 1095 | checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" 1096 | dependencies = [ 1097 | "getrandom", 1098 | ] 1099 | 1100 | [[package]] 1101 | name = "redox_syscall" 1102 | version = "0.2.16" 1103 | source = "registry+https://github.com/rust-lang/crates.io-index" 1104 | checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" 1105 | dependencies = [ 1106 | "bitflags", 1107 | ] 1108 | 1109 | [[package]] 1110 | name = "redox_syscall" 1111 | version = "0.3.5" 1112 | source = "registry+https://github.com/rust-lang/crates.io-index" 1113 | checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" 1114 | dependencies = [ 1115 | "bitflags", 1116 | ] 1117 | 1118 | [[package]] 1119 | name = "redox_users" 1120 | version = "0.4.3" 1121 | source = "registry+https://github.com/rust-lang/crates.io-index" 1122 | checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" 1123 | dependencies = [ 1124 | "getrandom", 1125 | "redox_syscall 0.2.16", 1126 | "thiserror", 1127 | ] 1128 | 1129 | [[package]] 1130 | name = "regex" 1131 | version = "1.6.0" 1132 | source = "registry+https://github.com/rust-lang/crates.io-index" 1133 | checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" 1134 | dependencies = [ 1135 | "aho-corasick", 1136 | "memchr", 1137 | "regex-syntax", 1138 | ] 1139 | 1140 | [[package]] 1141 | name = "regex-syntax" 1142 | version = "0.6.27" 1143 | source = "registry+https://github.com/rust-lang/crates.io-index" 1144 | checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" 1145 | 1146 | [[package]] 1147 | name = "reqwest" 1148 | version = "0.11.18" 1149 | source = "registry+https://github.com/rust-lang/crates.io-index" 1150 | checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" 1151 | dependencies = [ 1152 | "base64 0.21.0", 1153 | "bytes", 1154 | "encoding_rs", 1155 | "futures-core", 1156 | "futures-util", 1157 | "h2", 1158 | "http", 1159 | "http-body", 1160 | "hyper", 1161 | "hyper-rustls", 1162 | "ipnet", 1163 | "js-sys", 1164 | "log", 1165 | "mime", 1166 | "once_cell", 1167 | "percent-encoding", 1168 | "pin-project-lite", 1169 | "rustls", 1170 | "rustls-pemfile", 1171 | "serde", 1172 | "serde_json", 1173 | "serde_urlencoded", 1174 | "tokio", 1175 | "tokio-rustls", 1176 | "tower-service", 1177 | "url", 1178 | "wasm-bindgen", 1179 | "wasm-bindgen-futures", 1180 | "web-sys", 1181 | "webpki-roots", 1182 | "winreg", 1183 | ] 1184 | 1185 | [[package]] 1186 | name = "ring" 1187 | version = "0.16.20" 1188 | source = "registry+https://github.com/rust-lang/crates.io-index" 1189 | checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" 1190 | dependencies = [ 1191 | "cc", 1192 | "libc", 1193 | "once_cell", 1194 | "spin", 1195 | "untrusted", 1196 | "web-sys", 1197 | "winapi", 1198 | ] 1199 | 1200 | [[package]] 1201 | name = "rustc-demangle" 1202 | version = "0.1.21" 1203 | source = "registry+https://github.com/rust-lang/crates.io-index" 1204 | checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" 1205 | 1206 | [[package]] 1207 | name = "rustix" 1208 | version = "0.37.20" 1209 | source = "registry+https://github.com/rust-lang/crates.io-index" 1210 | checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" 1211 | dependencies = [ 1212 | "bitflags", 1213 | "errno 0.3.1", 1214 | "io-lifetimes", 1215 | "libc", 1216 | "linux-raw-sys", 1217 | "windows-sys 0.48.0", 1218 | ] 1219 | 1220 | [[package]] 1221 | name = "rustls" 1222 | version = "0.21.1" 1223 | source = "registry+https://github.com/rust-lang/crates.io-index" 1224 | checksum = "c911ba11bc8433e811ce56fde130ccf32f5127cab0e0194e9c68c5a5b671791e" 1225 | dependencies = [ 1226 | "log", 1227 | "ring", 1228 | "rustls-webpki", 1229 | "sct", 1230 | ] 1231 | 1232 | [[package]] 1233 | name = "rustls-pemfile" 1234 | version = "1.0.1" 1235 | source = "registry+https://github.com/rust-lang/crates.io-index" 1236 | checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" 1237 | dependencies = [ 1238 | "base64 0.13.0", 1239 | ] 1240 | 1241 | [[package]] 1242 | name = "rustls-webpki" 1243 | version = "0.100.1" 1244 | source = "registry+https://github.com/rust-lang/crates.io-index" 1245 | checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b" 1246 | dependencies = [ 1247 | "ring", 1248 | "untrusted", 1249 | ] 1250 | 1251 | [[package]] 1252 | name = "ryu" 1253 | version = "1.0.11" 1254 | source = "registry+https://github.com/rust-lang/crates.io-index" 1255 | checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" 1256 | 1257 | [[package]] 1258 | name = "scopeguard" 1259 | version = "1.1.0" 1260 | source = "registry+https://github.com/rust-lang/crates.io-index" 1261 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1262 | 1263 | [[package]] 1264 | name = "sct" 1265 | version = "0.7.0" 1266 | source = "registry+https://github.com/rust-lang/crates.io-index" 1267 | checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" 1268 | dependencies = [ 1269 | "ring", 1270 | "untrusted", 1271 | ] 1272 | 1273 | [[package]] 1274 | name = "serde" 1275 | version = "1.0.164" 1276 | source = "registry+https://github.com/rust-lang/crates.io-index" 1277 | checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" 1278 | 1279 | [[package]] 1280 | name = "serde_derive" 1281 | version = "1.0.164" 1282 | source = "registry+https://github.com/rust-lang/crates.io-index" 1283 | checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" 1284 | dependencies = [ 1285 | "proc-macro2", 1286 | "quote", 1287 | "syn 2.0.10", 1288 | ] 1289 | 1290 | [[package]] 1291 | name = "serde_json" 1292 | version = "1.0.85" 1293 | source = "registry+https://github.com/rust-lang/crates.io-index" 1294 | checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" 1295 | dependencies = [ 1296 | "itoa", 1297 | "ryu", 1298 | "serde", 1299 | ] 1300 | 1301 | [[package]] 1302 | name = "serde_spanned" 1303 | version = "0.6.2" 1304 | source = "registry+https://github.com/rust-lang/crates.io-index" 1305 | checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d" 1306 | dependencies = [ 1307 | "serde", 1308 | ] 1309 | 1310 | [[package]] 1311 | name = "serde_urlencoded" 1312 | version = "0.7.1" 1313 | source = "registry+https://github.com/rust-lang/crates.io-index" 1314 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1315 | dependencies = [ 1316 | "form_urlencoded", 1317 | "itoa", 1318 | "ryu", 1319 | "serde", 1320 | ] 1321 | 1322 | [[package]] 1323 | name = "sha2" 1324 | version = "0.10.7" 1325 | source = "registry+https://github.com/rust-lang/crates.io-index" 1326 | checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" 1327 | dependencies = [ 1328 | "cfg-if", 1329 | "cpufeatures", 1330 | "digest", 1331 | ] 1332 | 1333 | [[package]] 1334 | name = "sharded-slab" 1335 | version = "0.1.4" 1336 | source = "registry+https://github.com/rust-lang/crates.io-index" 1337 | checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" 1338 | dependencies = [ 1339 | "lazy_static", 1340 | ] 1341 | 1342 | [[package]] 1343 | name = "signal-hook-registry" 1344 | version = "1.4.0" 1345 | source = "registry+https://github.com/rust-lang/crates.io-index" 1346 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" 1347 | dependencies = [ 1348 | "libc", 1349 | ] 1350 | 1351 | [[package]] 1352 | name = "slab" 1353 | version = "0.4.7" 1354 | source = "registry+https://github.com/rust-lang/crates.io-index" 1355 | checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" 1356 | dependencies = [ 1357 | "autocfg", 1358 | ] 1359 | 1360 | [[package]] 1361 | name = "smallvec" 1362 | version = "1.9.0" 1363 | source = "registry+https://github.com/rust-lang/crates.io-index" 1364 | checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" 1365 | 1366 | [[package]] 1367 | name = "socket2" 1368 | version = "0.4.9" 1369 | source = "registry+https://github.com/rust-lang/crates.io-index" 1370 | checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" 1371 | dependencies = [ 1372 | "libc", 1373 | "winapi", 1374 | ] 1375 | 1376 | [[package]] 1377 | name = "spin" 1378 | version = "0.5.2" 1379 | source = "registry+https://github.com/rust-lang/crates.io-index" 1380 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 1381 | 1382 | [[package]] 1383 | name = "strsim" 1384 | version = "0.10.0" 1385 | source = "registry+https://github.com/rust-lang/crates.io-index" 1386 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 1387 | 1388 | [[package]] 1389 | name = "syn" 1390 | version = "1.0.105" 1391 | source = "registry+https://github.com/rust-lang/crates.io-index" 1392 | checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" 1393 | dependencies = [ 1394 | "proc-macro2", 1395 | "quote", 1396 | "unicode-ident", 1397 | ] 1398 | 1399 | [[package]] 1400 | name = "syn" 1401 | version = "2.0.10" 1402 | source = "registry+https://github.com/rust-lang/crates.io-index" 1403 | checksum = "5aad1363ed6d37b84299588d62d3a7d95b5a5c2d9aad5c85609fda12afaa1f40" 1404 | dependencies = [ 1405 | "proc-macro2", 1406 | "quote", 1407 | "unicode-ident", 1408 | ] 1409 | 1410 | [[package]] 1411 | name = "tar" 1412 | version = "0.4.38" 1413 | source = "registry+https://github.com/rust-lang/crates.io-index" 1414 | checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" 1415 | dependencies = [ 1416 | "filetime", 1417 | "libc", 1418 | "xattr", 1419 | ] 1420 | 1421 | [[package]] 1422 | name = "tempfile" 1423 | version = "3.6.0" 1424 | source = "registry+https://github.com/rust-lang/crates.io-index" 1425 | checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" 1426 | dependencies = [ 1427 | "autocfg", 1428 | "cfg-if", 1429 | "fastrand", 1430 | "redox_syscall 0.3.5", 1431 | "rustix", 1432 | "windows-sys 0.48.0", 1433 | ] 1434 | 1435 | [[package]] 1436 | name = "termcolor" 1437 | version = "1.1.3" 1438 | source = "registry+https://github.com/rust-lang/crates.io-index" 1439 | checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" 1440 | dependencies = [ 1441 | "winapi-util", 1442 | ] 1443 | 1444 | [[package]] 1445 | name = "terminal_size" 1446 | version = "0.1.17" 1447 | source = "registry+https://github.com/rust-lang/crates.io-index" 1448 | checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" 1449 | dependencies = [ 1450 | "libc", 1451 | "winapi", 1452 | ] 1453 | 1454 | [[package]] 1455 | name = "test-case" 1456 | version = "3.1.0" 1457 | source = "registry+https://github.com/rust-lang/crates.io-index" 1458 | checksum = "2a1d6e7bde536b0412f20765b76e921028059adfd1b90d8974d33fd3c91b25df" 1459 | dependencies = [ 1460 | "test-case-macros", 1461 | ] 1462 | 1463 | [[package]] 1464 | name = "test-case-core" 1465 | version = "3.0.0" 1466 | source = "registry+https://github.com/rust-lang/crates.io-index" 1467 | checksum = "72dc21b5887f4032c4656502d085dc28f2afbb686f25f216472bb0526f4b1b88" 1468 | dependencies = [ 1469 | "cfg-if", 1470 | "proc-macro-error", 1471 | "proc-macro2", 1472 | "quote", 1473 | "syn 1.0.105", 1474 | ] 1475 | 1476 | [[package]] 1477 | name = "test-case-macros" 1478 | version = "3.0.0" 1479 | source = "registry+https://github.com/rust-lang/crates.io-index" 1480 | checksum = "f3786898e0be151a96f730fd529b0e8a10f5990fa2a7ea14e37ca27613c05190" 1481 | dependencies = [ 1482 | "proc-macro-error", 1483 | "proc-macro2", 1484 | "quote", 1485 | "syn 1.0.105", 1486 | "test-case-core", 1487 | ] 1488 | 1489 | [[package]] 1490 | name = "thiserror" 1491 | version = "1.0.34" 1492 | source = "registry+https://github.com/rust-lang/crates.io-index" 1493 | checksum = "8c1b05ca9d106ba7d2e31a9dab4a64e7be2cce415321966ea3132c49a656e252" 1494 | dependencies = [ 1495 | "thiserror-impl", 1496 | ] 1497 | 1498 | [[package]] 1499 | name = "thiserror-impl" 1500 | version = "1.0.34" 1501 | source = "registry+https://github.com/rust-lang/crates.io-index" 1502 | checksum = "e8f2591983642de85c921015f3f070c665a197ed69e417af436115e3a1407487" 1503 | dependencies = [ 1504 | "proc-macro2", 1505 | "quote", 1506 | "syn 1.0.105", 1507 | ] 1508 | 1509 | [[package]] 1510 | name = "thread_local" 1511 | version = "1.1.4" 1512 | source = "registry+https://github.com/rust-lang/crates.io-index" 1513 | checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" 1514 | dependencies = [ 1515 | "once_cell", 1516 | ] 1517 | 1518 | [[package]] 1519 | name = "tinyvec" 1520 | version = "1.6.0" 1521 | source = "registry+https://github.com/rust-lang/crates.io-index" 1522 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 1523 | dependencies = [ 1524 | "tinyvec_macros", 1525 | ] 1526 | 1527 | [[package]] 1528 | name = "tinyvec_macros" 1529 | version = "0.1.0" 1530 | source = "registry+https://github.com/rust-lang/crates.io-index" 1531 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 1532 | 1533 | [[package]] 1534 | name = "tokio" 1535 | version = "1.28.2" 1536 | source = "registry+https://github.com/rust-lang/crates.io-index" 1537 | checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" 1538 | dependencies = [ 1539 | "autocfg", 1540 | "bytes", 1541 | "libc", 1542 | "mio", 1543 | "num_cpus", 1544 | "parking_lot", 1545 | "pin-project-lite", 1546 | "signal-hook-registry", 1547 | "socket2", 1548 | "tokio-macros", 1549 | "windows-sys 0.48.0", 1550 | ] 1551 | 1552 | [[package]] 1553 | name = "tokio-macros" 1554 | version = "2.1.0" 1555 | source = "registry+https://github.com/rust-lang/crates.io-index" 1556 | checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" 1557 | dependencies = [ 1558 | "proc-macro2", 1559 | "quote", 1560 | "syn 2.0.10", 1561 | ] 1562 | 1563 | [[package]] 1564 | name = "tokio-rustls" 1565 | version = "0.24.0" 1566 | source = "registry+https://github.com/rust-lang/crates.io-index" 1567 | checksum = "e0d409377ff5b1e3ca6437aa86c1eb7d40c134bfec254e44c830defa92669db5" 1568 | dependencies = [ 1569 | "rustls", 1570 | "tokio", 1571 | ] 1572 | 1573 | [[package]] 1574 | name = "tokio-util" 1575 | version = "0.7.3" 1576 | source = "registry+https://github.com/rust-lang/crates.io-index" 1577 | checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" 1578 | dependencies = [ 1579 | "bytes", 1580 | "futures-core", 1581 | "futures-sink", 1582 | "pin-project-lite", 1583 | "tokio", 1584 | "tracing", 1585 | ] 1586 | 1587 | [[package]] 1588 | name = "toml" 1589 | version = "0.7.4" 1590 | source = "registry+https://github.com/rust-lang/crates.io-index" 1591 | checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec" 1592 | dependencies = [ 1593 | "serde", 1594 | "serde_spanned", 1595 | "toml_datetime", 1596 | "toml_edit", 1597 | ] 1598 | 1599 | [[package]] 1600 | name = "toml_datetime" 1601 | version = "0.6.2" 1602 | source = "registry+https://github.com/rust-lang/crates.io-index" 1603 | checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" 1604 | dependencies = [ 1605 | "serde", 1606 | ] 1607 | 1608 | [[package]] 1609 | name = "toml_edit" 1610 | version = "0.19.10" 1611 | source = "registry+https://github.com/rust-lang/crates.io-index" 1612 | checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" 1613 | dependencies = [ 1614 | "indexmap", 1615 | "serde", 1616 | "serde_spanned", 1617 | "toml_datetime", 1618 | "winnow", 1619 | ] 1620 | 1621 | [[package]] 1622 | name = "tower-service" 1623 | version = "0.3.2" 1624 | source = "registry+https://github.com/rust-lang/crates.io-index" 1625 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" 1626 | 1627 | [[package]] 1628 | name = "tracing" 1629 | version = "0.1.36" 1630 | source = "registry+https://github.com/rust-lang/crates.io-index" 1631 | checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" 1632 | dependencies = [ 1633 | "cfg-if", 1634 | "pin-project-lite", 1635 | "tracing-core", 1636 | ] 1637 | 1638 | [[package]] 1639 | name = "tracing-core" 1640 | version = "0.1.29" 1641 | source = "registry+https://github.com/rust-lang/crates.io-index" 1642 | checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" 1643 | dependencies = [ 1644 | "once_cell", 1645 | "valuable", 1646 | ] 1647 | 1648 | [[package]] 1649 | name = "tracing-error" 1650 | version = "0.2.0" 1651 | source = "registry+https://github.com/rust-lang/crates.io-index" 1652 | checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" 1653 | dependencies = [ 1654 | "tracing", 1655 | "tracing-subscriber", 1656 | ] 1657 | 1658 | [[package]] 1659 | name = "tracing-subscriber" 1660 | version = "0.3.15" 1661 | source = "registry+https://github.com/rust-lang/crates.io-index" 1662 | checksum = "60db860322da191b40952ad9affe65ea23e7dd6a5c442c2c42865810c6ab8e6b" 1663 | dependencies = [ 1664 | "sharded-slab", 1665 | "thread_local", 1666 | "tracing-core", 1667 | ] 1668 | 1669 | [[package]] 1670 | name = "try-lock" 1671 | version = "0.2.3" 1672 | source = "registry+https://github.com/rust-lang/crates.io-index" 1673 | checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" 1674 | 1675 | [[package]] 1676 | name = "typenum" 1677 | version = "1.15.0" 1678 | source = "registry+https://github.com/rust-lang/crates.io-index" 1679 | checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" 1680 | 1681 | [[package]] 1682 | name = "unicode-bidi" 1683 | version = "0.3.8" 1684 | source = "registry+https://github.com/rust-lang/crates.io-index" 1685 | checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" 1686 | 1687 | [[package]] 1688 | name = "unicode-ident" 1689 | version = "1.0.3" 1690 | source = "registry+https://github.com/rust-lang/crates.io-index" 1691 | checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" 1692 | 1693 | [[package]] 1694 | name = "unicode-normalization" 1695 | version = "0.1.21" 1696 | source = "registry+https://github.com/rust-lang/crates.io-index" 1697 | checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" 1698 | dependencies = [ 1699 | "tinyvec", 1700 | ] 1701 | 1702 | [[package]] 1703 | name = "unicode-width" 1704 | version = "0.1.9" 1705 | source = "registry+https://github.com/rust-lang/crates.io-index" 1706 | checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" 1707 | 1708 | [[package]] 1709 | name = "untrusted" 1710 | version = "0.7.1" 1711 | source = "registry+https://github.com/rust-lang/crates.io-index" 1712 | checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" 1713 | 1714 | [[package]] 1715 | name = "url" 1716 | version = "2.2.2" 1717 | source = "registry+https://github.com/rust-lang/crates.io-index" 1718 | checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" 1719 | dependencies = [ 1720 | "form_urlencoded", 1721 | "idna", 1722 | "matches", 1723 | "percent-encoding", 1724 | ] 1725 | 1726 | [[package]] 1727 | name = "utf8parse" 1728 | version = "0.2.1" 1729 | source = "registry+https://github.com/rust-lang/crates.io-index" 1730 | checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" 1731 | 1732 | [[package]] 1733 | name = "valuable" 1734 | version = "0.1.0" 1735 | source = "registry+https://github.com/rust-lang/crates.io-index" 1736 | checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" 1737 | 1738 | [[package]] 1739 | name = "version_check" 1740 | version = "0.9.4" 1741 | source = "registry+https://github.com/rust-lang/crates.io-index" 1742 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1743 | 1744 | [[package]] 1745 | name = "want" 1746 | version = "0.3.0" 1747 | source = "registry+https://github.com/rust-lang/crates.io-index" 1748 | checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" 1749 | dependencies = [ 1750 | "log", 1751 | "try-lock", 1752 | ] 1753 | 1754 | [[package]] 1755 | name = "wasi" 1756 | version = "0.11.0+wasi-snapshot-preview1" 1757 | source = "registry+https://github.com/rust-lang/crates.io-index" 1758 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1759 | 1760 | [[package]] 1761 | name = "wasm-bindgen" 1762 | version = "0.2.82" 1763 | source = "registry+https://github.com/rust-lang/crates.io-index" 1764 | checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" 1765 | dependencies = [ 1766 | "cfg-if", 1767 | "wasm-bindgen-macro", 1768 | ] 1769 | 1770 | [[package]] 1771 | name = "wasm-bindgen-backend" 1772 | version = "0.2.82" 1773 | source = "registry+https://github.com/rust-lang/crates.io-index" 1774 | checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" 1775 | dependencies = [ 1776 | "bumpalo", 1777 | "log", 1778 | "once_cell", 1779 | "proc-macro2", 1780 | "quote", 1781 | "syn 1.0.105", 1782 | "wasm-bindgen-shared", 1783 | ] 1784 | 1785 | [[package]] 1786 | name = "wasm-bindgen-futures" 1787 | version = "0.4.32" 1788 | source = "registry+https://github.com/rust-lang/crates.io-index" 1789 | checksum = "fa76fb221a1f8acddf5b54ace85912606980ad661ac7a503b4570ffd3a624dad" 1790 | dependencies = [ 1791 | "cfg-if", 1792 | "js-sys", 1793 | "wasm-bindgen", 1794 | "web-sys", 1795 | ] 1796 | 1797 | [[package]] 1798 | name = "wasm-bindgen-macro" 1799 | version = "0.2.82" 1800 | source = "registry+https://github.com/rust-lang/crates.io-index" 1801 | checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" 1802 | dependencies = [ 1803 | "quote", 1804 | "wasm-bindgen-macro-support", 1805 | ] 1806 | 1807 | [[package]] 1808 | name = "wasm-bindgen-macro-support" 1809 | version = "0.2.82" 1810 | source = "registry+https://github.com/rust-lang/crates.io-index" 1811 | checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" 1812 | dependencies = [ 1813 | "proc-macro2", 1814 | "quote", 1815 | "syn 1.0.105", 1816 | "wasm-bindgen-backend", 1817 | "wasm-bindgen-shared", 1818 | ] 1819 | 1820 | [[package]] 1821 | name = "wasm-bindgen-shared" 1822 | version = "0.2.82" 1823 | source = "registry+https://github.com/rust-lang/crates.io-index" 1824 | checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" 1825 | 1826 | [[package]] 1827 | name = "web-sys" 1828 | version = "0.3.59" 1829 | source = "registry+https://github.com/rust-lang/crates.io-index" 1830 | checksum = "ed055ab27f941423197eb86b2035720b1a3ce40504df082cac2ecc6ed73335a1" 1831 | dependencies = [ 1832 | "js-sys", 1833 | "wasm-bindgen", 1834 | ] 1835 | 1836 | [[package]] 1837 | name = "webpki" 1838 | version = "0.22.0" 1839 | source = "registry+https://github.com/rust-lang/crates.io-index" 1840 | checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" 1841 | dependencies = [ 1842 | "ring", 1843 | "untrusted", 1844 | ] 1845 | 1846 | [[package]] 1847 | name = "webpki-roots" 1848 | version = "0.22.4" 1849 | source = "registry+https://github.com/rust-lang/crates.io-index" 1850 | checksum = "f1c760f0d366a6c24a02ed7816e23e691f5d92291f94d15e836006fd11b04daf" 1851 | dependencies = [ 1852 | "webpki", 1853 | ] 1854 | 1855 | [[package]] 1856 | name = "winapi" 1857 | version = "0.3.9" 1858 | source = "registry+https://github.com/rust-lang/crates.io-index" 1859 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1860 | dependencies = [ 1861 | "winapi-i686-pc-windows-gnu", 1862 | "winapi-x86_64-pc-windows-gnu", 1863 | ] 1864 | 1865 | [[package]] 1866 | name = "winapi-i686-pc-windows-gnu" 1867 | version = "0.4.0" 1868 | source = "registry+https://github.com/rust-lang/crates.io-index" 1869 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1870 | 1871 | [[package]] 1872 | name = "winapi-util" 1873 | version = "0.1.5" 1874 | source = "registry+https://github.com/rust-lang/crates.io-index" 1875 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1876 | dependencies = [ 1877 | "winapi", 1878 | ] 1879 | 1880 | [[package]] 1881 | name = "winapi-x86_64-pc-windows-gnu" 1882 | version = "0.4.0" 1883 | source = "registry+https://github.com/rust-lang/crates.io-index" 1884 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1885 | 1886 | [[package]] 1887 | name = "windows-sys" 1888 | version = "0.36.1" 1889 | source = "registry+https://github.com/rust-lang/crates.io-index" 1890 | checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" 1891 | dependencies = [ 1892 | "windows_aarch64_msvc 0.36.1", 1893 | "windows_i686_gnu 0.36.1", 1894 | "windows_i686_msvc 0.36.1", 1895 | "windows_x86_64_gnu 0.36.1", 1896 | "windows_x86_64_msvc 0.36.1", 1897 | ] 1898 | 1899 | [[package]] 1900 | name = "windows-sys" 1901 | version = "0.45.0" 1902 | source = "registry+https://github.com/rust-lang/crates.io-index" 1903 | checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" 1904 | dependencies = [ 1905 | "windows-targets 0.42.1", 1906 | ] 1907 | 1908 | [[package]] 1909 | name = "windows-sys" 1910 | version = "0.48.0" 1911 | source = "registry+https://github.com/rust-lang/crates.io-index" 1912 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 1913 | dependencies = [ 1914 | "windows-targets 0.48.0", 1915 | ] 1916 | 1917 | [[package]] 1918 | name = "windows-targets" 1919 | version = "0.42.1" 1920 | source = "registry+https://github.com/rust-lang/crates.io-index" 1921 | checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" 1922 | dependencies = [ 1923 | "windows_aarch64_gnullvm 0.42.1", 1924 | "windows_aarch64_msvc 0.42.1", 1925 | "windows_i686_gnu 0.42.1", 1926 | "windows_i686_msvc 0.42.1", 1927 | "windows_x86_64_gnu 0.42.1", 1928 | "windows_x86_64_gnullvm 0.42.1", 1929 | "windows_x86_64_msvc 0.42.1", 1930 | ] 1931 | 1932 | [[package]] 1933 | name = "windows-targets" 1934 | version = "0.48.0" 1935 | source = "registry+https://github.com/rust-lang/crates.io-index" 1936 | checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" 1937 | dependencies = [ 1938 | "windows_aarch64_gnullvm 0.48.0", 1939 | "windows_aarch64_msvc 0.48.0", 1940 | "windows_i686_gnu 0.48.0", 1941 | "windows_i686_msvc 0.48.0", 1942 | "windows_x86_64_gnu 0.48.0", 1943 | "windows_x86_64_gnullvm 0.48.0", 1944 | "windows_x86_64_msvc 0.48.0", 1945 | ] 1946 | 1947 | [[package]] 1948 | name = "windows_aarch64_gnullvm" 1949 | version = "0.42.1" 1950 | source = "registry+https://github.com/rust-lang/crates.io-index" 1951 | checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" 1952 | 1953 | [[package]] 1954 | name = "windows_aarch64_gnullvm" 1955 | version = "0.48.0" 1956 | source = "registry+https://github.com/rust-lang/crates.io-index" 1957 | checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" 1958 | 1959 | [[package]] 1960 | name = "windows_aarch64_msvc" 1961 | version = "0.36.1" 1962 | source = "registry+https://github.com/rust-lang/crates.io-index" 1963 | checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" 1964 | 1965 | [[package]] 1966 | name = "windows_aarch64_msvc" 1967 | version = "0.42.1" 1968 | source = "registry+https://github.com/rust-lang/crates.io-index" 1969 | checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" 1970 | 1971 | [[package]] 1972 | name = "windows_aarch64_msvc" 1973 | version = "0.48.0" 1974 | source = "registry+https://github.com/rust-lang/crates.io-index" 1975 | checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" 1976 | 1977 | [[package]] 1978 | name = "windows_i686_gnu" 1979 | version = "0.36.1" 1980 | source = "registry+https://github.com/rust-lang/crates.io-index" 1981 | checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" 1982 | 1983 | [[package]] 1984 | name = "windows_i686_gnu" 1985 | version = "0.42.1" 1986 | source = "registry+https://github.com/rust-lang/crates.io-index" 1987 | checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" 1988 | 1989 | [[package]] 1990 | name = "windows_i686_gnu" 1991 | version = "0.48.0" 1992 | source = "registry+https://github.com/rust-lang/crates.io-index" 1993 | checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" 1994 | 1995 | [[package]] 1996 | name = "windows_i686_msvc" 1997 | version = "0.36.1" 1998 | source = "registry+https://github.com/rust-lang/crates.io-index" 1999 | checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" 2000 | 2001 | [[package]] 2002 | name = "windows_i686_msvc" 2003 | version = "0.42.1" 2004 | source = "registry+https://github.com/rust-lang/crates.io-index" 2005 | checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" 2006 | 2007 | [[package]] 2008 | name = "windows_i686_msvc" 2009 | version = "0.48.0" 2010 | source = "registry+https://github.com/rust-lang/crates.io-index" 2011 | checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" 2012 | 2013 | [[package]] 2014 | name = "windows_x86_64_gnu" 2015 | version = "0.36.1" 2016 | source = "registry+https://github.com/rust-lang/crates.io-index" 2017 | checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" 2018 | 2019 | [[package]] 2020 | name = "windows_x86_64_gnu" 2021 | version = "0.42.1" 2022 | source = "registry+https://github.com/rust-lang/crates.io-index" 2023 | checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" 2024 | 2025 | [[package]] 2026 | name = "windows_x86_64_gnu" 2027 | version = "0.48.0" 2028 | source = "registry+https://github.com/rust-lang/crates.io-index" 2029 | checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" 2030 | 2031 | [[package]] 2032 | name = "windows_x86_64_gnullvm" 2033 | version = "0.42.1" 2034 | source = "registry+https://github.com/rust-lang/crates.io-index" 2035 | checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" 2036 | 2037 | [[package]] 2038 | name = "windows_x86_64_gnullvm" 2039 | version = "0.48.0" 2040 | source = "registry+https://github.com/rust-lang/crates.io-index" 2041 | checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" 2042 | 2043 | [[package]] 2044 | name = "windows_x86_64_msvc" 2045 | version = "0.36.1" 2046 | source = "registry+https://github.com/rust-lang/crates.io-index" 2047 | checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" 2048 | 2049 | [[package]] 2050 | name = "windows_x86_64_msvc" 2051 | version = "0.42.1" 2052 | source = "registry+https://github.com/rust-lang/crates.io-index" 2053 | checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" 2054 | 2055 | [[package]] 2056 | name = "windows_x86_64_msvc" 2057 | version = "0.48.0" 2058 | source = "registry+https://github.com/rust-lang/crates.io-index" 2059 | checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" 2060 | 2061 | [[package]] 2062 | name = "winnow" 2063 | version = "0.4.6" 2064 | source = "registry+https://github.com/rust-lang/crates.io-index" 2065 | checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699" 2066 | dependencies = [ 2067 | "memchr", 2068 | ] 2069 | 2070 | [[package]] 2071 | name = "winreg" 2072 | version = "0.10.1" 2073 | source = "registry+https://github.com/rust-lang/crates.io-index" 2074 | checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" 2075 | dependencies = [ 2076 | "winapi", 2077 | ] 2078 | 2079 | [[package]] 2080 | name = "xattr" 2081 | version = "0.2.3" 2082 | source = "registry+https://github.com/rust-lang/crates.io-index" 2083 | checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" 2084 | dependencies = [ 2085 | "libc", 2086 | ] 2087 | 2088 | [[package]] 2089 | name = "xz" 2090 | version = "0.1.0" 2091 | source = "registry+https://github.com/rust-lang/crates.io-index" 2092 | checksum = "3c887690ff2a2e233e8e49633461521f98ec57fbff9d59a884c9a4f04ec1da34" 2093 | dependencies = [ 2094 | "xz2", 2095 | ] 2096 | 2097 | [[package]] 2098 | name = "xz2" 2099 | version = "0.1.7" 2100 | source = "registry+https://github.com/rust-lang/crates.io-index" 2101 | checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" 2102 | dependencies = [ 2103 | "lzma-sys", 2104 | ] 2105 | 2106 | [[package]] 2107 | name = "yansi" 2108 | version = "0.5.1" 2109 | source = "registry+https://github.com/rust-lang/crates.io-index" 2110 | checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" 2111 | 2112 | [[package]] 2113 | name = "zip" 2114 | version = "0.6.6" 2115 | source = "registry+https://github.com/rust-lang/crates.io-index" 2116 | checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" 2117 | dependencies = [ 2118 | "byteorder", 2119 | "crc32fast", 2120 | "crossbeam-utils", 2121 | "flate2", 2122 | ] 2123 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chim" 3 | version = "1.1.1" 4 | edition = "2021" 5 | description = "Cross-platform binary shims with optional remote fetching." 6 | authors = ["Jeff Dickey (@jdxcode)"] 7 | homepage = "https://chim.sh" 8 | documentation = "https://chim.sh" 9 | repository = "https://github.com/jdxcode/chim" 10 | readme = "README.md" 11 | license = "MIT" 12 | keywords = ["shim"] 13 | categories = ["command-line-utilities", "development-tools::build-utils"] 14 | include = ["src/**/*", "LICENSE", "README.md"] 15 | 16 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 17 | 18 | [dependencies] 19 | bzip2 = "0.4.4" 20 | clap = { version = "4.3.8", features = ["derive"] } 21 | color-eyre = "0.6.2" 22 | dirs = "5.0.1" 23 | env_logger = "0.10.0" 24 | flate2 = "1.0.26" 25 | hex = "0.4.3" 26 | indicatif = "0.17.5" 27 | itertools = "0.10.5" 28 | log = "0.4.19" 29 | reqwest = {version = "0.11.18", features = ["rustls-tls"], default-features = false} 30 | serde = "1.0.164" 31 | serde_derive = "1.0.164" 32 | sha2 = "0.10.7" 33 | tar = "0.4.38" 34 | tempfile = "3.6.0" 35 | tokio = { version = "1.28.2", features = ["full"] } 36 | toml = "0.7.4" 37 | toml_edit = "0.19.10" 38 | xz = "0.1.0" 39 | zip = {version = "0.6.6", default-features = false, features = ["deflate"]} 40 | 41 | [target.'cfg(unix)'.dependencies] 42 | exec = "0.3.1" 43 | 44 | [features] 45 | test-e2e = [] # run e2e tests 46 | 47 | [dev-dependencies] 48 | test-case = "3.1.0" 49 | rand = "0.8.5" 50 | pretty_assertions = "1.3.0" 51 | 52 | [profile.release] 53 | opt-level = "z" # optimize for size 54 | lto = true 55 | debug = false 56 | debug-assertions = false 57 | panic = "abort" 58 | strip = "symbols" 59 | 60 | [package.metadata.release] 61 | allow-branch = ["master"] 62 | sign-tag = true 63 | sign-commit = true 64 | pre-release-replacements = [ 65 | {file="README.md", search="^chim [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace="chim {{version}}"}, 66 | {file="packaging/rpm/chim.spec", search="^Version: [0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace="Version: {{version}}"}, 67 | {file="packaging/win/setup.iss", search="^AppVersion=[0-9]+.[0-9]+.[0-9]+(-alpha.[0-9]+)?$", replace="AppVersion={{version}}"}, 68 | ] 69 | -------------------------------------------------------------------------------- /Cross.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | pre-build = [ 3 | "dpkg --add-architecture $CROSS_DEB_ARCH", 4 | "apt-get update && apt-get --assume-yes install libssl-dev:$CROSS_DEB_ARCH" 5 | ] 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Jeff Dickey 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [chim](https://chim.sh/) 2 | 3 | [![Crates.io](https://img.shields.io/crates/v/chim.svg)](https://crates.io/crates/chim) 4 | [![chim](https://github.com/jdxcode/chim/actions/workflows/chim.yml/badge.svg?branch=main)](https://github.com/jdxcode/chim/actions/workflows/chim.yml) 5 | [![codecov](https://codecov.io/gh/jdxcode/chim/branch/main/graph/badge.svg?token=CWOTCG9F5D)](https://codecov.io/gh/jdxcode/chim) 6 | 7 | _Cross-platform binary shims with optional remote fetching._ 8 | 9 | ## Quickstart (make an automatic fetching node.js wrapper) 10 | 11 | Install chim: (see docs for [alternate install methods](https://chim.sh/docs/installing/)) 12 | 13 | ``` 14 | $ cargo install chim 15 | $ chim --version 16 | chim 1.1.1 17 | ``` 18 | 19 | Create a chim in `./bin/node`: 20 | 21 | ```toml 22 | #!/usr/bin/env chim 23 | [macos-arm64] 24 | url = 'https://nodejs.org/dist/v18.7.0/node-v18.7.0-darwin-arm64.tar.xz' 25 | path = 'node-v18.7.0-darwin-arm64/bin/node' 26 | checksum = 'ef593cbb3a3f0aae9879b74a7850d794abab26178aa5e0f67ff182894811e6f0' 27 | 28 | [linux-x64] 29 | url = 'https://nodejs.org/dist/v18.7.0/node-v18.7.0-linux-x64.tar.xz' 30 | path = 'node-v18.7.0-linux-x64/bin/node' 31 | checksum = '8bc6a1b9deaed2586d726fc62d4bee9c1bfc5a30b96c1c4cff7edd15225a11a2' 32 | 33 | [windows-x64] 34 | url = 'https://nodejs.org/dist/v18.7.0/node-v18.7.0-win-x64.zip' 35 | path = 'node-v18.7.0-win-x64\node.exe' 36 | checksum = '9c0abfe32291dd5bed717463cb3590004289f03ab66011e383daa0fcec674683' 37 | ``` 38 | 39 | Now make it executable and run it: 40 | 41 | ``` 42 | $ chmod +x ./bin/node 43 | $ ./bin/node -v 44 | v18.7.0 45 | ``` 46 | 47 | The tarball is fetched once from nodejs.org, extracted into a cache directory, then reused on future `./bin/node` calls. 48 | 49 | ## What am I supposed to do with this? 50 | 51 | Commit a set of chims into a `/bin` directory in your project's repo. Other people can just add this directory to their 52 | `$PATH` and won't have to manually install each utility. Also run the chims in CI/CD so you have dev/prod parity with 53 | your tools! 54 | 55 | ## See also 56 | 57 | * [chim.sh](https://chim.sh/) - the documentation website 58 | * [GitHub (jdxcode/chim)](https://github.com/jdxcode/chim) - the repository 59 | * [GitHub (jdxcode/chim.sh)](https://github.com/jdxcode/chim.sh) - the repository for the documentation 60 | * [GitHub Discussions](https://github.com/jdxcode/chim/discussions) - message board for chim 61 | * [GitHub Releases (Changelog)](https://github.com/jdxcode/chim/releases) - see the latest releases 62 | * [Homebrew Formula](https://github.com/jdxcode/homebrew-tap/blob/main/chim.rb) - the Homebrew formula 63 | * [Crates.io (chim)](https://crates.io/crates/chim) - the crate on crates.io 64 | * [Discord](https://discord.gg/j3KUQj5HsN) - the chim discord server 65 | * [Introductory blog post](https://jdxcode.com/posts/2022-09-04-introducing-chim/) - a blog post introducing chim 66 | -------------------------------------------------------------------------------- /RELEASING.md: -------------------------------------------------------------------------------- 1 | # Release Instructions 2 | 3 | Simply run the following and GitHub Actions will do the rest: 4 | 5 | ```sh-session 6 | $ cargo release -x [major|minor|patch] 7 | ``` 8 | -------------------------------------------------------------------------------- /example/.bin/shellcheck-linux-x64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdx/chim/4f16e4487b14f88ffa260e4217749186f71367bf/example/.bin/shellcheck-linux-x64 -------------------------------------------------------------------------------- /example/.bin/shellcheck-macos-x64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdx/chim/4f16e4487b14f88ffa260e4217749186f71367bf/example/.bin/shellcheck-macos-x64 -------------------------------------------------------------------------------- /example/.multiarch/linux: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | echo "running on linux args:" "$@" 3 | -------------------------------------------------------------------------------- /example/.multiarch/macos: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | echo "running on macos-arm args:" "$@" 3 | -------------------------------------------------------------------------------- /example/abs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env chim 2 | 3 | [darwin-arm64] 4 | url = "abs://chimdev.blob.core.windows.net/chim/node-v18.8.0-darwin-arm64.tar.xz" 5 | checksum = "a03cb97533447a5005accef871b899df0e9da33d8a805675ac53715a534b3dcb" 6 | path = "node-v18.8.0-darwin-arm64/bin/node" 7 | 8 | [macos-x64] 9 | url = "abs://chimdev.blob.core.windows.net/chim/node-v18.8.0-darwin-x64.tar.xz" 10 | checksum = "f8527a1820f50a5f4c835d933e5c5318c4f93f7382294db5875791e2cb0cc4fa" 11 | path = "node-v18.8.0-darwin-x64/bin/node" 12 | 13 | [linux-x64] 14 | url = "abs://chimdev.blob.core.windows.net/chim/node-v18.8.0-linux-x64.tar.xz" 15 | checksum = "c4add613391e51406caad37fafe12ef67eb53eeff11f233f63cc65e643bf6700" 16 | path = "node-v18.8.0-linux-x64/bin/node" 17 | -------------------------------------------------------------------------------- /example/err: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env chim 2 | 3 | url = "http://chim.sh/invalid" 4 | -------------------------------------------------------------------------------- /example/gcs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env chim 2 | 3 | [darwin-arm64] 4 | url = "gs://chim/node-v18.8.0-darwin-arm64.tar.xz" 5 | checksum = "a03cb97533447a5005accef871b899df0e9da33d8a805675ac53715a534b3dcb" 6 | path = "node-v18.8.0-darwin-arm64/bin/node" 7 | 8 | [macos-x64] 9 | url = "gs://chim/node-v18.8.0-darwin-x64.tar.xz" 10 | checksum = "f8527a1820f50a5f4c835d933e5c5318c4f93f7382294db5875791e2cb0cc4fa" 11 | path = "node-v18.8.0-darwin-x64/bin/node" 12 | 13 | [linux-x64] 14 | url = "gs://chim/node-v18.8.0-linux-x64.tar.xz" 15 | checksum = "c4add613391e51406caad37fafe12ef67eb53eeff11f233f63cc65e643bf6700" 16 | path = "node-v18.8.0-linux-x64/bin/node" 17 | -------------------------------------------------------------------------------- /example/gz: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env chim 2 | 3 | [darwin-x64] 4 | url = "https://chim.s3.amazonaws.com/node-v18.8.0-darwin-x64.gz" 5 | checksum = "8c5f81535007c5f3584729b9b5d3d45b52035be6edf5fb9374962f164e249b28" 6 | 7 | [linux-x64] 8 | url = "https://chim.s3.amazonaws.com/node-v18.8.0-linux-x64.gz" 9 | checksum = "4b48bd867dca66c2db58e0d3d50480363d3402b51783d4bef3ebfaa28ffa1c0a" 10 | -------------------------------------------------------------------------------- /example/hooks: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env chim 2 | pre_execute = 'echo pre_execute >&2' 3 | post_execute = 'echo post_execute >&2' 4 | 5 | [macos-x64] 6 | url = 'https://nodejs.org/dist/v18.7.0/node-v18.7.0-darwin-arm64.tar.gz' 7 | path = 'node-v18.7.0-darwin-arm64/bin/node' 8 | checksum = 'ea24b35067bd0dc40ea8fda1087acc87672cbcbba881f7477dbd432e3c03343d' 9 | 10 | [macos-arm64] 11 | url = 'https://nodejs.org/dist/v18.7.0/node-v18.7.0-darwin-arm64.tar.gz' 12 | path = 'node-v18.7.0-darwin-arm64/bin/node' 13 | checksum = 'ea24b35067bd0dc40ea8fda1087acc87672cbcbba881f7477dbd432e3c03343d' 14 | 15 | [linux-x64] 16 | url = 'https://nodejs.org/dist/v18.7.0/node-v18.7.0-linux-x64.tar.xz' 17 | path = 'node-v18.7.0-linux-x64/bin/node' 18 | checksum = '8bc6a1b9deaed2586d726fc62d4bee9c1bfc5a30b96c1c4cff7edd15225a11a2' 19 | -------------------------------------------------------------------------------- /example/jq: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env chim 2 | 3 | execvp = false 4 | 5 | [macos-x64] 6 | url = "https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64" 7 | checksum = "sha256:5c0a0a3ea600f302ee458b30317425dd9632d1ad8882259fcaf4e9b868b2b1ef" 8 | 9 | # there isn't prebuilt macos-arm64 binary but chim will default macos to use 10 | # macos-x64 via Rosetta 2 11 | 12 | [linux-x64] 13 | url = "https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64" 14 | checksum = "sha256:af986793a515d500ab2d35f8d2aecd656e764504b789b66d7e1a0b727a124c44" 15 | 16 | [linux-aarch64] 17 | url = "https://chim.s3.amazonaws.com/jq-linux-aarch64" 18 | checksum = "sha256:a21c3d8616a9d60c2f1b20d69c5572f3b1f7301e4b5fbbc5e7ef68aabbd55d0a" 19 | -------------------------------------------------------------------------------- /example/multiarch: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env chim 2 | [macos-arm64] 3 | path = "./.multiarch/macos" 4 | [macos-x64] 5 | path = "./.multiarch/macos" 6 | [linux-x64] 7 | path = "./.multiarch/linux" 8 | -------------------------------------------------------------------------------- /example/node: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env chim 2 | [macos-arm64] 3 | url = 'https://nodejs.org/dist/v18.7.0/node-v18.7.0-darwin-arm64.tar.gz' 4 | path = 'node-v18.7.0-darwin-arm64/bin/node' 5 | checksum = "sha256:ea24b35067bd0dc40ea8fda1087acc87672cbcbba881f7477dbd432e3c03343d" 6 | 7 | [darwin-x86_64] 8 | url = 'https://nodejs.org/dist/v18.7.0/node-v18.7.0-darwin-x64.tar.gz' 9 | path = 'node-v18.7.0-darwin-x64/bin/node' 10 | checksum = "sha256:ce95b924b450edbcfeaf422b3635a6b44b17ad23cd1f5efff6b051c60db548c8" 11 | 12 | [linux-x64] 13 | url = 'https://nodejs.org/dist/v18.7.0/node-v18.7.0-linux-x64.tar.xz' 14 | path = 'node-v18.7.0-linux-x64/bin/node' 15 | checksum = "sha256:8bc6a1b9deaed2586d726fc62d4bee9c1bfc5a30b96c1c4cff7edd15225a11a2" 16 | 17 | [linux-arm64] 18 | url = 'https://nodejs.org/dist/v18.7.0/node-v18.7.0-linux-arm64.tar.xz' 19 | path = 'node-v18.7.0-linux-arm64/bin/node' 20 | checksum = "sha256:c3ac4905ec3993d00a45d2c7af8417e79e907be51b8ffecb54c5b9ab8ef0bc9f" 21 | 22 | [win-x64] 23 | url = 'https://nodejs.org/dist/v18.7.0/node-v18.7.0-win-x64.zip' 24 | path = 'node-v18.7.0-win-x64\node.exe' 25 | checksum = "sha256:9c0abfe32291dd5bed717463cb3590004289f03ab66011e383daa0fcec674683" 26 | -------------------------------------------------------------------------------- /example/node.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | chim "%~dp0\node" %* ; Runs `chim .\node` 3 | EXIT /B %ERRORLEVEL% ; Return the errorlevel of the last command 4 | -------------------------------------------------------------------------------- /example/s3: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env chim 2 | 3 | [darwin-x64] 4 | url = "s3://chim/node-v18.8.0-darwin-x64.tar.xz" 5 | checksum = "f8527a1820f50a5f4c835d933e5c5318c4f93f7382294db5875791e2cb0cc4fa" 6 | path = "node-v18.8.0-darwin-x64/bin/node" 7 | 8 | [darwin-arm64] 9 | url = "s3://chim/node-v18.8.0-darwin-arm64.tar.xz" 10 | checksum = "a03cb97533447a5005accef871b899df0e9da33d8a805675ac53715a534b3dcb" 11 | path = "node-v18.8.0-darwin-arm64/bin/node" 12 | 13 | [linux-x64] 14 | url = "s3://chim/node-v18.8.0-linux-x64.tar.xz" 15 | checksum = "c4add613391e51406caad37fafe12ef67eb53eeff11f233f63cc65e643bf6700" 16 | path = "node-v18.8.0-linux-x64/bin/node" 17 | -------------------------------------------------------------------------------- /example/scp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env chim 2 | 3 | [darwin-arm64] 4 | url = "scp://cloud/chim/node-v18.8.0-darwin-x64.tar.gz" 5 | checksum = "57457aeb1b3bfa2295235a134ebcdb58a72144b88049b72d9f7739f6591f850f" 6 | path = "node-v18.8.0-darwin-x64/bin/node" 7 | -------------------------------------------------------------------------------- /example/shellcheck: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env chim 2 | [macos-x64] 3 | url = 'https://github.com/koalaman/shellcheck/releases/download/v0.8.0/shellcheck-v0.8.0.darwin.x86_64.tar.xz' 4 | path = 'shellcheck-v0.8.0/shellcheck' 5 | checksum = 'e065d4afb2620cc8c1d420a9b3e6243c84ff1a693c1ff0e38f279c8f31e86634' 6 | 7 | [linux-x64] 8 | url = 'https://github.com/koalaman/shellcheck/releases/download/v0.8.0/shellcheck-v0.8.0.linux.x86_64.tar.xz' 9 | path = 'shellcheck-v0.8.0/shellcheck' 10 | checksum = 'ab6ee1b178f014d1b86d1e24da20d1139656c8b0ed34d2867fbb834dad02bf0a' 11 | -------------------------------------------------------------------------------- /example/shfmt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env chim 2 | 3 | [macos-x64] 4 | url = 'https://github.com/mvdan/sh/releases/download/v3.5.1/shfmt_v3.5.1_darwin_amd64' 5 | 6 | [macos-arm64] 7 | url = 'https://github.com/mvdan/sh/releases/download/v3.5.1/shfmt_v3.5.1_darwin_arm64' 8 | 9 | [linux-x64] 10 | url = 'https://github.com/mvdan/sh/releases/download/v3.5.1/shfmt_v3.5.1_linux_amd64' 11 | -------------------------------------------------------------------------------- /example/xz: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env chim 2 | 3 | [darwin-x64] 4 | url = "https://chim.s3.amazonaws.com/node-v18.8.0-darwin-x64.xz" 5 | checksum = "548db492cd6cbc81ac5996aff9e2cee607958268f2f6fdf0f1a83c3358c7010d" 6 | 7 | [linux-x64] 8 | url = "https://chim.s3.amazonaws.com/node-v18.8.0-linux-x64.xz" 9 | checksum = "44fd49378710695cf2fb9d4711a159e918394fb69ade55715e95840dbef702b2" 10 | -------------------------------------------------------------------------------- /packaging/chimstrap/chimstrap.envsubst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | #region logging setup 5 | if [ "${CHIMSTRAP_TRACE-}" = "1" ] || [ "${CHIMSTRAP_TRACE-}" = "true" ]; then 6 | set -x 7 | fi 8 | if [ "${CHIM_DEBUG-}" = "true" ] || [ "${CHIM_DEBUG-}" = "1" ]; then 9 | debug() { 10 | echo "$@" >&2 11 | } 12 | else 13 | debug() { 14 | : 15 | } 16 | fi 17 | 18 | if [ "${CHIM_QUIET-}" = "1" ] || [ "${CHIMSTRAP_QUIET-}" = "1" ] || 19 | [ "${CHIM_QUIET-}" = "true" ] || [ "${CHIMSTRAP_QUIET-}" = "true" ]; then 20 | info() { 21 | echo "$@" >&2 22 | } 23 | else 24 | info() { 25 | : 26 | } 27 | fi 28 | 29 | error() { 30 | echo "$@" >&2 31 | exit 1 32 | } 33 | #endregion 34 | 35 | #region environment setup 36 | get_os() { 37 | os="$(uname -s)" 38 | if [ "$os" = Darwin ]; then 39 | echo "macos" 40 | elif [ "$os" = Linux ]; then 41 | echo "linux" 42 | else 43 | error "unsupported OS: $os" 44 | fi 45 | } 46 | 47 | get_arch() { 48 | arch="$(uname -m)" 49 | if [ "$arch" = x86_64 ]; then 50 | echo "x64" 51 | elif [ "$arch" = aarch64 ] || [ "$arch" = arm64 ]; then 52 | echo "arm64" 53 | else 54 | error "unsupported architecture: $arch" 55 | fi 56 | } 57 | 58 | get_cache_dir() { 59 | # faster than calling `uname -s` 60 | if [ -d "${HOME}/Library/Caches" ] && [ -x /usr/bin/xcode-select ]; then 61 | echo "${HOME}/Library/Caches/chim" 62 | else 63 | echo "${HOME}/.cache/chim" 64 | fi 65 | } 66 | 67 | get_checksum() { 68 | os="$(get_os)" 69 | arch="$(get_arch)" 70 | 71 | checksum_linux_x86_64="$CHIM_CHECKSUM_LINUX_X86_64" 72 | checksum_linux_arm64="$CHIM_CHECKSUM_LINUX_ARM64" 73 | checksum_macos_x86_64="$CHIM_CHECKSUM_MACOS_X86_64" 74 | checksum_macos_arm64="$CHIM_CHECKSUM_MACOS_ARM64" 75 | 76 | if [ "$os" = "linux" ] && [ "$arch" = "x64" ]; then 77 | echo "$checksum_linux_x86_64" 78 | elif [ "$os" = "linux" ] && [ "$arch" = "arm64" ]; then 79 | echo "$checksum_linux_arm64" 80 | elif [ "$os" = "macos" ] && [ "$arch" = "x64" ]; then 81 | echo "$checksum_macos_x86_64" 82 | elif [ "$os" = "macos" ] && [ "$arch" = "arm64" ]; then 83 | echo "$checksum_macos_arm64" 84 | else 85 | warn "no checksum for $os-$arch" 86 | fi 87 | } 88 | 89 | #endregion 90 | 91 | download_file() { 92 | url="$1" 93 | filename="$(basename "$url")" 94 | cache_dir="$(mktemp -d)" 95 | file="$cache_dir/$filename" 96 | 97 | info "chimstrap: installing chim..." 98 | 99 | if command -v curl >/dev/null 2>&1; then 100 | debug ">" curl -fLlSso "$file" "$url" 101 | curl -fLlSso "$file" "$url" 102 | else 103 | if command -v wget >/dev/null 2>&1; then 104 | debug ">" wget -qO "$file" "$url" 105 | stderr=$(mktemp) 106 | wget -O "$file" "$url" >"$stderr" 2>&1 || error "wget failed: $(cat "$stderr")" 107 | else 108 | error "chimstrap requires curl or wget but neither is installed. Aborting." 109 | fi 110 | fi 111 | 112 | echo "$file" 113 | } 114 | 115 | install_chim() { 116 | # download the tarball 117 | version="$CHIM_VERSION" 118 | os="$(get_os)" 119 | arch="$(get_arch)" 120 | cache_dir="$(get_cache_dir)" 121 | tarball_url="https://chim.sh/releases/${version}/chim-${version}-${os}-${arch}.tar.gz" 122 | 123 | cache_file=$(download_file "${CHIMSTRAP_URL:-$tarball_url}") 124 | debug "chimstrap: cache_file is $cache_file" 125 | 126 | if [ -z "${CHIMSTRAP_URL:-}" ]; then 127 | debug "validating checksum" 128 | cd "$(dirname "$cache_file")" && get_checksum | sha256sum -c >/dev/null 129 | else 130 | debug "not validating checksum since CHIMSTRAP_URL was defined" 131 | fi 132 | 133 | # extract tarball 134 | mkdir -p "$cache_dir" 135 | tar -xzf "$cache_file" -C "$cache_dir/.." 136 | rm -f "$cache_file" 137 | } 138 | 139 | __chim_path="$(get_cache_dir)/bin/chim" 140 | 141 | if [ ! -x "$__chim_path" ]; then 142 | debug "chimstrap: chim not found in $__chim_path" 143 | install_chim 144 | fi 145 | 146 | debug "chimstrap: running chim with args:" "$@" 147 | exec "$__chim_path" "$@" 148 | -------------------------------------------------------------------------------- /packaging/deb/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | 3 | RUN apt-get update && apt-get install -y \ 4 | build-essential \ 5 | ruby \ 6 | && apt-get clean 7 | 8 | RUN gem install fpm 9 | -------------------------------------------------------------------------------- /packaging/deb/generate-release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | do_hash() { 5 | HASH_NAME=$1 6 | HASH_CMD=$2 7 | echo "${HASH_NAME}:" 8 | for f in $(find -type f); do 9 | f=$(echo $f | cut -c3-) # remove ./ prefix 10 | if [ "$f" = "Release" ]; then 11 | continue 12 | fi 13 | echo " $(${HASH_CMD} ${f} | cut -d" " -f1) $(wc -c $f)" 14 | done 15 | } 16 | 17 | cat << EOF 18 | Origin: Chim Repository 19 | Label: Chim 20 | Suite: stable 21 | Codename: stable 22 | Version: 1.0 23 | Architectures: amd64 arm64 24 | Components: main 25 | Description: https://chim.sh 26 | Date: $(date -Ru) 27 | EOF 28 | do_hash "MD5Sum" "md5sum" 29 | do_hash "SHA1" "sha1sum" 30 | do_hash "SHA256" "sha256sum" 31 | -------------------------------------------------------------------------------- /packaging/macos/homebrew.rb: -------------------------------------------------------------------------------- 1 | class Chim < Formula 2 | desc "Cross-platform binary fetcher/runner" 3 | homepage "https://chim.sh" 4 | license "MIT" 5 | version "$CHIM_VERSION" 6 | 7 | on_macos do 8 | if Hardware::CPU.intel? 9 | url "https://chim.sh/releases/v$CHIM_VERSION/chim-v$CHIM_VERSION-macos-x64.tar.xz" 10 | sha256 "$CHIM_CHECKSUM_MACOS_X86_64" 11 | 12 | def install 13 | bin.install "bin/chim" 14 | end 15 | end 16 | if Hardware::CPU.arm? 17 | url "https://chim.sh/releases/v$CHIM_VERSION/chim-v$CHIM_VERSION-macos-arm64.tar.xz" 18 | sha256 "$CHIM_CHECKSUM_MACOS_ARM64" 19 | 20 | def install 21 | bin.install "bin/chim" 22 | end 23 | end 24 | end 25 | 26 | on_linux do 27 | if Hardware::CPU.arm? && Hardware::CPU.is_64_bit? 28 | url "https://chim.sh/releases/v$CHIM_VERSION/chim-v$CHIM_VERSION-linux-arm64.tar.xz" 29 | sha256 "$CHIM_CHECKSUM_LINUX_ARM64" 30 | 31 | def install 32 | bin.install "bin/chim" 33 | end 34 | end 35 | if Hardware::CPU.intel? 36 | url "https://chim.sh/releases/v$CHIM_VERSION/chim-v$CHIM_VERSION-linux-x64.tar.xz" 37 | sha256 "$CHIM_CHECKSUM_LINUX_X86_64" 38 | 39 | def install 40 | bin.install "bin/chim" 41 | end 42 | end 43 | end 44 | 45 | test do 46 | system "#{bin}/chim --version" 47 | (testpath/"test-chim").write < 0 then exit; 14 | 15 | { App string to the end of the path variable } 16 | Paths := Paths + ';'+ Path +';' 17 | 18 | { Overwrite (or create if missing) path environment variable } 19 | if RegWriteStringValue(HKEY_LOCAL_MACHINE, EnvironmentKey, 'Path', Paths) 20 | then Log(Format('The [%s] added to PATH: [%s]', [Path, Paths])) 21 | else Log(Format('Error while adding the [%s] to PATH: [%s]', [Path, Paths])); 22 | end; 23 | 24 | procedure EnvRemovePath(Path: string); 25 | var 26 | Paths: string; 27 | P: Integer; 28 | begin 29 | { Skip if registry entry not exists } 30 | if not RegQueryStringValue(HKEY_LOCAL_MACHINE, EnvironmentKey, 'Path', Paths) then 31 | exit; 32 | 33 | { Skip if string not found in path } 34 | P := Pos(';' + Uppercase(Path) + ';', ';' + Uppercase(Paths) + ';'); 35 | if P = 0 then exit; 36 | 37 | { Update path variable } 38 | Delete(Paths, P - 1, Length(Path) + 1); 39 | 40 | { Overwrite path environment variable } 41 | if RegWriteStringValue(HKEY_LOCAL_MACHINE, EnvironmentKey, 'Path', Paths) 42 | then Log(Format('The [%s] removed from PATH: [%s]', [Path, Paths])) 43 | else Log(Format('Error while removing the [%s] from PATH: [%s]', [Path, Paths])); 44 | end; 45 | -------------------------------------------------------------------------------- /packaging/win/setup.iss: -------------------------------------------------------------------------------- 1 | ; Script generated by the Inno Setup Script Wizard. 2 | ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! 3 | #include "environment.iss" 4 | 5 | [Setup] 6 | AppName=chim 7 | AppVersion=1.1.1 8 | AppPublisher=Jeff Dickey 9 | AppSupportURL=https://chim.sh/ 10 | DefaultDirName={autopf}\chim 11 | SourceDir=..\.. 12 | OutputBaseFilename=chim-setup 13 | OutputDir=dist 14 | AppId=chim 15 | ChangesEnvironment=True 16 | 17 | [Files] 18 | Source: "target\release\chim.exe"; DestDir: "{app}\bin" 19 | Source: "README.md"; DestDir: "{app}"; Flags: isreadme 20 | 21 | [Tasks] 22 | Name: envPath; Description: "Add to PATH variable" 23 | 24 | [Code] 25 | procedure CurStepChanged(CurStep: TSetupStep); 26 | begin 27 | if CurStep = ssPostInstall 28 | then EnvAddPath(ExpandConstant('{app}') +'\bin'); 29 | end; 30 | 31 | procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); 32 | begin 33 | if CurUninstallStep = usPostUninstall 34 | then EnvRemovePath(ExpandConstant('{app}') +'\bin'); 35 | end; 36 | -------------------------------------------------------------------------------- /scripts/build-deb.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euxo pipefail 3 | 4 | CHIM_VERSION=$(./scripts/get-version.sh) 5 | 6 | tar -xvJf "dist/chim-$CHIM_VERSION-linux-x64.tar.xz" 7 | fpm -s dir -t deb \ 8 | --name chim \ 9 | --license MIT \ 10 | --version "${CHIM_VERSION#v*}" \ 11 | --architecture amd64 \ 12 | --description "Cross-platform binary shims with optional remote fetching" \ 13 | --url "https://chim.sh" \ 14 | --maintainer "Jeff Dickey @jdxcode" \ 15 | chim/bin/chim=/usr/bin/chim 16 | 17 | tar -xvJf "dist/chim-$CHIM_VERSION-linux-arm64.tar.xz" 18 | fpm -s dir -t deb \ 19 | --name chim \ 20 | --license MIT \ 21 | --version "${CHIM_VERSION#v*}" \ 22 | --architecture arm64 \ 23 | --description "Cross-platform binary shims with optional remote fetching" \ 24 | --url "https://chim.sh" \ 25 | --maintainer "Jeff Dickey @jdxcode" \ 26 | chim/bin/chim=/usr/bin/chim 27 | 28 | mkdir -p dist/deb/pool/main 29 | cp -v ./*.deb dist/deb/pool/main 30 | mkdir -p dist/deb/dists/stable/main/binary-amd64 31 | mkdir -p dist/deb/dists/stable/main/binary-arm64 32 | cd dist/deb 33 | dpkg-scanpackages --arch amd64 pool/ >dists/stable/main/binary-amd64/Packages 34 | dpkg-scanpackages --arch arm64 pool/ >dists/stable/main/binary-arm64/Packages 35 | gzip -9c dists/stable/main/binary-amd64/Packages.gz 36 | gzip -9c dists/stable/main/binary-arm64/Packages.gz 37 | cd ../.. 38 | 39 | cd dist/deb/dists/stable 40 | "$GITHUB_WORKSPACE/packaging/deb/generate-release.sh" >Release 41 | gpg -u 7E07A8D14B7A5595 -abs Release.gpg 42 | gpg -u 7E07A8D14B7A5595 -abs --clearsign InRelease 43 | cd "$GITHUB_WORKSPACE" 44 | -------------------------------------------------------------------------------- /scripts/build-rpm.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euxo pipefail 3 | 4 | CHIM_VERSION=$(./scripts/get-version.sh) 5 | 6 | tar -xvJf "dist/chim-$CHIM_VERSION-linux-x64.tar.xz" 7 | fpm -s dir -t rpm \ 8 | --name chim \ 9 | --license MIT \ 10 | --version "${CHIM_VERSION#v*}" \ 11 | --architecture x86_64 \ 12 | --description "Cross-platform binary shims with optional remote fetching" \ 13 | --url "https://chim.sh" \ 14 | --maintainer "Jeff Dickey @jdxcode" \ 15 | chim/bin/chim=/usr/bin/chim 16 | 17 | tar -xvJf "dist/chim-$CHIM_VERSION-linux-arm64.tar.xz" 18 | fpm -s dir -t rpm \ 19 | --name chim \ 20 | --license MIT \ 21 | --version "${CHIM_VERSION#v*}" \ 22 | --architecture aarch64 \ 23 | --description "Cross-platform binary shims with optional remote fetching" \ 24 | --url "https://chim.sh" \ 25 | --maintainer "Jeff Dickey @jdxcode" \ 26 | chim/bin/chim=/usr/bin/chim 27 | 28 | cat <~/.rpmmacros 29 | %_signature gpg 30 | %_gpg_name 7E07A8D14B7A5595 31 | EOF 32 | 33 | mkdir -p dist/rpmrepo/packages 34 | cp -v packaging/rpm/chim.repo dist/rpmrepo 35 | cp -v ./*.rpm dist/rpmrepo/packages 36 | rpm --addsign dist/rpmrepo/packages/*.rpm 37 | createrepo dist/rpmrepo 38 | gpg --batch --yes --detach-sign --armor dist/rpmrepo/repodata/repomd.xml 39 | -------------------------------------------------------------------------------- /scripts/build-tarball.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euxo pipefail 3 | 4 | error() { 5 | echo "$@" >&2 6 | exit 1 7 | } 8 | 9 | RUST_TRIPLE=${1:-$(rustc -vV | grep ^host: | cut -d ' ' -f2)} 10 | 11 | #region os/arch 12 | get_os() { 13 | case "$RUST_TRIPLE" in 14 | *-apple-darwin*) 15 | echo "macos" 16 | ;; 17 | *-linux-*) 18 | echo "linux" 19 | ;; 20 | *) 21 | error "unsupported OS: $RUST_TRIPLE" 22 | ;; 23 | esac 24 | } 25 | 26 | get_arch() { 27 | case "$RUST_TRIPLE" in 28 | aarch64-*) 29 | echo "arm64" 30 | ;; 31 | x86_64-*) 32 | echo "x64" 33 | ;; 34 | *) 35 | error "unsupported arch: $RUST_TRIPLE" 36 | ;; 37 | esac 38 | } 39 | #endregion 40 | 41 | VERSION=$(./scripts/get-version.sh) 42 | BASENAME=chim-$VERSION-$(get_os)-$(get_arch) 43 | 44 | #if [ "${CROSS:-}" = "1" ]; then 45 | # cross build --release --target "$RUST_TRIPLE" 46 | #else 47 | # cargo build --release --target "$RUST_TRIPLE" 48 | #fi 49 | 50 | mkdir -p "dist/chim/bin" 51 | cp "target/$RUST_TRIPLE/release/chim" "dist/chim/bin/chim" 52 | cp README.md "dist/chim/README.md" 53 | 54 | cd dist 55 | tar -cJf "$BASENAME.tar.xz" chim 56 | tar -czf "$BASENAME.tar.gz" chim 57 | 58 | echo "dist/$BASENAME.tar.xz" 59 | -------------------------------------------------------------------------------- /scripts/build-windows.ps1: -------------------------------------------------------------------------------- 1 | Get-ChildItem target\release 2 | New-Item dist\chim\bin -ItemType Directory -ea 0 3 | Copy-Item target\release\chim.exe dist\chim\bin\chim.exe 4 | $Env:CHIM_VERSION = (cargo get version --pretty) 5 | Compress-Archive -Path dist\chim -DestinationPath dist\chim-$env:CHIM_VERSION-windows-x64.zip 6 | -------------------------------------------------------------------------------- /scripts/get-version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | echo "v$(grep '^version =' Cargo.toml | head -n1 | cut -d '"' -f 2)" 5 | -------------------------------------------------------------------------------- /scripts/release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euxo pipefail 3 | 4 | git config --global user.name chim-bot 5 | git config --global user.email release@chim.sh 6 | 7 | CHIM_VERSION=$(cd chim && ./scripts/get-version.sh) 8 | RELEASE_DIR=chim.sh/static/releases 9 | rm -rf "${RELEASE_DIR:?}/$CHIM_VERSION" 10 | mkdir -p "$RELEASE_DIR/$CHIM_VERSION" 11 | 12 | cp artifacts/tarball-x86_64-pc-windows-gnu/*.zip "$RELEASE_DIR/$CHIM_VERSION" 13 | cp artifacts/tarball-x86_64-pc-windows-gnu/*.zip "$RELEASE_DIR/chim-latest-windows.zip" 14 | 15 | targets=( 16 | x86_64-unknown-linux-gnu 17 | aarch64-unknown-linux-gnu 18 | x86_64-apple-darwin 19 | aarch64-apple-darwin 20 | ) 21 | for target in "${targets[@]}"; do 22 | cp "artifacts/tarball-$target/"*.tar.gz "$RELEASE_DIR/$CHIM_VERSION" 23 | cp "artifacts/tarball-$target/"*.tar.xz "$RELEASE_DIR/$CHIM_VERSION" 24 | done 25 | 26 | platforms=( 27 | linux-x64 28 | linux-arm64 29 | macos-x64 30 | macos-arm64 31 | ) 32 | for platform in "${platforms[@]}"; do 33 | cp "$RELEASE_DIR/$CHIM_VERSION/chim-$CHIM_VERSION-$platform.tar.gz" "$RELEASE_DIR/chim-latest-$platform.tar.gz" 34 | cp "$RELEASE_DIR/$CHIM_VERSION/chim-$CHIM_VERSION-$platform.tar.xz" "$RELEASE_DIR/chim-latest-$platform.tar.xz" 35 | done 36 | 37 | pushd "$RELEASE_DIR" 38 | sha256sum ./*.zip ./*.tar.xz ./*.tar.gz >SHASUMS256.txt 39 | gpg --clearsign -u 7E07A8D14B7A5595 SHASUMS256.asc 40 | popd 41 | 42 | pushd "$RELEASE_DIR/$CHIM_VERSION" 43 | sha256sum ./* >SHASUMS256.txt 44 | gpg --clearsign -u 7E07A8D14B7A5595 SHASUMS256.asc 45 | popd 46 | 47 | export CHIM_VERSION RELEASE_DIR 48 | ./chim/scripts/render-chimstrap.sh >chim.sh/static/chimstrap 49 | 50 | rm -rf chim.sh/static/rpm 51 | mv artifacts/rpm chim.sh/static/rpm 52 | 53 | rm -rf chim.sh/static/deb 54 | mv artifacts/deb chim.sh/static/deb 55 | 56 | pushd chim.sh 57 | git add . && git commit -m "$CHIM_VERSION" 58 | popd 59 | 60 | ./chim/scripts/render-homebrew.sh >homebrew-tap/chim.rb 61 | pushd homebrew-tap 62 | git add . && git commit -m "$CHIM_VERSION" 63 | popd 64 | -------------------------------------------------------------------------------- /scripts/render-chimstrap.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euxo pipefail 3 | 4 | # shellcheck disable=SC2016 5 | CHIM_VERSION=$CHIM_VERSION \ 6 | CHIM_CHECKSUM_LINUX_X86_64=$(grep linux-x64.tar.gz "$RELEASE_DIR/$CHIM_VERSION/SHASUMS256.txt") \ 7 | CHIM_CHECKSUM_LINUX_ARM64=$(grep linux-arm64.tar.gz "$RELEASE_DIR/$CHIM_VERSION/SHASUMS256.txt") \ 8 | CHIM_CHECKSUM_MACOS_X86_64=$(grep macos-x64.tar.gz "$RELEASE_DIR/$CHIM_VERSION/SHASUMS256.txt") \ 9 | CHIM_CHECKSUM_MACOS_ARM64=$(grep macos-arm64.tar.gz "$RELEASE_DIR/$CHIM_VERSION/SHASUMS256.txt") \ 10 | envsubst '$CHIM_VERSION,$CHIM_CHECKSUM_LINUX_X86_64,$CHIM_CHECKSUM_LINUX_ARM64,$CHIM_CHECKSUM_MACOS_X86_64,$CHIM_CHECKSUM_MACOS_ARM64' \ 11 | { 11 | config: &'a Config, 12 | hooks: Hooks<'a>, 13 | } 14 | 15 | impl<'a> App<'a> { 16 | pub fn new(config: &'a Config) -> Result> { 17 | Ok(App { 18 | config, 19 | hooks: Hooks::new(config), 20 | }) 21 | } 22 | 23 | pub fn validate(&self, filename: &Path) -> Result<()> { 24 | let checksum = &self.config.checksum; 25 | match checksum { 26 | Some(checksum) => { 27 | debug!("validating checksum for {:?}", filename); 28 | checksum::validate(filename, checksum) 29 | .with_section(|| format!("URL: {}", self.config.url)) 30 | .with_suggestion(|| { 31 | format!( 32 | "ensure that checksum is valid in chim {}", 33 | self.config.chim_path.display(), 34 | ) 35 | })?; 36 | debug!("checksum is valid"); 37 | Ok(()) 38 | } 39 | None if self.config.paranoid => Err(eyre!("checksum is required in paranoid mode")), 40 | None => { 41 | info!("no checksum specified for {:?}", filename); 42 | Ok(()) 43 | } 44 | } 45 | } 46 | 47 | pub async fn fetch(&self, output: &Path) -> Result<()> { 48 | let url = match self.hooks.pre_fetch()? { 49 | url if url.is_empty() => self.config.url.clone(), 50 | url => url, 51 | }; 52 | debug!("fetching {}", url); 53 | 54 | fetchers::new(self.config) 55 | .fetch(&url, output) 56 | .await 57 | .wrap_err_with(|| format!("error fetching {}", url))?; 58 | 59 | Ok(()) 60 | } 61 | 62 | pub fn extract(&self, filename: &Path) -> Result<()> { 63 | let dest = &self.config.cache_path; 64 | debug!("extracting archive {:?} to {:?}", filename, dest); 65 | self.hooks.pre_extract()?; 66 | archive::extract(filename, dest, &self.config.bin_path, &self.config.archive)?; 67 | 68 | Ok(()) 69 | } 70 | 71 | pub fn exec(&self, args: Vec) -> Result<()> { 72 | let bin = &self.config.bin_path; 73 | let execvp = self.config.execvp; 74 | 75 | debug!("executing platform binary {:?}", bin); 76 | self.hooks.pre_execute()?; 77 | bin::new(bin.as_os_str()) 78 | .args(args.iter().skip(2).map(|s| s.as_ref())) 79 | .execvp(execvp) 80 | .exec()?; 81 | self.hooks.post_execute()?; 82 | 83 | Ok(()) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/archive.rs: -------------------------------------------------------------------------------- 1 | use crate::config; 2 | use bzip2::read::BzDecoder; 3 | use color_eyre::Result; 4 | use flate2::read::GzDecoder; 5 | use std::fs::{create_dir_all, File}; 6 | use std::io::Read; 7 | use std::path::Path; 8 | use tar::Archive; 9 | use xz::read::XzDecoder; 10 | 11 | #[cfg(not(target_os = "windows"))] 12 | use std::os::unix::fs::PermissionsExt; 13 | 14 | pub fn extract( 15 | filename: &Path, 16 | destination: &Path, 17 | bin_path: &Path, 18 | archive: &config::Archive, 19 | ) -> Result<()> { 20 | let file = File::open(filename)?; 21 | let mut input = decode(file, archive); 22 | 23 | match archive { 24 | config::Archive::TarGz 25 | | config::Archive::TarXz 26 | | config::Archive::TarBz2 27 | | config::Archive::Tar => { 28 | let mut archive = Archive::new(input); 29 | archive.unpack(destination)?; 30 | } 31 | config::Archive::Gz 32 | | config::Archive::Xz 33 | | config::Archive::Bz2 34 | | config::Archive::None => { 35 | create_dir_all(Path::new(bin_path).parent().unwrap())?; 36 | let mut output = File::create(bin_path)?; 37 | make_executable(&mut output)?; 38 | 39 | std::io::copy(&mut input, &mut output)?; 40 | } 41 | config::Archive::Zip => { 42 | let input = File::open(filename)?; 43 | let mut archive = zip::ZipArchive::new(input)?; 44 | archive.extract(destination)?; 45 | } 46 | } 47 | 48 | Ok(()) 49 | } 50 | 51 | fn decode(file: File, archive: &config::Archive) -> Box { 52 | match archive { 53 | config::Archive::TarGz | config::Archive::Gz => Box::new(GzDecoder::new(file)), 54 | config::Archive::TarXz | config::Archive::Xz => Box::new(XzDecoder::new(file)), 55 | config::Archive::TarBz2 | config::Archive::Bz2 => Box::new(BzDecoder::new(file)), 56 | config::Archive::Tar | config::Archive::None | config::Archive::Zip => Box::new(file), 57 | } 58 | } 59 | 60 | #[cfg(target_os = "windows")] 61 | fn make_executable(_file: &mut File) -> Result<()> { 62 | Ok(()) 63 | } 64 | 65 | #[cfg(not(target_os = "windows"))] 66 | fn make_executable(file: &mut File) -> Result<()> { 67 | let metadata = file.metadata()?; 68 | let mut permissions = metadata.permissions(); 69 | permissions.set_mode(0o755); 70 | file.set_permissions(permissions)?; 71 | Ok(()) 72 | } 73 | -------------------------------------------------------------------------------- /src/bin.rs: -------------------------------------------------------------------------------- 1 | #[cfg(unix)] 2 | use color_eyre::eyre::eyre; 3 | use color_eyre::eyre::{Context, Result}; 4 | use itertools::Itertools; 5 | use std::ffi::OsStr; 6 | use std::process::{exit, Command}; 7 | 8 | pub struct Bin 9 | where 10 | T: AsRef, 11 | { 12 | program: T, 13 | args: Vec, 14 | execvp: bool, 15 | } 16 | 17 | pub fn new(program: T) -> Bin 18 | where 19 | T: AsRef, 20 | { 21 | Bin { 22 | program, 23 | args: Vec::new(), 24 | execvp: false, 25 | } 26 | } 27 | 28 | impl Bin 29 | where 30 | T: AsRef, 31 | { 32 | pub fn args(mut self, args: I) -> Self 33 | where 34 | I: IntoIterator, 35 | { 36 | self.args = args.into_iter().collect(); 37 | 38 | self 39 | } 40 | 41 | pub fn execvp(mut self, execvp: bool) -> Self { 42 | self.execvp = execvp; 43 | 44 | self 45 | } 46 | 47 | pub fn exec(self) -> Result<()> { 48 | match self.execvp { 49 | true => self.do_execvp(), 50 | false => self.do_subprocess(), 51 | } 52 | .with_context(|| { 53 | format!( 54 | "Error executing {} with args: {}", 55 | display_os_str(&self.program), 56 | display_args(&self.args), 57 | ) 58 | }) 59 | } 60 | 61 | #[cfg(unix)] 62 | #[cfg(not(tarpaulin_include))] 63 | fn do_execvp(&self) -> Result<()> { 64 | debug!( 65 | "execvp: {} {}", 66 | display_os_str(&self.program), 67 | display_args(&self.args) 68 | ); 69 | let err = exec::Command::new(&self.program).args(&self.args).exec(); 70 | 71 | // always errors if it gets here 72 | Err(eyre!("execvp failed: {}", err)) 73 | } 74 | 75 | #[cfg(not(unix))] 76 | fn do_execvp(&self) -> Result<()> { 77 | self.do_subprocess() 78 | } 79 | 80 | fn do_subprocess(&self) -> Result<()> { 81 | debug!( 82 | "subprocess: {} {}", 83 | display_os_str(&self.program), 84 | display_args(&self.args) 85 | ); 86 | 87 | let status = Command::new(&self.program).args(&self.args).status()?; 88 | 89 | debug!("subprocess exited with {status}"); 90 | 91 | if status.code() != Some(0) { 92 | exit(status.code().unwrap_or(1)); 93 | } 94 | 95 | Ok(()) 96 | } 97 | } 98 | 99 | fn display_args(args: &[I]) -> String 100 | where 101 | I: AsRef, 102 | { 103 | args.iter().map(display_os_str).join(" ") 104 | } 105 | 106 | fn display_os_str(os_str: T) -> String 107 | where 108 | T: AsRef, 109 | { 110 | return os_str.as_ref().to_string_lossy().to_string(); 111 | } 112 | 113 | #[cfg(test)] 114 | mod tests { 115 | use super::*; 116 | 117 | #[test] 118 | fn test_exec() { 119 | let result = new("test").args(["1"]).exec(); 120 | assert!(result.is_ok()); 121 | } 122 | 123 | #[test] 124 | fn test_exec_invalid_bin() { 125 | let result = new("invalid_bin").exec(); 126 | assert!(result.is_err()); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/checksum.rs: -------------------------------------------------------------------------------- 1 | use color_eyre::eyre::{eyre, Result}; 2 | use color_eyre::owo_colors::OwoColorize; 3 | use color_eyre::Section; 4 | use sha2::{Digest, Sha256, Sha512}; 5 | use std::path::Path; 6 | use std::{fs, io}; 7 | 8 | pub fn validate(filename: &Path, checksum: &str) -> Result<()> { 9 | let (algo, expected) = split_checksum(checksum); 10 | 11 | let actual = match algo { 12 | "sha256" => get_checksum::(filename)?, 13 | "sha512" => get_checksum::(filename)?, 14 | _ => return Err(eyre!("unsupported checksum algorithm: {}", algo)), 15 | }; 16 | 17 | if actual != expected { 18 | display_mismatch_err(&actual, expected)?; 19 | } 20 | 21 | Ok(()) 22 | } 23 | 24 | pub fn get_checksum(file: &Path) -> Result { 25 | let mut hasher = D::new(); 26 | let mut file = fs::File::open(file)?; 27 | io::copy(&mut file, &mut hasher)?; 28 | 29 | Ok(hex::encode(hasher.finalize())) 30 | } 31 | 32 | fn split_checksum(checksum: &str) -> (&str, &str) { 33 | let mut split = checksum.split(':'); 34 | let algorithm = split.next().unwrap(); 35 | let hex_digest = split.next().unwrap(); 36 | (algorithm, hex_digest) 37 | } 38 | 39 | fn display_mismatch_err(actual: &str, expected: &str) -> Result<()> { 40 | Err(eyre!("checksum mismatch").section(format!( 41 | "Expected: {}\nActual: {}", 42 | expected.green(), 43 | actual.red() 44 | ))) 45 | } 46 | 47 | #[cfg(test)] 48 | mod tests { 49 | use super::*; 50 | use pretty_assertions::assert_eq; 51 | use std::fs::File; 52 | use std::io::Write; 53 | use tempfile::tempdir; 54 | 55 | #[test] 56 | fn test_split_checksum() { 57 | let (algo, expected) = split_checksum("sha256:1234567890abcdef"); 58 | assert_eq!(algo, "sha256"); 59 | assert_eq!(expected, "1234567890abcdef"); 60 | } 61 | 62 | #[test] 63 | fn test_get_checksum() { 64 | let dir = tempdir().unwrap(); 65 | let file = dir.path().join("test.txt"); 66 | let mut f = File::create(&file).unwrap(); 67 | f.write_all(b"hello world").unwrap(); 68 | 69 | let checksum = get_checksum::(&file).unwrap(); 70 | assert_eq!( 71 | checksum, 72 | "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9" 73 | ); 74 | } 75 | 76 | #[test] 77 | fn test_validate() { 78 | let dir = tempdir().unwrap(); 79 | let file = dir.path().join("test.txt"); 80 | let mut f = File::create(&file).unwrap(); 81 | f.write_all(b"hello world").unwrap(); 82 | 83 | validate( 84 | &file, 85 | "sha256:b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9", 86 | ) 87 | .unwrap(); 88 | assert!(validate(&file, "sha256:invalid").is_err()); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/chim_file.rs: -------------------------------------------------------------------------------- 1 | use crate::platform::split_platform_name; 2 | use color_eyre::eyre::Context; 3 | use color_eyre::{Result, Section}; 4 | use serde_derive::Deserialize; 5 | use std::collections::HashMap; 6 | use std::fs; 7 | use std::path::Path; 8 | 9 | #[derive(Debug, Deserialize, Default)] 10 | pub struct ChimFile { 11 | #[serde(default)] 12 | pub debug: bool, 13 | 14 | #[serde(default)] 15 | pub quiet: bool, 16 | 17 | pub url: Option, 18 | pub path: Option, 19 | pub checksum: Option, 20 | pub archive: Option, 21 | pub execvp: Option, 22 | 23 | // s3 24 | pub aws_profile: Option, 25 | pub aws_access_key_id: Option, 26 | pub aws_secret_access_key: Option, 27 | pub aws_access_token: Option, 28 | pub aws_region: Option, 29 | 30 | // hooks 31 | pub pre_fetch: Option, 32 | pub pre_extract: Option, 33 | pub pre_execute: Option, 34 | pub post_execute: Option, 35 | 36 | pub pre_execute_interval: Option, 37 | 38 | #[serde(flatten)] 39 | pub platforms: HashMap, 40 | } 41 | 42 | #[derive(Debug, Deserialize, PartialEq, Eq, Hash, Default)] 43 | pub struct Platform { 44 | pub url: Option, 45 | pub path: Option, 46 | pub checksum: Option, 47 | pub archive: Option, 48 | pub execvp: Option, 49 | 50 | // s3 51 | pub aws_profile: Option, 52 | pub aws_access_key_id: Option, 53 | pub aws_secret_access_key: Option, 54 | pub aws_access_token: Option, 55 | pub aws_region: Option, 56 | } 57 | 58 | impl ChimFile { 59 | pub fn from_file(filename: &Path) -> Result { 60 | let body = fs::read_to_string(filename).suggestion("ensure file exists and can be read")?; 61 | ChimFile::from_str(body).wrap_err("error parsing toml") 62 | } 63 | 64 | fn from_str(s: String) -> Result { 65 | let mut c: ChimFile = toml::from_str(&s).suggestion("Ensure chim is valid TOML.")?; 66 | c.normalize_platforms(); 67 | 68 | Ok(c) 69 | } 70 | 71 | fn normalize_platforms(&mut self) { 72 | let keys = self.platforms.keys().cloned().collect::>(); 73 | for k in keys { 74 | let (os, arch) = split_platform_name(&k.to_lowercase()); 75 | let platform = self.platforms.remove(&k).unwrap(); 76 | self.platforms.insert(format!("{os}-{arch}"), platform); 77 | } 78 | } 79 | } 80 | 81 | #[cfg(test)] 82 | mod tests { 83 | use super::*; 84 | use pretty_assertions::assert_eq; 85 | 86 | #[test] 87 | fn test_normalize_platforms() { 88 | let mut cf = ChimFile { 89 | platforms: vec![("darwin-arm64".to_string(), Platform::default())] 90 | .into_iter() 91 | .collect(), 92 | ..ChimFile::default() 93 | }; 94 | 95 | cf.normalize_platforms(); 96 | 97 | assert_eq!(cf.platforms.len(), 1); 98 | assert!(cf.platforms.contains_key("macos-aarch64")); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/cli/checksums.rs: -------------------------------------------------------------------------------- 1 | use crate::checksum::get_checksum; 2 | use crate::config::Config; 3 | use crate::fetchers; 4 | use crate::platform::split_platform_name; 5 | use color_eyre::eyre::Result; 6 | use sha2::Sha256; 7 | use std::fs; 8 | use std::path::{Path, PathBuf}; 9 | use tempfile::tempdir; 10 | use toml_edit::{value, Document}; 11 | 12 | #[derive(Debug, clap::Args)] 13 | #[clap(about = "Regenerates all checksums in a chim")] 14 | pub struct Args { 15 | #[clap(help = "The path to the chim file to update")] 16 | chim_file: PathBuf, 17 | } 18 | 19 | pub async fn run(args: Args) -> Result<()> { 20 | let filename = &args.chim_file; 21 | let mut doc = read(filename)?; 22 | trace!("{}", doc.to_string()); 23 | 24 | for (platform, values) in doc.iter_mut() { 25 | if !values.is_table() { 26 | continue; 27 | } 28 | values["checksum"] = value(fetch_checksum(filename, &platform).await?); 29 | } 30 | 31 | debug!("{}", doc.to_string()); 32 | write(filename, doc)?; 33 | 34 | info!("updated checksums in {:?}", filename); 35 | Ok(()) 36 | } 37 | 38 | fn read(filename: &Path) -> Result { 39 | trace!("reading {:?}", filename); 40 | let toml = fs::read_to_string(filename)?; 41 | let doc = toml.parse::()?; 42 | 43 | Ok(doc) 44 | } 45 | 46 | fn write(filename: &Path, doc: Document) -> Result<()> { 47 | trace!("writing {:?}", filename); 48 | fs::write(filename, doc.to_string())?; 49 | 50 | Ok(()) 51 | } 52 | 53 | async fn fetch_checksum(filename: &Path, platform: &str) -> Result { 54 | let (os, arch) = split_platform_name(platform); 55 | let config = Config::from_chim_file(filename, &os, &arch)?; 56 | let tmpdir = tempdir()?; 57 | let tmpfile = tmpdir.path().join("archive"); 58 | 59 | info!("fetching checksum for {}", config.url); 60 | fetchers::new(&config).fetch(&config.url, &tmpfile).await?; 61 | 62 | let checksum = format!("sha256:{}", get_checksum::(&tmpfile)?); 63 | info!("checksum: {}", checksum); 64 | 65 | Ok(checksum) 66 | } 67 | 68 | #[cfg(test)] 69 | #[cfg(feature = "test-e2e")] 70 | mod tests { 71 | use super::*; 72 | use pretty_assertions::assert_eq; 73 | use std::fs::File; 74 | use std::io::Write; 75 | use std::path::PathBuf; 76 | use tempfile::{tempdir, TempDir}; 77 | 78 | #[tokio::test] 79 | async fn test_checksums() { 80 | let dir = tempdir().unwrap(); 81 | let chim_path = create_chim(&dir); 82 | run(Args { 83 | chim_file: chim_path.clone(), 84 | }) 85 | .await 86 | .unwrap(); 87 | 88 | assert_eq!( 89 | fs::read_to_string(&chim_path).unwrap(), 90 | r#"#!/usr/bin/env chim 91 | execvp = false 92 | [macos-arm64] 93 | url = 'https://nodejs.org/dist/v18.7.0/node-v18.7.0-darwin-arm64.tar.gz' 94 | path = 'node-v18.7.0-darwin-arm64/bin/node' 95 | checksum = "sha256:ea24b35067bd0dc40ea8fda1087acc87672cbcbba881f7477dbd432e3c03343d" 96 | 97 | [win-x64] 98 | url = 'https://nodejs.org/dist/v18.7.0/node-v18.7.0-win-x64.zip' 99 | path = 'node-v18.7.0-win-x64\node.exe' 100 | checksum = "sha256:9c0abfe32291dd5bed717463cb3590004289f03ab66011e383daa0fcec674683" 101 | "# 102 | ); 103 | } 104 | 105 | fn create_chim(dir: &TempDir) -> PathBuf { 106 | let filename = dir.path().join("node"); 107 | let mut file = File::create(&filename).unwrap(); 108 | file.write_all( 109 | br#"#!/usr/bin/env chim 110 | execvp = false 111 | [macos-arm64] 112 | url = 'https://nodejs.org/dist/v18.7.0/node-v18.7.0-darwin-arm64.tar.gz' 113 | path = 'node-v18.7.0-darwin-arm64/bin/node' 114 | 115 | [win-x64] 116 | url = 'https://nodejs.org/dist/v18.7.0/node-v18.7.0-win-x64.zip' 117 | path = 'node-v18.7.0-win-x64\node.exe' 118 | "#, 119 | ) 120 | .unwrap(); 121 | 122 | filename 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/cli/mod.rs: -------------------------------------------------------------------------------- 1 | mod checksums; 2 | mod run; 3 | mod version; 4 | 5 | use clap::{Parser, Subcommand}; 6 | use color_eyre::Result; 7 | use std::path::Path; 8 | 9 | #[derive(Debug, Parser)] 10 | #[clap(version, about, long_about=None, name="chim", help_expected=true, subcommand_required=true, arg_required_else_help=true)] 11 | struct Cli { 12 | #[clap(subcommand)] 13 | command: Option, 14 | } 15 | 16 | #[derive(Debug, Subcommand)] 17 | enum Commands { 18 | Checksums(checksums::Args), 19 | } 20 | 21 | pub async fn parse(args: Vec) -> Result<()> { 22 | if let Some(arg) = args.get(1) { 23 | match arg.as_ref() { 24 | arg if arg_is_path(arg) => return run::run(args).await, 25 | "-v" | "version" => return version::run(), 26 | _ => {} 27 | } 28 | }; 29 | 30 | match Cli::parse_from(args).command.unwrap() { 31 | Commands::Checksums(args) => checksums::run(args).await, 32 | } 33 | } 34 | 35 | /// detects if we should attempt to run a chim or not 36 | /// this should be true if called from a shebang or .bat file 37 | fn arg_is_path(arg: &str) -> bool { 38 | arg.starts_with('.') 39 | || arg.starts_with('/') 40 | || arg.starts_with('~') 41 | || Path::new(arg).is_absolute() 42 | } 43 | 44 | #[cfg(test)] 45 | mod tests { 46 | use super::*; 47 | 48 | #[tokio::test] 49 | async fn test_version() { 50 | parse(vec!["chim".to_string(), "-v".to_string()]) 51 | .await 52 | .unwrap(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/cli/run.rs: -------------------------------------------------------------------------------- 1 | use crate::app::App; 2 | use crate::config::{Config, Fetcher}; 3 | use color_eyre::eyre::Result; 4 | use color_eyre::Section; 5 | use std::env::consts::{ARCH, OS}; 6 | use std::path::Path; 7 | 8 | pub async fn run(args: Vec) -> Result<()> { 9 | let filename = Path::new(&args[1]); 10 | let config = Config::from_chim_file(filename, OS, ARCH) 11 | .with_section(|| format!("Chim: {}", filename.to_string_lossy()))?; 12 | debug!("config: {:#?}", config); 13 | 14 | let app = App::new(&config)?; 15 | if !config.bin_exists() { 16 | match config.fetcher { 17 | Fetcher::Local => {} 18 | _ => { 19 | let tmpdir = tempfile::tempdir()?; 20 | let archive = tmpdir.path().join("archive"); 21 | app.fetch(&archive).await?; 22 | app.validate(&archive)?; 23 | app.extract(&archive)?; 24 | } 25 | } 26 | } 27 | app.exec(args) 28 | } 29 | 30 | #[cfg(test)] 31 | #[cfg(feature = "test-e2e")] 32 | mod tests { 33 | use super::*; 34 | use std::fs::File; 35 | use std::io::Write; 36 | use std::path::PathBuf; 37 | use tempfile::{tempdir, TempDir}; 38 | 39 | #[tokio::test] 40 | async fn test_app() { 41 | if cfg!(target_os = "linux") && cfg!(target_arch = "aarch64") { 42 | warn!("skipping test_app on linux-aarch64 since node binary does not work in alpine"); 43 | return; 44 | } 45 | let dir = tempdir().unwrap(); 46 | let chim_path = create_chim(&dir); 47 | run(args_to_str(vec!["node", chim_path.to_str().unwrap(), "-v"])) 48 | .await 49 | .unwrap(); 50 | } 51 | 52 | #[tokio::test] 53 | async fn test_jq() { 54 | let chim_path = Path::new("example/jq"); 55 | run(args_to_str(vec!["jq", chim_path.to_str().unwrap(), "-V"])) 56 | .await 57 | .unwrap(); 58 | } 59 | 60 | fn create_chim(dir: &TempDir) -> PathBuf { 61 | let filename = dir.path().join("node"); 62 | let mut file = File::create(&filename).unwrap(); 63 | file.write_all( 64 | br#"#!/usr/bin/env chim 65 | 66 | post_execute = 'echo post_execute' # disables execvp 67 | 68 | [macos-arm64] 69 | url = 'https://nodejs.org/dist/v18.7.0/node-v18.7.0-darwin-arm64.tar.gz' 70 | path = 'node-v18.7.0-darwin-arm64/bin/node' 71 | checksum = "sha256:ea24b35067bd0dc40ea8fda1087acc87672cbcbba881f7477dbd432e3c03343d" 72 | 73 | [darwin-x86_64] 74 | url = 'https://nodejs.org/dist/v18.7.0/node-v18.7.0-darwin-x64.tar.gz' 75 | path = 'node-v18.7.0-darwin-x64/bin/node' 76 | checksum = "sha256:ce95b924b450edbcfeaf422b3635a6b44b17ad23cd1f5efff6b051c60db548c8" 77 | 78 | [linux-x64] 79 | url = 'https://nodejs.org/dist/v18.7.0/node-v18.7.0-linux-x64.tar.xz' 80 | path = 'node-v18.7.0-linux-x64/bin/node' 81 | checksum = "sha256:8bc6a1b9deaed2586d726fc62d4bee9c1bfc5a30b96c1c4cff7edd15225a11a2" 82 | 83 | [linux-arm64] 84 | url = 'https://nodejs.org/dist/v18.7.0/node-v18.7.0-linux-arm64.tar.xz' 85 | path = 'node-v18.7.0-linux-arm64/bin/node' 86 | checksum = "sha256:c3ac4905ec3993d00a45d2c7af8417e79e907be51b8ffecb54c5b9ab8ef0bc9f" 87 | 88 | [win-x64] 89 | url = 'https://nodejs.org/dist/v18.7.0/node-v18.7.0-win-x64.zip' 90 | path = 'node-v18.7.0-win-x64\node.exe' 91 | checksum = "sha256:9c0abfe32291dd5bed717463cb3590004289f03ab66011e383daa0fcec674683" 92 | "#, 93 | ) 94 | .unwrap(); 95 | 96 | filename 97 | } 98 | 99 | fn args_to_str(input: Vec<&str>) -> Vec { 100 | input.into_iter().map(String::from).collect() 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/cli/version.rs: -------------------------------------------------------------------------------- 1 | use color_eyre::Result; 2 | 3 | pub fn run() -> Result<()> { 4 | println!("chim {}", env!("CARGO_PKG_VERSION")); 5 | Ok(()) 6 | } 7 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use crate::chim_file::ChimFile; 2 | use crate::chim_file::Platform; 3 | use crate::env; 4 | use color_eyre::eyre::{eyre, Report, Result}; 5 | use color_eyre::Section; 6 | use reqwest::Url; 7 | use sha2::{Digest, Sha256}; 8 | use std::path::{Path, PathBuf}; 9 | 10 | #[derive(Debug)] 11 | pub enum Fetcher { 12 | Local, 13 | Http, 14 | S3, 15 | Gcs, 16 | Abs, 17 | Scp, 18 | // Git, 19 | } 20 | 21 | #[derive(Debug)] 22 | pub enum Archive { 23 | TarGz, 24 | TarXz, 25 | TarBz2, 26 | Tar, 27 | Zip, 28 | Gz, 29 | Xz, 30 | Bz2, 31 | None, 32 | } 33 | 34 | #[derive(Debug)] 35 | pub struct Config { 36 | pub chim_path: PathBuf, 37 | pub name: String, 38 | 39 | pub fetcher: Fetcher, 40 | pub archive: Archive, 41 | pub url: String, 42 | pub checksum: Option, 43 | pub execvp: bool, 44 | pub paranoid: bool, 45 | pub quiet: bool, 46 | 47 | pub bin_path: PathBuf, 48 | pub cache_path: PathBuf, 49 | 50 | // s3 51 | pub aws_profile: Option, 52 | pub aws_access_key_id: Option, 53 | pub aws_secret_access_key: Option, 54 | pub aws_access_token: Option, 55 | pub aws_region: Option, 56 | 57 | // hooks 58 | pub pre_fetch: Option, 59 | pub pre_extract: Option, 60 | pub pre_execute: Option, 61 | pub post_execute: Option, 62 | //pub pre_execute_interval: Option, 63 | } 64 | 65 | impl Config { 66 | pub fn from_chim_file(chim_path: &Path, os: &str, arch: &str) -> Result { 67 | let chim_file = ChimFile::from_file(chim_path)?; 68 | let name = chim_path.file_name().unwrap().to_string_lossy().to_string(); 69 | let chim_dir = chim_path.parent().unwrap(); 70 | 71 | let default_platform = Platform::default(); 72 | let platform = chim_file 73 | .platforms 74 | .get(&format!("{}-{}", os, arch)) 75 | .or_else(|| match (os, arch) { 76 | ("macos", "aarch64") => chim_file.platforms.get("macos-x86_64"), 77 | _ => None, 78 | }) 79 | .unwrap_or(&default_platform); 80 | 81 | let url = get_url(&chim_file, platform); 82 | let archive = get_archive(&chim_file, platform, &url)?; 83 | let fetcher = get_fetcher(&url)?; 84 | let path = get_path(&chim_file, platform, &url, &archive) 85 | .ok_or_else(|| show_no_url_or_path_error(&fetcher, os, arch))?; 86 | 87 | let cache_path = get_cache_path(&url)?; 88 | let bin_path = get_bin_path(&fetcher, chim_dir, &cache_path, &path); 89 | 90 | Ok(Config { 91 | chim_path: chim_path.to_path_buf(), 92 | name, 93 | fetcher, 94 | archive, 95 | url, 96 | checksum: get_checksum(&chim_file, platform), 97 | bin_path, 98 | cache_path, 99 | execvp: get_execvp(&chim_file, platform), 100 | paranoid: get_paranoid(), 101 | quiet: get_quiet(&chim_file), 102 | 103 | // s3 104 | aws_profile: get_aws_profile(&chim_file, platform), 105 | aws_access_key_id: get_aws_access_key_id(&chim_file, platform), 106 | aws_secret_access_key: get_aws_secret_access_key(&chim_file, platform), 107 | aws_access_token: get_aws_access_token(&chim_file, platform), 108 | aws_region: get_aws_region(&chim_file, platform), 109 | 110 | // hooks 111 | pre_fetch: chim_file.pre_fetch, 112 | pre_extract: chim_file.pre_extract, 113 | pre_execute: chim_file.pre_execute, 114 | post_execute: chim_file.post_execute, 115 | //pre_execute_interval: chim_file.pre_execute_interval, 116 | }) 117 | } 118 | 119 | pub fn bin_exists(&self) -> bool { 120 | Path::exists(self.bin_path.as_path()) 121 | } 122 | } 123 | 124 | /// sha256 encode a string as hex 125 | fn str_to_sha256(s: &str) -> String { 126 | let mut sha256 = Sha256::new(); 127 | sha256.update(s.as_bytes()); 128 | 129 | hex::encode(sha256.finalize()) 130 | } 131 | 132 | fn get_url(chim_file: &ChimFile, platform: &Platform) -> String { 133 | platform 134 | .url 135 | .clone() 136 | .or_else(|| chim_file.url.clone()) 137 | .unwrap_or_else(|| String::from("local:")) 138 | } 139 | 140 | fn get_cache_path(url: &str) -> Result { 141 | Ok(get_cache_root()?.join(str_to_sha256(url))) 142 | } 143 | 144 | fn get_bin_path(fetcher: &Fetcher, chim_dir: &Path, cache_path: &Path, path: &str) -> PathBuf { 145 | match fetcher { 146 | Fetcher::Local => { 147 | if path.starts_with('/') { 148 | Path::new(path) 149 | } else { 150 | chim_dir 151 | } 152 | } 153 | _ => cache_path, 154 | } 155 | .join(path) 156 | } 157 | 158 | fn get_path( 159 | chim_file: &ChimFile, 160 | platform: &Platform, 161 | url: &str, 162 | archive: &Archive, 163 | ) -> Option { 164 | platform 165 | .path 166 | .clone() 167 | .or_else(|| chim_file.path.clone()) 168 | .or_else(|| match archive { 169 | Archive::Gz | Archive::Bz2 | Archive::Xz | Archive::None => { 170 | if url == "local:" { 171 | return None; 172 | } 173 | Some( 174 | get_filename_from_url(url) 175 | .unwrap() 176 | .trim_end_matches(".gz") 177 | .trim_end_matches(".xz") 178 | .trim_end_matches(".bz2") 179 | .to_string(), 180 | ) 181 | } 182 | _ => None, 183 | }) 184 | } 185 | 186 | fn get_checksum(chim_file: &ChimFile, platform: &Platform) -> Option { 187 | match platform 188 | .checksum 189 | .clone() 190 | .or_else(|| chim_file.checksum.clone()) 191 | { 192 | Some(checksum) if !checksum.contains(':') => Some(format!("sha256:{}", checksum)), 193 | Some(checksum) => Some(checksum), 194 | None => None, 195 | } 196 | } 197 | 198 | fn get_fetcher(url: &str) -> Result { 199 | match url.split(':').next().unwrap() { 200 | "local" => Ok(Fetcher::Local), 201 | "http" | "https" => Ok(Fetcher::Http), 202 | "s3" => Ok(Fetcher::S3), 203 | "gs" => Ok(Fetcher::Gcs), 204 | "abs" => Ok(Fetcher::Abs), 205 | "scp" => Ok(Fetcher::Scp), 206 | _ => Err(eyre!("unsupported url protocol: {}", url)), 207 | } 208 | } 209 | 210 | fn get_archive(chim_file: &ChimFile, platform: &Platform, url: &str) -> Result { 211 | let archive = platform 212 | .archive 213 | .clone() 214 | .or_else(|| chim_file.archive.clone()); 215 | match &archive { 216 | Some(archive) => match extension_to_archive(&format!(".{archive}")) { 217 | Archive::None => Err(eyre!("unsupported archive: {}", archive)), 218 | a => Ok(a), 219 | }, 220 | None => { 221 | let filename = get_filename_from_url(url)?; 222 | Ok(extension_to_archive(&filename)) 223 | } 224 | } 225 | } 226 | 227 | fn extension_to_archive(f: &str) -> Archive { 228 | match f { 229 | f if f.ends_with(".tar.xz") || f.ends_with(".txz") => Archive::TarXz, 230 | f if f.ends_with(".tar.gz") || f.ends_with(".tgz") => Archive::TarGz, 231 | f if f.ends_with(".tar.bz2") || f.ends_with(".tbz2") => Archive::TarBz2, 232 | f if f.ends_with(".tar") => Archive::Tar, 233 | f if f.ends_with(".zip") => Archive::Zip, 234 | f if f.ends_with(".xz") => Archive::Xz, 235 | f if f.ends_with(".gz") => Archive::Gz, 236 | f if f.ends_with(".bz2") => Archive::Bz2, 237 | _ => Archive::None, 238 | } 239 | } 240 | 241 | fn get_execvp(chim_file: &ChimFile, platform: &Platform) -> bool { 242 | if env::var_is_false("CHIM_EXECVP") || chim_file.post_execute.is_some() { 243 | return false; 244 | } 245 | match platform.execvp { 246 | Some(execvp) => execvp, 247 | None => chim_file.execvp.unwrap_or(true), 248 | } 249 | } 250 | 251 | fn get_aws_profile(chim_file: &ChimFile, platform: &Platform) -> Option { 252 | match &platform.aws_profile { 253 | Some(aws_profile) => Some(aws_profile.clone()), 254 | None => chim_file.aws_profile.clone(), 255 | } 256 | } 257 | 258 | fn get_aws_access_key_id(chim_file: &ChimFile, platform: &Platform) -> Option { 259 | match &platform.aws_access_key_id { 260 | Some(aws_access_key_id) => Some(aws_access_key_id.clone()), 261 | None => chim_file.aws_access_key_id.clone(), 262 | } 263 | } 264 | 265 | fn get_aws_secret_access_key(chim_file: &ChimFile, platform: &Platform) -> Option { 266 | match &platform.aws_secret_access_key { 267 | Some(aws_secret_access_key) => Some(aws_secret_access_key.clone()), 268 | None => chim_file.aws_secret_access_key.clone(), 269 | } 270 | } 271 | 272 | fn get_aws_access_token(chim_file: &ChimFile, platform: &Platform) -> Option { 273 | match &platform.aws_access_token { 274 | Some(aws_access_token) => Some(aws_access_token.to_string()), 275 | None => chim_file.aws_access_token.clone(), 276 | } 277 | } 278 | 279 | fn get_aws_region(chim_file: &ChimFile, platform: &Platform) -> Option { 280 | match &platform.aws_region { 281 | Some(aws_region) => Some(aws_region.clone()), 282 | None => chim_file.aws_region.clone(), 283 | } 284 | } 285 | 286 | fn get_paranoid() -> bool { 287 | env::var_is_true("CHIM_PARANOID") 288 | } 289 | 290 | fn get_cache_root() -> Result { 291 | match std::env::var("CHIM_CACHE_DIR") { 292 | Ok(v) => Ok(PathBuf::from(&v)), 293 | Err(_) => { 294 | let base = dirs::cache_dir().ok_or_else(|| eyre!("cache dir not found"))?; 295 | Ok(base.join("chim")) 296 | } 297 | } 298 | } 299 | 300 | fn show_no_url_or_path_error(fetcher: &Fetcher, os: &str, arch: &str) -> Report { 301 | let url_or_path = match fetcher { 302 | Fetcher::Local => "url or path", 303 | _ => "path", 304 | }; 305 | 306 | eyre!("no {url_or_path} found for {os}-{arch} platform") 307 | .suggestion(format!("add a {url_or_path} field to chim")) 308 | } 309 | 310 | fn get_filename_from_url(url: &str) -> Result { 311 | Ok(Url::parse(url)? 312 | .path_segments() 313 | .and_then(|segments| segments.last()) 314 | .and_then(|name| if name.is_empty() { None } else { Some(name) }) 315 | .unwrap_or("download.file") 316 | .to_string()) 317 | } 318 | 319 | fn get_quiet(chim_file: &ChimFile) -> bool { 320 | env::var_is_true("CHIM_QUIET") || (chim_file.quiet && !env::var_is_false("CHIM_QUIET")) 321 | } 322 | 323 | #[cfg(test)] 324 | mod tests { 325 | use super::*; 326 | use pretty_assertions::assert_eq; 327 | 328 | #[test] 329 | fn test_node_config() { 330 | let chim_path = Path::new("example/node"); 331 | let c = Config::from_chim_file(chim_path, "macos", "aarch64").unwrap(); 332 | 333 | assert_eq!( 334 | c.url, 335 | "https://nodejs.org/dist/v18.7.0/node-v18.7.0-darwin-arm64.tar.gz" 336 | ); 337 | } 338 | } 339 | -------------------------------------------------------------------------------- /src/env.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | pub fn var_is_true(key: &str) -> bool { 4 | match env::var(key) { 5 | Ok(v) => v == "true" || v == "1", 6 | Err(_) => false, 7 | } 8 | } 9 | 10 | pub fn var_is_false(key: &str) -> bool { 11 | match env::var(key) { 12 | Ok(v) => v == "false" || v == "0", 13 | Err(_) => false, 14 | } 15 | } 16 | 17 | #[cfg(test)] 18 | mod tests { 19 | use super::*; 20 | use pretty_assertions::assert_eq; 21 | use std::env; 22 | use test_case::test_case; 23 | 24 | #[test_case(Some("true"), true)] 25 | #[test_case(Some("1"), true)] 26 | #[test_case(Some("something"), false)] 27 | #[test_case(Some("0"), false)] 28 | #[test_case(Some("false"), false)] 29 | #[test_case(None, false)] 30 | fn test_var_is_true(value: Option<&str>, expected: bool) { 31 | let key = get_key(); 32 | match value { 33 | Some(v) => env::set_var(&key, v), 34 | None => env::remove_var(&key), 35 | }; 36 | assert_eq!(var_is_true(&key), expected); 37 | env::remove_var(&key); 38 | } 39 | 40 | #[test_case(Some("true"), false)] 41 | #[test_case(Some("1"), false)] 42 | #[test_case(Some("something"), false)] 43 | #[test_case(Some("0"), true)] 44 | #[test_case(Some("false"), true)] 45 | #[test_case(None, false)] 46 | fn test_var_is_false(value: Option<&str>, expected: bool) { 47 | let key = get_key(); 48 | match value { 49 | Some(v) => env::set_var(&key, v), 50 | None => env::remove_var(&key), 51 | }; 52 | assert_eq!(var_is_false(&key), expected); 53 | env::remove_var(&key); 54 | } 55 | 56 | // #[quickcheck] 57 | fn get_key() -> String { 58 | format!("CHIM_TEST_KEY_{}", rand::random::()) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/fetchers/abs.rs: -------------------------------------------------------------------------------- 1 | use color_eyre::eyre::{eyre, Result}; 2 | use color_eyre::{Section, SectionExt}; 3 | use std::path::Path; 4 | use std::process::Command; 5 | 6 | pub fn fetch(url: &str, output: &Path) -> Result<()> { 7 | let mut cmd = Command::new("az"); 8 | cmd.args([ 9 | "storage", 10 | "blob", 11 | "download", 12 | "--blob-url", 13 | &rewrite_url_proto(url), 14 | "-f", 15 | output.to_str().unwrap(), 16 | ]); 17 | debug!("{:?}", cmd); 18 | 19 | let output = cmd.output()?; 20 | 21 | match output.status.success() { 22 | true => Ok(()), 23 | false => { 24 | let stdout = String::from_utf8_lossy(&output.stdout); 25 | let stderr = String::from_utf8_lossy(&output.stderr); 26 | 27 | Err(eyre!("az exited with status {}", output.status.to_string()) 28 | .with_section(move || stdout.trim().to_string().header("Stdout")) 29 | .with_section(move || stderr.trim().to_string().header("Stderr"))) 30 | } 31 | } 32 | } 33 | 34 | fn rewrite_url_proto(url: &str) -> String { 35 | url.replace("abs://", "https://") 36 | } 37 | -------------------------------------------------------------------------------- /src/fetchers/gcs.rs: -------------------------------------------------------------------------------- 1 | use color_eyre::eyre::{eyre, Result}; 2 | use color_eyre::{Section, SectionExt}; 3 | use std::path::Path; 4 | use std::process::Command; 5 | 6 | pub fn fetch(url: &str, output: &Path) -> Result<()> { 7 | let mut cmd = Command::new("gsutil"); 8 | cmd.args(["cp", url, output.to_str().unwrap()]); 9 | debug!("{:?}", cmd); 10 | 11 | let output = cmd.output()?; 12 | 13 | match output.status.success() { 14 | true => Ok(()), 15 | false => { 16 | let stdout = String::from_utf8_lossy(&output.stdout); 17 | let stderr = String::from_utf8_lossy(&output.stderr); 18 | 19 | Err( 20 | eyre!("gsutil exited with status {}", output.status.to_string()) 21 | .with_section(move || stdout.trim().to_string().header("Stdout")) 22 | .with_section(move || stderr.trim().to_string().header("Stderr")), 23 | ) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/fetchers/http.rs: -------------------------------------------------------------------------------- 1 | use crate::config::Config; 2 | use color_eyre::Result; 3 | use indicatif::{ProgressBar, ProgressStyle}; 4 | use reqwest::Response; 5 | use std::fs::File; 6 | use std::io::Write; 7 | use std::path::Path; 8 | 9 | pub async fn fetch(config: &Config, url: &str, output: &Path) -> Result<()> { 10 | let mut response = reqwest::get(url).await?; 11 | response.error_for_status_ref()?; 12 | let mut file = File::create(output)?; 13 | let pb = get_content_length(&response) 14 | .map(|l| create_progress_bar(config, l)) 15 | .unwrap_or_else(ProgressBar::hidden); 16 | 17 | while let Some(chunk) = response.chunk().await? { 18 | pb.inc(chunk.len() as u64); 19 | file.write_all(&chunk)?; 20 | } 21 | 22 | Ok(()) 23 | } 24 | 25 | fn get_content_length(response: &Response) -> Option { 26 | response 27 | .headers() 28 | .get("content-length") 29 | .and_then(|v| v.to_str().ok()) 30 | .and_then(|v| v.parse::().ok()) 31 | } 32 | 33 | fn create_progress_bar(config: &Config, length: u64) -> ProgressBar { 34 | if config.quiet { 35 | return ProgressBar::hidden(); 36 | } 37 | let pb = ProgressBar::new(length); 38 | pb.set_style(ProgressStyle::with_template("{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta})") 39 | .unwrap() 40 | .progress_chars("=>-")); 41 | //.with_key("eta", |state: &ProgressState, w: &mut dyn Write| write!(w, "{:.1}s", state.eta().as_secs_f64()).unwrap()) 42 | 43 | pb 44 | } 45 | -------------------------------------------------------------------------------- /src/fetchers/mod.rs: -------------------------------------------------------------------------------- 1 | mod abs; 2 | mod gcs; 3 | mod http; 4 | mod s3; 5 | mod scp; 6 | 7 | use crate::config; 8 | use crate::config::Config; 9 | use color_eyre::Result; 10 | use std::path::Path; 11 | 12 | pub struct Fetcher<'a> { 13 | config: &'a Config, 14 | } 15 | 16 | pub fn new(config: &Config) -> Fetcher { 17 | Fetcher { config } 18 | } 19 | 20 | impl<'a> Fetcher<'a> { 21 | pub async fn fetch(&self, url: &str, tmpfile: &Path) -> Result<()> { 22 | match self.config.fetcher { 23 | config::Fetcher::Http => http::fetch(self.config, url, tmpfile).await, 24 | config::Fetcher::S3 => s3::fetch(self.config, url, tmpfile), 25 | config::Fetcher::Gcs => gcs::fetch(url, tmpfile), 26 | config::Fetcher::Abs => abs::fetch(url, tmpfile), 27 | config::Fetcher::Scp => scp::fetch(url, tmpfile), 28 | _ => panic!("unsupported fetcher"), 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/fetchers/s3.rs: -------------------------------------------------------------------------------- 1 | use crate::config::Config; 2 | use color_eyre::eyre::{eyre, Result}; 3 | use color_eyre::{Section, SectionExt}; 4 | use std::path::Path; 5 | use std::process::Command; 6 | 7 | pub fn fetch(config: &Config, url: &str, output: &Path) -> Result<()> { 8 | let mut cmd = Command::new("aws"); 9 | cmd.args(["s3", "cp", url, output.to_str().unwrap()]); 10 | add_aws_args(config, &mut cmd); 11 | 12 | let output = cmd.output()?; 13 | 14 | match output.status.success() { 15 | true => Ok(()), 16 | false => { 17 | let stdout = String::from_utf8_lossy(&output.stdout); 18 | let stderr = String::from_utf8_lossy(&output.stderr); 19 | 20 | Err( 21 | eyre!("aws exited with status {}", output.status.to_string()) 22 | .with_section(move || stdout.trim().to_string().header("Stdout")) 23 | .with_section(move || stderr.trim().to_string().header("Stderr")), 24 | ) 25 | } 26 | } 27 | } 28 | 29 | fn add_aws_args(config: &Config, cmd: &mut Command) { 30 | match &config.aws_profile { 31 | Some(aws_profile) => { 32 | cmd.env("AWS_PROFILE", aws_profile); 33 | } 34 | None => {} 35 | } 36 | match &config.aws_access_key_id { 37 | Some(aws_access_key_id) => { 38 | cmd.env("AWS_ACCESS_KEY_ID", aws_access_key_id); 39 | } 40 | None => {} 41 | } 42 | match &config.aws_secret_access_key { 43 | Some(aws_secret_access_key) => { 44 | cmd.env("AWS_SECRET_ACCESS_KEY", aws_secret_access_key); 45 | } 46 | None => {} 47 | } 48 | match &config.aws_access_token { 49 | Some(aws_access_token) => { 50 | cmd.env("AWS_ACCESS_TOKEN", aws_access_token); 51 | } 52 | None => {} 53 | } 54 | match &config.aws_region { 55 | Some(aws_region) => { 56 | cmd.env("AWS_DEFAULT_REGION", aws_region); 57 | } 58 | None => {} 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/fetchers/scp.rs: -------------------------------------------------------------------------------- 1 | use color_eyre::eyre::{eyre, Result}; 2 | use color_eyre::{Section, SectionExt}; 3 | use std::path::Path; 4 | use std::process::Command; 5 | 6 | pub fn fetch(url: &str, output: &Path) -> Result<()> { 7 | let mut cmd = Command::new("scp"); 8 | cmd.args([url, output.to_str().unwrap()]); 9 | debug!("{:?}", cmd); 10 | 11 | let output = cmd.output()?; 12 | 13 | match output.status.success() { 14 | true => Ok(()), 15 | false => { 16 | let stdout = String::from_utf8_lossy(&output.stdout); 17 | let stderr = String::from_utf8_lossy(&output.stderr); 18 | 19 | Err( 20 | eyre!("ssh exited with status {}", output.status.to_string()) 21 | .with_section(move || stdout.trim().to_string().header("Stdout")) 22 | .with_section(move || stderr.trim().to_string().header("Stderr")), 23 | ) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/hooks.rs: -------------------------------------------------------------------------------- 1 | use crate::config::Config; 2 | use color_eyre::eyre::{eyre, Context}; 3 | use color_eyre::Result; 4 | use std::process::{Command, Stdio}; 5 | 6 | pub struct Hooks<'a> { 7 | config: &'a Config, 8 | } 9 | 10 | impl<'a> Hooks<'a> { 11 | pub fn new(config: &Config) -> Hooks { 12 | Hooks { config } 13 | } 14 | 15 | pub fn pre_fetch(&self) -> Result { 16 | self.exec_hook("pre_fetch", &self.config.pre_fetch) 17 | } 18 | pub fn pre_extract(&self) -> Result { 19 | self.exec_hook("pre_extract", &self.config.pre_extract) 20 | } 21 | 22 | pub fn pre_execute(&self) -> Result { 23 | // TODO: check config.pre_execute_interval 24 | self.exec_hook("pre_execute", &self.config.pre_execute) 25 | } 26 | 27 | pub fn post_execute(&self) -> Result { 28 | self.exec_hook("post_execute", &self.config.post_execute) 29 | } 30 | 31 | fn exec_hook(&self, hook: &str, script: &Option) -> Result { 32 | match &script { 33 | Some(script) => { 34 | debug!("running {hook} hook: {}", script); 35 | let output = Command::new("sh") 36 | .args(["-c", script]) 37 | .env("CHIM_URL", &self.config.url) 38 | .env("CHIM_BIN_PATH", &self.config.bin_path) 39 | .stdin(Stdio::inherit()) 40 | .stderr(Stdio::inherit()) 41 | .output() 42 | .wrap_err_with(|| format!("error executing {hook}: {}", script))?; 43 | 44 | let status = output.status; 45 | match status.success() { 46 | true => Ok(String::from_utf8_lossy(&output.stdout).to_string()), 47 | false => Err(eyre!("{hook} failed with {status}")), 48 | } 49 | } 50 | None => { 51 | trace!("no {hook} hook specified"); 52 | Ok(String::new()) 53 | } 54 | } 55 | } 56 | } 57 | 58 | #[cfg(test)] 59 | mod tests { 60 | use super::*; 61 | use pretty_assertions::assert_eq; 62 | use std::env::consts::{ARCH, OS}; 63 | use std::path::Path; 64 | 65 | #[test] 66 | fn test_hooks() { 67 | let config = Config::from_chim_file(Path::new("test/fixtures/hooks"), OS, ARCH).unwrap(); 68 | 69 | let hooks = Hooks::new(&config); 70 | assert_eq!(hooks.pre_fetch().unwrap(), "_pre_fetch_\n"); 71 | assert_eq!(hooks.pre_extract().unwrap(), "_pre_extract_\n"); 72 | assert_eq!(hooks.pre_execute().unwrap(), "_pre_execute_\n"); 73 | assert_eq!( 74 | hooks.post_execute().err().unwrap().to_string(), 75 | "post_execute failed with exit status: 1" 76 | ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/logger.rs: -------------------------------------------------------------------------------- 1 | use crate::env; 2 | use env_logger::{Builder, Env}; 3 | use std::io::Write; 4 | 5 | pub fn init() { 6 | if env::var_is_true("CHIM_DEBUG") { 7 | std::env::set_var("CHIM_LOG_LEVEL", "debug"); 8 | } else if env::var_is_true("CHIM_QUIET") { 9 | std::env::set_var("CHIM_LOG_LEVEL", "error"); 10 | } 11 | let env = Env::default().filter("CHIM_LOG_LEVEL"); 12 | 13 | #[cfg(not(tarpaulin_include))] 14 | Builder::from_env(env) 15 | .format(|buf, record| { 16 | let style = buf.default_level_style(record.level()); 17 | writeln!( 18 | buf, 19 | "chim[{:5} {}] {}", 20 | style.value(record.level()), 21 | record.module_path().unwrap_or(""), 22 | record.args() 23 | ) 24 | }) 25 | .init(); 26 | } 27 | 28 | #[cfg(test)] 29 | mod tests { 30 | use super::*; 31 | 32 | #[test] 33 | fn test_init() { 34 | init(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use color_eyre::eyre::Result; 2 | use color_eyre::Section; 3 | 4 | mod app; 5 | mod archive; 6 | mod bin; 7 | mod checksum; 8 | mod chim_file; 9 | mod cli; 10 | mod config; 11 | mod env; 12 | mod fetchers; 13 | mod hooks; 14 | mod logger; 15 | mod platform; 16 | 17 | #[macro_use] 18 | extern crate log; 19 | 20 | #[tokio::main] 21 | #[cfg(not(tarpaulin_include))] 22 | pub async fn main() -> Result<()> { 23 | logger::init(); 24 | color_eyre::install()?; 25 | 26 | let args: Vec = std::env::args().collect(); 27 | cli::parse(args).await.section("See https://chim.sh") 28 | } 29 | -------------------------------------------------------------------------------- /src/platform.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Cow; 2 | 3 | pub fn split_platform_name(name: &str) -> (Cow<'static, str>, Cow<'static, str>) { 4 | let mut parts = name.split('-'); 5 | return ( 6 | normalize_os(parts.next().unwrap()), 7 | normalize_arch(parts.next().unwrap()), 8 | ); 9 | } 10 | 11 | fn normalize_os(os: &str) -> Cow<'static, str> { 12 | match os { 13 | "darwin" => "macos".into(), 14 | "win" => "windows".into(), 15 | _ => os.to_owned().into(), 16 | } 17 | } 18 | 19 | fn normalize_arch(arch: &str) -> Cow<'static, str> { 20 | match arch { 21 | "arm64" => "aarch64".into(), 22 | "x64" => "x86_64".into(), 23 | _ => arch.to_owned().into(), 24 | } 25 | } 26 | 27 | #[cfg(test)] 28 | mod tests { 29 | use super::*; 30 | use pretty_assertions::assert_eq; 31 | use test_case::test_case; 32 | 33 | #[test_case("darwin-x64", "macos-x86_64")] 34 | #[test_case("macos-x64", "macos-x86_64")] 35 | #[test_case("macos-arm64", "macos-aarch64")] 36 | #[test_case("linux-aarch64", "linux-aarch64")] 37 | fn test_split_platform_name(input: &str, expected: &str) { 38 | let (os, arch) = split_platform_name(input); 39 | assert_eq!(format!("{os}-{arch}"), expected); 40 | } 41 | 42 | #[test] 43 | fn test_normalize_os() { 44 | assert_eq!(normalize_os("darwin"), "macos"); 45 | assert_eq!(normalize_os("win"), "windows"); 46 | assert_eq!(normalize_os("linux"), "linux"); 47 | } 48 | 49 | #[test] 50 | fn test_normalize_arch() { 51 | assert_eq!(normalize_arch("arm64"), "aarch64"); 52 | assert_eq!(normalize_arch("x64"), "x86_64"); 53 | assert_eq!(normalize_arch("x86"), "x86"); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /test/fixtures/hooks: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env chim 2 | 3 | pre_fetch = 'echo _pre_fetch_' 4 | pre_extract = 'echo _pre_extract_' 5 | pre_execute = 'echo _pre_execute_' 6 | post_execute = 'exit 1' 7 | path = '.' 8 | --------------------------------------------------------------------------------