├── .github ├── dependabot.yml └── workflows │ ├── quick-check.yml │ └── release.yml ├── .gitignore ├── .rustfmt.toml ├── Cargo.lock ├── Cargo.toml ├── Formula └── diener.rb ├── README.md ├── src ├── main.rs ├── patch.rs ├── update.rs └── workspacify.rs └── templates └── formula.rb /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: '/' 5 | schedule: 6 | interval: daily 7 | -------------------------------------------------------------------------------- /.github/workflows/quick-check.yml: -------------------------------------------------------------------------------- 1 | name: Quick check 2 | 3 | on: 4 | push: 5 | branches: 6 | - "*" 7 | pull_request: 8 | types: [opened, synchronize, reopened, edited, ready_for_review] 9 | 10 | jobs: 11 | quick_check: 12 | strategy: 13 | matrix: 14 | os: ["ubuntu-latest"] 15 | runs-on: ${{ matrix.os }} 16 | steps: 17 | - name: Install Rust stable toolchain 18 | uses: actions-rs/toolchain@v1 19 | with: 20 | profile: minimal 21 | toolchain: stable 22 | override: true 23 | components: clippy, rustfmt 24 | 25 | - name: Cache Dependencies & Build Outputs 26 | uses: actions/cache@v3 27 | with: 28 | path: | 29 | ~/.cargo/registry 30 | ~/.cargo/git 31 | target 32 | key: ${{ runner.os }}-${{ matrix.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} 33 | 34 | - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 35 | 36 | - name: Cargo fmt 37 | uses: actions-rs/cargo@v1 38 | with: 39 | command: fmt 40 | args: --all -- --check 41 | 42 | - name: Cargo check 43 | uses: actions-rs/cargo@v1 44 | with: 45 | command: check 46 | 47 | - name: Cargo clippy 48 | uses: actions-rs/cargo@v1 49 | with: 50 | command: clippy 51 | args: -- -D warnings 52 | 53 | - name: Cargo test 54 | uses: actions-rs/cargo@v1 55 | with: 56 | command: test 57 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # This workflow runs on every push 2 | 3 | name: Release 4 | 5 | on: 6 | push: 7 | tags: 8 | - "v*" 9 | 10 | jobs: 11 | linux: 12 | env: 13 | TARGET_DIR: target/release 14 | 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 18 | 19 | - name: Install latest nightly 20 | uses: actions-rs/toolchain@b2417cde72dcf67f306c0ae8e0828a81bf0b189f 21 | with: 22 | toolchain: nightly 23 | override: true 24 | components: rustfmt, clippy 25 | 26 | - name: Install cargo deb 27 | uses: actions-rs/cargo@ae10961054e4aa8b4aa7dffede299aaf087aa33b 28 | with: 29 | command: install 30 | args: cargo-deb 31 | 32 | - name: Build debian package 33 | shell: bash 34 | run: | 35 | cargo deb -p diener -o "diener_linux_amd64.deb" 36 | 37 | - name: Upload artifacts 38 | uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce 39 | with: 40 | name: linux 41 | path: | 42 | diener_linux_amd64.deb 43 | 44 | macos: 45 | env: 46 | TARGET_DIR: target/release 47 | 48 | runs-on: macos-10.15 49 | steps: 50 | - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 51 | with: 52 | fetch-depth: 0 53 | 54 | - name: Get Release Version 55 | run: | 56 | echo GITHUB_REF=$GITHUB_REF 57 | RELEASE_VERSION=${GITHUB_REF#refs/*/} 58 | RAW_VERSION=${RELEASE_VERSION:1} 59 | echo "RELEASE_VERSION=$RELEASE_VERSION" >> $GITHUB_ENV 60 | echo "RAW_VERSION=$RAW_VERSION" >> $GITHUB_ENV 61 | echo "SHORT_SHA=${GITHUB_SHA::8}" >> $GITHUB_ENV 62 | 63 | - name: Install rust toolchain 64 | uses: actions-rs/toolchain@b2417cde72dcf67f306c0ae8e0828a81bf0b189f 65 | with: 66 | toolchain: stable 67 | override: true 68 | 69 | - name: Check tooling 70 | shell: bash 71 | run: | 72 | tar --version 73 | shasum --version 74 | cargo --version 75 | rustc --version 76 | 77 | - name: Build MacOS binary 78 | run: | 79 | cargo build --locked --profile release 80 | ls -al "${{ env.TARGET_DIR }}/diener" 81 | 82 | - name: Check binary 83 | env: 84 | BINARY: "${{ env.TARGET_DIR }}/diener" 85 | run: | 86 | file $BINARY 87 | $BINARY --version 88 | $BINARY --help 89 | 90 | - name: Compress & sha256 91 | run: | 92 | tar -czf ${{ env.TARGET_DIR }}/diener_macos.tar.gz -C ${{ env.TARGET_DIR }} diener 93 | SHA256=$(shasum -a 256 ${{ env.TARGET_DIR }}/diener_macos.tar.gz | awk '{ print $1}' | tee ${{ env.TARGET_DIR }}/diener_macos.tar.gz.sha256) 94 | echo SHA256: $SHA256 95 | echo "SHA256=$SHA256" >> $GITHUB_ENV 96 | 97 | - name: Upload MacOS artifacts 98 | uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce 99 | with: 100 | name: macos 101 | path: | 102 | ${{ env.TARGET_DIR }}/diener_macos.tar.gz 103 | ${{ env.TARGET_DIR }}/diener_macos.tar.gz.sha256 104 | 105 | - name: Install tera MacOS binary v0.1.3 106 | run: | 107 | URL=https://github.com/chevdor/tera-cli/releases/download/v0.1.3/tera-macos-v0.1.3.tar.gz 108 | wget $URL 109 | tar xvf tera-macos-v0.1.3.tar.gz -C /usr/local/bin 110 | tera --version 111 | 112 | # We do that before checking out master (in case we were not in master already) 113 | - name: Prepare new Formula 114 | env: 115 | NAME: Diener 116 | DESCRIPTION: "dependency diener is a tool for easily changing Polkadot SDK dependency versions" 117 | SITE: https://github.com 118 | REPO: paritytech/diener 119 | SHA256: ${{env.SHA256}} 120 | VERSION: ${{env.RAW_VERSION}} 121 | run: | 122 | tera --version 123 | tera --template templates/formula.rb --env-only > $HOME/diener.rb 124 | cat $HOME/diener.rb 125 | 126 | - name: Update Homebrew Formula 127 | run: | 128 | cp -f $HOME/diener.rb Formula/diener.rb 129 | git config --global user.name 'CI' 130 | git config --global user.email 'foo@example.invalid' 131 | git commit Formula/diener.rb -m "build: new homebrew formula for ${{ env.RELEASE_VERSION }}" 132 | git push origin HEAD:master 133 | 134 | create_draft: 135 | needs: ["linux", "macos"] 136 | name: Create Draft 137 | runs-on: ubuntu-latest 138 | outputs: 139 | release_url: ${{ steps.create-release.outputs.html_url }} 140 | asset_upload_url: ${{ steps.create-release.outputs.upload_url }} 141 | steps: 142 | - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 143 | with: 144 | fetch-depth: 0 145 | - name: Get Release Version 146 | run: | 147 | echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV 148 | echo "SHORT_SHA=${GITHUB_SHA::8}" >> $GITHUB_ENV 149 | 150 | - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a 151 | 152 | - name: Create Release 153 | id: create-release 154 | uses: actions/create-release@0cb9c9b65d5d1901c1f53e5e66eaf4afd303e70e 155 | env: 156 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 157 | with: 158 | tag_name: ${{ env.RELEASE_VERSION }} 159 | release_name: Diener ${{ env.RELEASE_VERSION }} (${{ env.SHORT_SHA }}) 160 | draft: true 161 | 162 | publish-binaries: 163 | runs-on: ubuntu-latest 164 | needs: ["create_draft"] 165 | steps: 166 | - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 167 | - name: Get Release Version 168 | run: | 169 | echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV 170 | echo "SHORT_SHA=${GITHUB_SHA::8}" >> $GITHUB_ENV 171 | 172 | - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a 173 | 174 | - name: Upload Debian package 175 | uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 176 | env: 177 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 178 | with: 179 | upload_url: ${{ needs.create_draft.outputs.asset_upload_url }} 180 | asset_path: "linux/diener_linux_amd64.deb" 181 | asset_name: "diener_linux_amd64_${{ env.RELEASE_VERSION }}.deb" 182 | asset_content_type: application/vnd.debian.binary-package 183 | 184 | - name: Upload MacOS archive 185 | uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 186 | env: 187 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 188 | with: 189 | upload_url: ${{ needs.create_draft.outputs.asset_upload_url }} 190 | asset_path: "macos/diener_macos.tar.gz" 191 | asset_name: "diener_macos_${{ env.RELEASE_VERSION }}.tar.gz" 192 | asset_content_type: application/gzip 193 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # These are backup files generated by rustfmt 6 | **/*.rs.bk 7 | 8 | # Used by cargo-cleanup 9 | executables 10 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paritytech/diener/dbd4977d6fdfdb47524e36573ede7b46d8992093/.rustfmt.toml -------------------------------------------------------------------------------- /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.21.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" 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 = "1.0.3" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "86b8f9420f797f2d9e935edf629310eb938a0d839f984e25327f3c7eed22300c" 25 | dependencies = [ 26 | "memchr", 27 | ] 28 | 29 | [[package]] 30 | name = "ansi_term" 31 | version = "0.12.1" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" 34 | dependencies = [ 35 | "winapi", 36 | ] 37 | 38 | [[package]] 39 | name = "anyhow" 40 | version = "1.0.72" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" 43 | 44 | [[package]] 45 | name = "atty" 46 | version = "0.2.14" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 49 | dependencies = [ 50 | "hermit-abi 0.1.19", 51 | "libc", 52 | "winapi", 53 | ] 54 | 55 | [[package]] 56 | name = "backtrace" 57 | version = "0.3.69" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" 60 | dependencies = [ 61 | "addr2line", 62 | "cc", 63 | "cfg-if", 64 | "libc", 65 | "miniz_oxide", 66 | "object", 67 | "rustc-demangle", 68 | ] 69 | 70 | [[package]] 71 | name = "bitflags" 72 | version = "1.3.2" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 75 | 76 | [[package]] 77 | name = "bitflags" 78 | version = "2.3.3" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" 81 | 82 | [[package]] 83 | name = "camino" 84 | version = "1.1.6" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" 87 | dependencies = [ 88 | "serde", 89 | ] 90 | 91 | [[package]] 92 | name = "cargo-platform" 93 | version = "0.1.3" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479" 96 | dependencies = [ 97 | "serde", 98 | ] 99 | 100 | [[package]] 101 | name = "cargo_metadata" 102 | version = "0.17.0" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | checksum = "e7daec1a2a2129eeba1644b220b4647ec537b0b5d4bfd6876fcc5a540056b592" 105 | dependencies = [ 106 | "camino", 107 | "cargo-platform", 108 | "semver", 109 | "serde", 110 | "serde_json", 111 | "thiserror", 112 | ] 113 | 114 | [[package]] 115 | name = "cc" 116 | version = "1.0.82" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" 119 | dependencies = [ 120 | "libc", 121 | ] 122 | 123 | [[package]] 124 | name = "cfg-if" 125 | version = "1.0.0" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 128 | 129 | [[package]] 130 | name = "clap" 131 | version = "2.34.0" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" 134 | dependencies = [ 135 | "ansi_term", 136 | "atty", 137 | "bitflags 1.3.2", 138 | "strsim", 139 | "textwrap", 140 | "unicode-width", 141 | "vec_map", 142 | ] 143 | 144 | [[package]] 145 | name = "color-eyre" 146 | version = "0.6.2" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204" 149 | dependencies = [ 150 | "backtrace", 151 | "color-spantrace", 152 | "eyre", 153 | "indenter", 154 | "once_cell", 155 | "owo-colors", 156 | "tracing-error", 157 | ] 158 | 159 | [[package]] 160 | name = "color-spantrace" 161 | version = "0.2.1" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" 164 | dependencies = [ 165 | "once_cell", 166 | "owo-colors", 167 | "tracing-core", 168 | "tracing-error", 169 | ] 170 | 171 | [[package]] 172 | name = "diener" 173 | version = "0.5.0" 174 | dependencies = [ 175 | "anyhow", 176 | "cargo_metadata", 177 | "env_logger", 178 | "git-url-parse", 179 | "log", 180 | "pathdiff", 181 | "structopt", 182 | "toml_edit", 183 | "walkdir", 184 | ] 185 | 186 | [[package]] 187 | name = "env_logger" 188 | version = "0.10.0" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" 191 | dependencies = [ 192 | "humantime", 193 | "is-terminal", 194 | "log", 195 | "regex", 196 | "termcolor", 197 | ] 198 | 199 | [[package]] 200 | name = "equivalent" 201 | version = "1.0.1" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 204 | 205 | [[package]] 206 | name = "errno" 207 | version = "0.3.2" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" 210 | dependencies = [ 211 | "errno-dragonfly", 212 | "libc", 213 | "windows-sys", 214 | ] 215 | 216 | [[package]] 217 | name = "errno-dragonfly" 218 | version = "0.1.2" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" 221 | dependencies = [ 222 | "cc", 223 | "libc", 224 | ] 225 | 226 | [[package]] 227 | name = "eyre" 228 | version = "0.6.12" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" 231 | dependencies = [ 232 | "indenter", 233 | "once_cell", 234 | ] 235 | 236 | [[package]] 237 | name = "form_urlencoded" 238 | version = "1.2.1" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 241 | dependencies = [ 242 | "percent-encoding", 243 | ] 244 | 245 | [[package]] 246 | name = "gimli" 247 | version = "0.28.1" 248 | source = "registry+https://github.com/rust-lang/crates.io-index" 249 | checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" 250 | 251 | [[package]] 252 | name = "git-url-parse" 253 | version = "0.4.4" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "b037f7449dd4a8b711e660301ff1ff28aa00eea09698421fb2d78db51a7b7a72" 256 | dependencies = [ 257 | "color-eyre", 258 | "regex", 259 | "strum", 260 | "strum_macros", 261 | "tracing", 262 | "url", 263 | ] 264 | 265 | [[package]] 266 | name = "hashbrown" 267 | version = "0.14.0" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" 270 | 271 | [[package]] 272 | name = "heck" 273 | version = "0.3.3" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" 276 | dependencies = [ 277 | "unicode-segmentation", 278 | ] 279 | 280 | [[package]] 281 | name = "heck" 282 | version = "0.4.1" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 285 | 286 | [[package]] 287 | name = "hermit-abi" 288 | version = "0.1.19" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 291 | dependencies = [ 292 | "libc", 293 | ] 294 | 295 | [[package]] 296 | name = "hermit-abi" 297 | version = "0.3.2" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" 300 | 301 | [[package]] 302 | name = "humantime" 303 | version = "2.1.0" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 306 | 307 | [[package]] 308 | name = "idna" 309 | version = "0.5.0" 310 | source = "registry+https://github.com/rust-lang/crates.io-index" 311 | checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" 312 | dependencies = [ 313 | "unicode-bidi", 314 | "unicode-normalization", 315 | ] 316 | 317 | [[package]] 318 | name = "indenter" 319 | version = "0.3.3" 320 | source = "registry+https://github.com/rust-lang/crates.io-index" 321 | checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" 322 | 323 | [[package]] 324 | name = "indexmap" 325 | version = "2.0.0" 326 | source = "registry+https://github.com/rust-lang/crates.io-index" 327 | checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" 328 | dependencies = [ 329 | "equivalent", 330 | "hashbrown", 331 | ] 332 | 333 | [[package]] 334 | name = "is-terminal" 335 | version = "0.4.9" 336 | source = "registry+https://github.com/rust-lang/crates.io-index" 337 | checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" 338 | dependencies = [ 339 | "hermit-abi 0.3.2", 340 | "rustix", 341 | "windows-sys", 342 | ] 343 | 344 | [[package]] 345 | name = "itoa" 346 | version = "1.0.9" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" 349 | 350 | [[package]] 351 | name = "lazy_static" 352 | version = "1.4.0" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 355 | 356 | [[package]] 357 | name = "libc" 358 | version = "0.2.147" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" 361 | 362 | [[package]] 363 | name = "linux-raw-sys" 364 | version = "0.4.5" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" 367 | 368 | [[package]] 369 | name = "log" 370 | version = "0.4.19" 371 | source = "registry+https://github.com/rust-lang/crates.io-index" 372 | checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" 373 | 374 | [[package]] 375 | name = "memchr" 376 | version = "2.5.0" 377 | source = "registry+https://github.com/rust-lang/crates.io-index" 378 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 379 | 380 | [[package]] 381 | name = "miniz_oxide" 382 | version = "0.7.2" 383 | source = "registry+https://github.com/rust-lang/crates.io-index" 384 | checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" 385 | dependencies = [ 386 | "adler", 387 | ] 388 | 389 | [[package]] 390 | name = "object" 391 | version = "0.32.2" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" 394 | dependencies = [ 395 | "memchr", 396 | ] 397 | 398 | [[package]] 399 | name = "once_cell" 400 | version = "1.19.0" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 403 | 404 | [[package]] 405 | name = "owo-colors" 406 | version = "3.5.0" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" 409 | 410 | [[package]] 411 | name = "pathdiff" 412 | version = "0.2.1" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" 415 | 416 | [[package]] 417 | name = "percent-encoding" 418 | version = "2.3.1" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 421 | 422 | [[package]] 423 | name = "pin-project-lite" 424 | version = "0.2.13" 425 | source = "registry+https://github.com/rust-lang/crates.io-index" 426 | checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" 427 | 428 | [[package]] 429 | name = "proc-macro-error" 430 | version = "1.0.4" 431 | source = "registry+https://github.com/rust-lang/crates.io-index" 432 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 433 | dependencies = [ 434 | "proc-macro-error-attr", 435 | "proc-macro2", 436 | "quote", 437 | "syn 1.0.109", 438 | "version_check", 439 | ] 440 | 441 | [[package]] 442 | name = "proc-macro-error-attr" 443 | version = "1.0.4" 444 | source = "registry+https://github.com/rust-lang/crates.io-index" 445 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 446 | dependencies = [ 447 | "proc-macro2", 448 | "quote", 449 | "version_check", 450 | ] 451 | 452 | [[package]] 453 | name = "proc-macro2" 454 | version = "1.0.66" 455 | source = "registry+https://github.com/rust-lang/crates.io-index" 456 | checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" 457 | dependencies = [ 458 | "unicode-ident", 459 | ] 460 | 461 | [[package]] 462 | name = "quote" 463 | version = "1.0.32" 464 | source = "registry+https://github.com/rust-lang/crates.io-index" 465 | checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" 466 | dependencies = [ 467 | "proc-macro2", 468 | ] 469 | 470 | [[package]] 471 | name = "regex" 472 | version = "1.9.3" 473 | source = "registry+https://github.com/rust-lang/crates.io-index" 474 | checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" 475 | dependencies = [ 476 | "aho-corasick", 477 | "memchr", 478 | "regex-automata", 479 | "regex-syntax", 480 | ] 481 | 482 | [[package]] 483 | name = "regex-automata" 484 | version = "0.3.6" 485 | source = "registry+https://github.com/rust-lang/crates.io-index" 486 | checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" 487 | dependencies = [ 488 | "aho-corasick", 489 | "memchr", 490 | "regex-syntax", 491 | ] 492 | 493 | [[package]] 494 | name = "regex-syntax" 495 | version = "0.7.4" 496 | source = "registry+https://github.com/rust-lang/crates.io-index" 497 | checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" 498 | 499 | [[package]] 500 | name = "rustc-demangle" 501 | version = "0.1.23" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" 504 | 505 | [[package]] 506 | name = "rustix" 507 | version = "0.38.7" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | checksum = "172891ebdceb05aa0005f533a6cbfca599ddd7d966f6f5d4d9b2e70478e70399" 510 | dependencies = [ 511 | "bitflags 2.3.3", 512 | "errno", 513 | "libc", 514 | "linux-raw-sys", 515 | "windows-sys", 516 | ] 517 | 518 | [[package]] 519 | name = "rustversion" 520 | version = "1.0.14" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" 523 | 524 | [[package]] 525 | name = "ryu" 526 | version = "1.0.15" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" 529 | 530 | [[package]] 531 | name = "same-file" 532 | version = "1.0.6" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 535 | dependencies = [ 536 | "winapi-util", 537 | ] 538 | 539 | [[package]] 540 | name = "semver" 541 | version = "1.0.18" 542 | source = "registry+https://github.com/rust-lang/crates.io-index" 543 | checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" 544 | dependencies = [ 545 | "serde", 546 | ] 547 | 548 | [[package]] 549 | name = "serde" 550 | version = "1.0.183" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c" 553 | dependencies = [ 554 | "serde_derive", 555 | ] 556 | 557 | [[package]] 558 | name = "serde_derive" 559 | version = "1.0.183" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" 562 | dependencies = [ 563 | "proc-macro2", 564 | "quote", 565 | "syn 2.0.28", 566 | ] 567 | 568 | [[package]] 569 | name = "serde_json" 570 | version = "1.0.104" 571 | source = "registry+https://github.com/rust-lang/crates.io-index" 572 | checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" 573 | dependencies = [ 574 | "itoa", 575 | "ryu", 576 | "serde", 577 | ] 578 | 579 | [[package]] 580 | name = "sharded-slab" 581 | version = "0.1.7" 582 | source = "registry+https://github.com/rust-lang/crates.io-index" 583 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 584 | dependencies = [ 585 | "lazy_static", 586 | ] 587 | 588 | [[package]] 589 | name = "strsim" 590 | version = "0.8.0" 591 | source = "registry+https://github.com/rust-lang/crates.io-index" 592 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 593 | 594 | [[package]] 595 | name = "structopt" 596 | version = "0.3.26" 597 | source = "registry+https://github.com/rust-lang/crates.io-index" 598 | checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" 599 | dependencies = [ 600 | "clap", 601 | "lazy_static", 602 | "structopt-derive", 603 | ] 604 | 605 | [[package]] 606 | name = "structopt-derive" 607 | version = "0.4.18" 608 | source = "registry+https://github.com/rust-lang/crates.io-index" 609 | checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" 610 | dependencies = [ 611 | "heck 0.3.3", 612 | "proc-macro-error", 613 | "proc-macro2", 614 | "quote", 615 | "syn 1.0.109", 616 | ] 617 | 618 | [[package]] 619 | name = "strum" 620 | version = "0.24.1" 621 | source = "registry+https://github.com/rust-lang/crates.io-index" 622 | checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" 623 | 624 | [[package]] 625 | name = "strum_macros" 626 | version = "0.24.3" 627 | source = "registry+https://github.com/rust-lang/crates.io-index" 628 | checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" 629 | dependencies = [ 630 | "heck 0.4.1", 631 | "proc-macro2", 632 | "quote", 633 | "rustversion", 634 | "syn 1.0.109", 635 | ] 636 | 637 | [[package]] 638 | name = "syn" 639 | version = "1.0.109" 640 | source = "registry+https://github.com/rust-lang/crates.io-index" 641 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 642 | dependencies = [ 643 | "proc-macro2", 644 | "quote", 645 | "unicode-ident", 646 | ] 647 | 648 | [[package]] 649 | name = "syn" 650 | version = "2.0.28" 651 | source = "registry+https://github.com/rust-lang/crates.io-index" 652 | checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" 653 | dependencies = [ 654 | "proc-macro2", 655 | "quote", 656 | "unicode-ident", 657 | ] 658 | 659 | [[package]] 660 | name = "termcolor" 661 | version = "1.2.0" 662 | source = "registry+https://github.com/rust-lang/crates.io-index" 663 | checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" 664 | dependencies = [ 665 | "winapi-util", 666 | ] 667 | 668 | [[package]] 669 | name = "textwrap" 670 | version = "0.11.0" 671 | source = "registry+https://github.com/rust-lang/crates.io-index" 672 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 673 | dependencies = [ 674 | "unicode-width", 675 | ] 676 | 677 | [[package]] 678 | name = "thiserror" 679 | version = "1.0.44" 680 | source = "registry+https://github.com/rust-lang/crates.io-index" 681 | checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" 682 | dependencies = [ 683 | "thiserror-impl", 684 | ] 685 | 686 | [[package]] 687 | name = "thiserror-impl" 688 | version = "1.0.44" 689 | source = "registry+https://github.com/rust-lang/crates.io-index" 690 | checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" 691 | dependencies = [ 692 | "proc-macro2", 693 | "quote", 694 | "syn 2.0.28", 695 | ] 696 | 697 | [[package]] 698 | name = "thread_local" 699 | version = "1.1.7" 700 | source = "registry+https://github.com/rust-lang/crates.io-index" 701 | checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" 702 | dependencies = [ 703 | "cfg-if", 704 | "once_cell", 705 | ] 706 | 707 | [[package]] 708 | name = "tinyvec" 709 | version = "1.6.0" 710 | source = "registry+https://github.com/rust-lang/crates.io-index" 711 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 712 | dependencies = [ 713 | "tinyvec_macros", 714 | ] 715 | 716 | [[package]] 717 | name = "tinyvec_macros" 718 | version = "0.1.1" 719 | source = "registry+https://github.com/rust-lang/crates.io-index" 720 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 721 | 722 | [[package]] 723 | name = "toml_datetime" 724 | version = "0.6.3" 725 | source = "registry+https://github.com/rust-lang/crates.io-index" 726 | checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" 727 | 728 | [[package]] 729 | name = "toml_edit" 730 | version = "0.19.14" 731 | source = "registry+https://github.com/rust-lang/crates.io-index" 732 | checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" 733 | dependencies = [ 734 | "indexmap", 735 | "toml_datetime", 736 | "winnow", 737 | ] 738 | 739 | [[package]] 740 | name = "tracing" 741 | version = "0.1.40" 742 | source = "registry+https://github.com/rust-lang/crates.io-index" 743 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 744 | dependencies = [ 745 | "pin-project-lite", 746 | "tracing-attributes", 747 | "tracing-core", 748 | ] 749 | 750 | [[package]] 751 | name = "tracing-attributes" 752 | version = "0.1.27" 753 | source = "registry+https://github.com/rust-lang/crates.io-index" 754 | checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" 755 | dependencies = [ 756 | "proc-macro2", 757 | "quote", 758 | "syn 2.0.28", 759 | ] 760 | 761 | [[package]] 762 | name = "tracing-core" 763 | version = "0.1.32" 764 | source = "registry+https://github.com/rust-lang/crates.io-index" 765 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 766 | dependencies = [ 767 | "once_cell", 768 | "valuable", 769 | ] 770 | 771 | [[package]] 772 | name = "tracing-error" 773 | version = "0.2.0" 774 | source = "registry+https://github.com/rust-lang/crates.io-index" 775 | checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" 776 | dependencies = [ 777 | "tracing", 778 | "tracing-subscriber", 779 | ] 780 | 781 | [[package]] 782 | name = "tracing-subscriber" 783 | version = "0.3.18" 784 | source = "registry+https://github.com/rust-lang/crates.io-index" 785 | checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" 786 | dependencies = [ 787 | "sharded-slab", 788 | "thread_local", 789 | "tracing-core", 790 | ] 791 | 792 | [[package]] 793 | name = "unicode-bidi" 794 | version = "0.3.15" 795 | source = "registry+https://github.com/rust-lang/crates.io-index" 796 | checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" 797 | 798 | [[package]] 799 | name = "unicode-ident" 800 | version = "1.0.11" 801 | source = "registry+https://github.com/rust-lang/crates.io-index" 802 | checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" 803 | 804 | [[package]] 805 | name = "unicode-normalization" 806 | version = "0.1.22" 807 | source = "registry+https://github.com/rust-lang/crates.io-index" 808 | checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" 809 | dependencies = [ 810 | "tinyvec", 811 | ] 812 | 813 | [[package]] 814 | name = "unicode-segmentation" 815 | version = "1.10.1" 816 | source = "registry+https://github.com/rust-lang/crates.io-index" 817 | checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" 818 | 819 | [[package]] 820 | name = "unicode-width" 821 | version = "0.1.10" 822 | source = "registry+https://github.com/rust-lang/crates.io-index" 823 | checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" 824 | 825 | [[package]] 826 | name = "url" 827 | version = "2.5.0" 828 | source = "registry+https://github.com/rust-lang/crates.io-index" 829 | checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" 830 | dependencies = [ 831 | "form_urlencoded", 832 | "idna", 833 | "percent-encoding", 834 | ] 835 | 836 | [[package]] 837 | name = "valuable" 838 | version = "0.1.0" 839 | source = "registry+https://github.com/rust-lang/crates.io-index" 840 | checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" 841 | 842 | [[package]] 843 | name = "vec_map" 844 | version = "0.8.2" 845 | source = "registry+https://github.com/rust-lang/crates.io-index" 846 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 847 | 848 | [[package]] 849 | name = "version_check" 850 | version = "0.9.4" 851 | source = "registry+https://github.com/rust-lang/crates.io-index" 852 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 853 | 854 | [[package]] 855 | name = "walkdir" 856 | version = "2.3.3" 857 | source = "registry+https://github.com/rust-lang/crates.io-index" 858 | checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" 859 | dependencies = [ 860 | "same-file", 861 | "winapi-util", 862 | ] 863 | 864 | [[package]] 865 | name = "winapi" 866 | version = "0.3.9" 867 | source = "registry+https://github.com/rust-lang/crates.io-index" 868 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 869 | dependencies = [ 870 | "winapi-i686-pc-windows-gnu", 871 | "winapi-x86_64-pc-windows-gnu", 872 | ] 873 | 874 | [[package]] 875 | name = "winapi-i686-pc-windows-gnu" 876 | version = "0.4.0" 877 | source = "registry+https://github.com/rust-lang/crates.io-index" 878 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 879 | 880 | [[package]] 881 | name = "winapi-util" 882 | version = "0.1.5" 883 | source = "registry+https://github.com/rust-lang/crates.io-index" 884 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 885 | dependencies = [ 886 | "winapi", 887 | ] 888 | 889 | [[package]] 890 | name = "winapi-x86_64-pc-windows-gnu" 891 | version = "0.4.0" 892 | source = "registry+https://github.com/rust-lang/crates.io-index" 893 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 894 | 895 | [[package]] 896 | name = "windows-sys" 897 | version = "0.48.0" 898 | source = "registry+https://github.com/rust-lang/crates.io-index" 899 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 900 | dependencies = [ 901 | "windows-targets", 902 | ] 903 | 904 | [[package]] 905 | name = "windows-targets" 906 | version = "0.48.1" 907 | source = "registry+https://github.com/rust-lang/crates.io-index" 908 | checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" 909 | dependencies = [ 910 | "windows_aarch64_gnullvm", 911 | "windows_aarch64_msvc", 912 | "windows_i686_gnu", 913 | "windows_i686_msvc", 914 | "windows_x86_64_gnu", 915 | "windows_x86_64_gnullvm", 916 | "windows_x86_64_msvc", 917 | ] 918 | 919 | [[package]] 920 | name = "windows_aarch64_gnullvm" 921 | version = "0.48.0" 922 | source = "registry+https://github.com/rust-lang/crates.io-index" 923 | checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" 924 | 925 | [[package]] 926 | name = "windows_aarch64_msvc" 927 | version = "0.48.0" 928 | source = "registry+https://github.com/rust-lang/crates.io-index" 929 | checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" 930 | 931 | [[package]] 932 | name = "windows_i686_gnu" 933 | version = "0.48.0" 934 | source = "registry+https://github.com/rust-lang/crates.io-index" 935 | checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" 936 | 937 | [[package]] 938 | name = "windows_i686_msvc" 939 | version = "0.48.0" 940 | source = "registry+https://github.com/rust-lang/crates.io-index" 941 | checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" 942 | 943 | [[package]] 944 | name = "windows_x86_64_gnu" 945 | version = "0.48.0" 946 | source = "registry+https://github.com/rust-lang/crates.io-index" 947 | checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" 948 | 949 | [[package]] 950 | name = "windows_x86_64_gnullvm" 951 | version = "0.48.0" 952 | source = "registry+https://github.com/rust-lang/crates.io-index" 953 | checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" 954 | 955 | [[package]] 956 | name = "windows_x86_64_msvc" 957 | version = "0.48.0" 958 | source = "registry+https://github.com/rust-lang/crates.io-index" 959 | checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" 960 | 961 | [[package]] 962 | name = "winnow" 963 | version = "0.5.4" 964 | source = "registry+https://github.com/rust-lang/crates.io-index" 965 | checksum = "acaaa1190073b2b101e15083c38ee8ec891b5e05cbee516521e94ec008f61e64" 966 | dependencies = [ 967 | "memchr", 968 | ] 969 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "diener" 3 | version = "0.5.0" 4 | authors = ["Bastian Köcher "] 5 | edition = "2021" 6 | categories = ["command-line-utilities"] 7 | documentation = "https://docs.rs/diener" 8 | repository = "https://github.com/bkchr/diener" 9 | keywords = ["cli", "substrate", "polkadot", "polkadot-sdk"] 10 | license = "Apache-2.0/MIT" 11 | description = """ 12 | dependency diener is a tool for easily changing [Polkadot SDK](https://github.com/paritytech/polkadot-sdk) dependency versions 13 | """ 14 | readme = "./README.md" 15 | 16 | [dependencies] 17 | structopt = "0.3" 18 | walkdir = "2.3" 19 | git-url-parse = "0.4" 20 | toml_edit = "0.19" 21 | cargo_metadata = "0.17" 22 | env_logger = "0.10" 23 | log = "0.4" 24 | pathdiff = "0.2" 25 | anyhow = "1.0" 26 | -------------------------------------------------------------------------------- /Formula/diener.rb: -------------------------------------------------------------------------------- 1 | class Diener < Formula 2 | desc "dependency diener is a tool for easily changing Polkadot SDK dependency versions" 3 | homepage "https://github.com/paritytech/diener" 4 | url "https://github.com/paritytech/diener/releases/download/v0.4.4/diener_macos_v0.4.4.tar.gz" 5 | sha256 "1caba305bcc460a528fbcf2f0a7dd519fb31ad21fffa9902d9497019809ff90b" 6 | version "0.4.4" 7 | 8 | def install 9 | bin.install "diener" 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # diener - dependency diener is a tool for easily changing [Polkadot SDK](https://github.com/paritytech/polkadot-sdk) dependency versions 2 | 3 | [![](https://docs.rs/diener/badge.svg)](https://docs.rs/diener/) [![](https://img.shields.io/crates/v/diener.svg)](https://crates.io/crates/diener) [![](https://img.shields.io/crates/d/diener.png)](https://crates.io/crates/diener) 4 | 5 | * [Usage](#usage) 6 | * [License](#license) 7 | 8 | ### Usage 9 | 10 | You can find the full documentation on [docs.rs](https://docs.rs/crate/diener). 11 | 12 | #### Update 13 | 14 | The `update` subcommand changes all `Cargo.toml` files in a given folder to use 15 | a specific branch/path/commit/tag. 16 | 17 | Change all Polkadot SDK dependencies in a folder to a different branch: 18 | 19 | ```rust 20 | diener update --branch diener-branch 21 | ``` 22 | 23 | Diener also supports `tag` and `rev` as arguments. 24 | 25 | #### Patch 26 | 27 | The `patch` subcommand adds a patch section for each crate in a given cargo workspace 28 | to the workspace `Cargo.toml` file in some other cargo workspace. 29 | 30 | Patch all git dependencies to be build from a given path: 31 | 32 | ```rust 33 | diener patch --crates-to-patch ../path/to/polkadot-sdk/checkout 34 | ``` 35 | 36 | This subcommand can be compared to `.cargo/config` without using a deprecated 37 | feature of Cargo ;) 38 | 39 | ### License 40 | 41 | Licensed under either of 42 | 43 | * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 44 | 45 | * [MIT license](http://opensource.org/licenses/MIT) 46 | 47 | at your option. 48 | 49 | License: Apache-2.0/MIT 50 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | 3 | diener - dependency diener is a tool for easily changing [Polkadot SDK](https://github.com/paritytech/polkadot) dependency versions 4 | 5 | [![](https://docs.rs/diener/badge.svg)](https://docs.rs/diener/) [![](https://img.shields.io/crates/v/diener.svg)](https://crates.io/crates/diener) [![](https://img.shields.io/crates/d/diener.png)](https://crates.io/crates/diener) 6 | 7 | * [Usage](#usage) 8 | * [License](#license) 9 | 10 | ## Usage 11 | 12 | ### Update 13 | 14 | The `update` subcommand changes all `Cargo.toml` files in a given folder to use 15 | a specific branch/path/commit/tag. 16 | 17 | Change all Polkadot SDK dependencies in a folder to a different branch: 18 | 19 | ```rust 20 | diener update --branch diener-branch 21 | ``` 22 | 23 | Diener also supports `tag` and `rev` as arguments. 24 | 25 | ### Patch 26 | 27 | The `patch` subcommand adds a patch section for each crate in a given cargo workspace 28 | to the workspace `Cargo.toml` file in some other cargo workspace. 29 | 30 | Patch all git dependencies to be build from a given path: 31 | 32 | ```rust 33 | diener patch --crates-to-patch ../path/to/polkadot-sdk/checkout 34 | ``` 35 | 36 | This subcommand can be compared to `.cargo/config` without using a deprecated 37 | feature of Cargo ;) 38 | 39 | ## License 40 | 41 | Licensed under either of 42 | 43 | * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 44 | 45 | * [MIT license](http://opensource.org/licenses/MIT) 46 | 47 | at your option. 48 | */ 49 | 50 | use env_logger::Env; 51 | use structopt::{ 52 | clap::{crate_name, crate_version}, 53 | StructOpt, 54 | }; 55 | 56 | mod patch; 57 | mod update; 58 | mod workspacify; 59 | 60 | /// diener is a tool for easily finding and changing Polkadot SDK dependency versions. 61 | /// diener will not modified the cargo.lock file but update specific dependencies in the Cargo.toml files or the project. 62 | #[derive(Debug, StructOpt)] 63 | enum SubCommands { 64 | /// Update all `Cargo.toml` files at a given path to some specific path/branch/commit. 65 | Update(update::Update), 66 | /// Patch all crates from a given cargo workspace in another given cargo workspace. 67 | /// 68 | /// This will get all crates from a given cargo workspace and add a patch 69 | /// section for each of these crates to the workspace `Cargo.toml` of a 70 | /// given cargo workspace. Essentially this is the same as using 71 | /// `.cargo/config`, but using a non-deprecated way. 72 | Patch(patch::Patch), 73 | /// Creates a workspace from the supplied directory tree. 74 | /// 75 | /// This can be ran on existing workspaces to make sure everything is properly setup. 76 | /// 77 | /// - Every dependency residing in the tree will be rewritten into a `path` dependency. 78 | /// - The top level `Cargo.toml` `workspace.members` array will be filled with all crates. 79 | /// - It will also be sorted alphabetically 80 | /// - The path dependency entries will be sorted into a canonical order. 81 | Workspacify(workspacify::Workspacify), 82 | } 83 | 84 | /// Cli options of Diener 85 | #[derive(Debug, StructOpt)] 86 | #[structopt( 87 | about = "Diener - dependency diener for replacing Polkadot SDK versions in `Cargo.toml` files" 88 | )] 89 | struct Options { 90 | #[structopt(subcommand)] 91 | subcommand: SubCommands, 92 | } 93 | 94 | fn main() -> anyhow::Result<()> { 95 | env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); 96 | log::info!("Running {} v{}", crate_name!(), crate_version!()); 97 | 98 | match Options::from_args().subcommand { 99 | SubCommands::Update(update) => update.run(), 100 | SubCommands::Patch(patch) => patch.run(), 101 | SubCommands::Workspacify(workspacify) => workspacify.run(), 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/patch.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{anyhow, bail, Context, Error, Result}; 2 | use std::{ 3 | env::current_dir, 4 | fs, 5 | path::{Path, PathBuf}, 6 | str::FromStr, 7 | }; 8 | use structopt::StructOpt; 9 | use toml_edit::{Document, Item, Value}; 10 | 11 | enum PatchTarget { 12 | Crates, 13 | Git(String), 14 | Custom(String), 15 | } 16 | 17 | /// Where should the patch point to? 18 | enum PointTo { 19 | /// Point to the crate path. 20 | Path, 21 | /// Point to the git branch. 22 | GitBranch { repository: String, branch: String }, 23 | /// Point to the git commit. 24 | GitCommit { repository: String, commit: String }, 25 | } 26 | 27 | impl PointTo { 28 | fn from_cli( 29 | point_to_git: Option, 30 | point_to_git_branch: Option, 31 | point_to_git_commit: Option, 32 | ) -> Result { 33 | if let Some(repository) = point_to_git { 34 | if let Some(branch) = point_to_git_branch { 35 | Ok(Self::GitBranch { repository, branch }) 36 | } else if let Some(commit) = point_to_git_commit { 37 | Ok(Self::GitCommit { repository, commit }) 38 | } else { 39 | bail!("`--point-to-git-branch` or `--point-to-git-commit` are required when `--point-to-git` is passed!"); 40 | } 41 | } else { 42 | Ok(Self::Path) 43 | } 44 | } 45 | } 46 | 47 | impl PatchTarget { 48 | /// Returns the patch target in a toml compatible format. 49 | fn as_str(&self) -> &str { 50 | match self { 51 | Self::Crates => "crates-io", 52 | Self::Git(url) => url, 53 | Self::Custom(custom) => custom, 54 | } 55 | } 56 | } 57 | 58 | /// `patch` subcommand options. 59 | #[derive(Debug, StructOpt)] 60 | pub struct Patch { 61 | /// The path to the project where the patch section should be added. 62 | /// 63 | /// If not given, the current directory will be taken. 64 | /// 65 | /// If this points to a `Cargo.toml` file, this file will be taken as the 66 | /// cargo workspace `Cargo.toml` file to add the patches. 67 | /// 68 | /// The patches will be added to the cargo workspace `Cargo.toml` file. 69 | #[structopt(long)] 70 | path: Option, 71 | 72 | /// The workspace that should be scanned and added to the patch section. 73 | /// 74 | /// This will execute `cargo metadata` in the given workspace and add 75 | /// all packages of this workspace to the patch section. 76 | #[structopt(long)] 77 | crates_to_patch: PathBuf, 78 | 79 | /// Instead of using the path to the crates, use the given git repository. 80 | /// 81 | /// This requires that either `--point-to-git-commit` or 82 | /// `--point-to-git-branch` is given as well. 83 | #[structopt(long)] 84 | point_to_git: Option, 85 | 86 | /// Specify the git branch that should be used with the repository given 87 | /// to `--point-to-git`. 88 | #[structopt( 89 | long, 90 | conflicts_with_all = &[ "point-to-git-commit" ], 91 | requires_all = &[ "point-to-git" ], 92 | )] 93 | point_to_git_branch: Option, 94 | 95 | /// Specify the git commit that should be used with the repository given 96 | /// to `--point-to-git`. 97 | #[structopt( 98 | long, 99 | conflicts_with_all = &[ "point-to-git-branch" ], 100 | requires_all = &[ "point-to-git" ], 101 | )] 102 | point_to_git_commit: Option, 103 | 104 | /// The patch target that should be used. 105 | /// The default is the official `polkadot-sdk` repository. 106 | /// 107 | /// The target is `[patch.TARGET]` in the final `Cargo.toml`. 108 | #[structopt( 109 | long, 110 | conflicts_with_all = &[ "crates" ] 111 | )] 112 | target: Option, 113 | 114 | /// Use `crates.io` as patch target instead. 115 | #[structopt( 116 | long, 117 | conflicts_with_all = &[ "target" ] 118 | )] 119 | crates: bool, 120 | } 121 | 122 | impl Patch { 123 | /// Run this subcommand. 124 | pub fn run(self) -> Result<()> { 125 | let patch_target = self.patch_target(); 126 | let path = self 127 | .path 128 | .map(|p| { 129 | if !p.exists() { 130 | bail!("Given --path=`{}` does not exist!", p.display()); 131 | } else { 132 | Ok(p) 133 | } 134 | }) 135 | .unwrap_or_else(|| { 136 | current_dir().with_context(|| anyhow!("Working directory is invalid.")) 137 | })?; 138 | 139 | // Get the path to the `Cargo.toml` where we need to add the patches 140 | let cargo_toml_to_patch = workspace_root_package(&path)?; 141 | 142 | let point_to = PointTo::from_cli( 143 | self.point_to_git, 144 | self.point_to_git_branch, 145 | self.point_to_git_commit, 146 | )?; 147 | 148 | add_patches_for_packages( 149 | &cargo_toml_to_patch, 150 | &patch_target, 151 | workspace_packages(&self.crates_to_patch)?, 152 | point_to, 153 | ) 154 | } 155 | 156 | fn patch_target(&self) -> PatchTarget { 157 | if let Some(ref custom) = self.target { 158 | PatchTarget::Custom(custom.clone()) 159 | } else if self.crates { 160 | PatchTarget::Crates 161 | } else { 162 | PatchTarget::Git("https://github.com/paritytech/polkadot-sdk".into()) 163 | } 164 | } 165 | } 166 | 167 | fn workspace_root_package(path: &Path) -> Result { 168 | if path.ends_with("Cargo.toml") { 169 | return Ok(path.into()); 170 | } 171 | 172 | let metadata = cargo_metadata::MetadataCommand::new() 173 | .current_dir(path) 174 | .exec() 175 | .with_context(|| "Failed to get cargo metadata for workspace")?; 176 | 177 | Ok(metadata.workspace_root.join("Cargo.toml").into()) 178 | } 179 | 180 | /// Returns all package names of the given `workspace`. 181 | fn workspace_packages(workspace: &Path) -> Result> { 182 | let metadata = cargo_metadata::MetadataCommand::new() 183 | .current_dir(workspace) 184 | .exec() 185 | .with_context(|| "Failed to get cargo metadata for workspace.")?; 186 | 187 | Ok(metadata 188 | .workspace_members 189 | .clone() 190 | .into_iter() 191 | .map(move |p| metadata[&p].clone())) 192 | } 193 | 194 | fn add_patches_for_packages( 195 | cargo_toml: &Path, 196 | patch_target: &PatchTarget, 197 | mut packages: impl Iterator, 198 | point_to: PointTo, 199 | ) -> Result<()> { 200 | let content = fs::read_to_string(cargo_toml) 201 | .with_context(|| anyhow!("Failed to read manifest at {}", cargo_toml.display()))?; 202 | let mut doc = Document::from_str(&content).context("Failed to parse Cargo.toml")?; 203 | 204 | let patch_table = doc 205 | .as_table_mut() 206 | .entry("patch") 207 | .or_insert(Item::Table(Default::default())) 208 | .as_table_mut() 209 | .ok_or_else(|| anyhow!("Patch table isn't a toml table!"))?; 210 | 211 | patch_table.set_implicit(true); 212 | 213 | let patch_target_table = patch_table 214 | .entry(patch_target.as_str()) 215 | .or_insert(Item::Table(Default::default())) 216 | .as_table_mut() 217 | .ok_or_else(|| anyhow!("Patch target table isn't a toml table!"))?; 218 | 219 | packages.try_for_each(|mut p| { 220 | log::info!("Adding patch for `{}`.", p.name); 221 | 222 | let patch = patch_target_table 223 | .entry(&p.name) 224 | .or_insert(Item::Value(Value::InlineTable(Default::default()))) 225 | .as_inline_table_mut() 226 | .ok_or_else(|| anyhow!("Patch entry for `{}` isn't an inline table!", p.name))?; 227 | 228 | if p.manifest_path.ends_with("Cargo.toml") { 229 | p.manifest_path.pop(); 230 | } 231 | 232 | let path: PathBuf = p.manifest_path.into(); 233 | 234 | match &point_to { 235 | PointTo::Path => { 236 | *patch.get_or_insert("path", "") = 237 | Value::from(path.display().to_string()).decorated(" ", " "); 238 | } 239 | PointTo::GitBranch { repository, branch } => { 240 | *patch.get_or_insert("git", "") = 241 | Value::from(repository.clone()).decorated(" ", " "); 242 | *patch.get_or_insert("branch", "") = 243 | Value::from(branch.clone()).decorated(" ", " "); 244 | } 245 | PointTo::GitCommit { repository, commit } => { 246 | *patch.get_or_insert("git", "") = 247 | Value::from(repository.clone()).decorated(" ", " "); 248 | *patch.get_or_insert("rev", "") = Value::from(commit.clone()).decorated(" ", " "); 249 | } 250 | } 251 | Ok::<_, Error>(()) 252 | })?; 253 | 254 | fs::write(cargo_toml, doc.to_string()) 255 | .with_context(|| anyhow!("Failed to write manifest to {}", cargo_toml.display())) 256 | } 257 | -------------------------------------------------------------------------------- /src/update.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{bail, ensure, Context, Result}; 2 | use git_url_parse::GitUrl; 3 | use std::{env::current_dir, fs, path::PathBuf, str::FromStr}; 4 | use structopt::StructOpt; 5 | use toml_edit::{Document, InlineTable, Value}; 6 | use walkdir::{DirEntry, WalkDir}; 7 | 8 | /// The version the dependencies should be switched to. 9 | #[derive(Debug, Clone)] 10 | enum Version { 11 | Tag(String), 12 | Branch(String), 13 | Rev(String), 14 | } 15 | 16 | /// `update` subcommand options. 17 | #[derive(Debug, StructOpt)] 18 | pub struct Update { 19 | /// The path where Diener should search for `Cargo.toml` files. 20 | #[structopt(long)] 21 | path: Option, 22 | 23 | /// The `branch` that the dependencies should use. 24 | #[structopt(long, conflicts_with_all = &[ "rev", "tag" ])] 25 | branch: Option, 26 | 27 | /// The `rev` that the dependencies should use. 28 | #[structopt(long, conflicts_with_all = &[ "branch", "tag" ])] 29 | rev: Option, 30 | 31 | /// The `tag` that the dependencies should use. 32 | #[structopt(long, conflicts_with_all = &[ "rev", "branch" ])] 33 | tag: Option, 34 | 35 | /// Rewrite the `git` url to the give one. 36 | #[structopt(long)] 37 | git: Option, 38 | } 39 | 40 | impl Update { 41 | /// Convert the options into the parts `Option`, `Version`, `Option`. 42 | fn into_parts(self) -> Result<(Option, Version, Option)> { 43 | let version = if let Some(branch) = self.branch { 44 | Version::Branch(branch) 45 | } else if let Some(rev) = self.rev { 46 | Version::Rev(rev) 47 | } else if let Some(tag) = self.tag { 48 | Version::Tag(tag) 49 | } else { 50 | bail!("You need to pass `--branch`, `--tag` or `--rev`"); 51 | }; 52 | 53 | Ok((self.git, version, self.path)) 54 | } 55 | 56 | /// Run this subcommand. 57 | pub fn run(self) -> Result<()> { 58 | let (git, version, path) = self.into_parts()?; 59 | 60 | let path = path 61 | .map(Ok) 62 | .unwrap_or_else(|| current_dir().with_context(|| "Working directory is invalid."))?; 63 | ensure!( 64 | path.is_dir(), 65 | "Path '{}' is not a directory.", 66 | path.display() 67 | ); 68 | 69 | let is_hidden = |entry: &DirEntry| { 70 | entry 71 | .file_name() 72 | .to_str() 73 | .map(|s| s.starts_with('.')) 74 | .unwrap_or(false) 75 | }; 76 | 77 | WalkDir::new(path) 78 | .follow_links(true) 79 | .into_iter() 80 | .filter_entry(|e| !is_hidden(e)) 81 | .filter_map(|e| e.ok()) 82 | .filter(|e| { 83 | e.file_type().is_file() && e.file_name().to_string_lossy().ends_with("Cargo.toml") 84 | }) 85 | .try_for_each(|toml| handle_toml_file(toml.into_path(), &git, &version)) 86 | } 87 | } 88 | 89 | /// Handle a given dependency. 90 | /// 91 | /// This directly modifies the given `dep` in the requested way. 92 | fn handle_dependency(name: &str, dep: &mut InlineTable, git: &Option, version: &Version) { 93 | if !dep 94 | .get("git") 95 | .and_then(|v| v.as_str()) 96 | .and_then(|d| GitUrl::parse(d).ok()) 97 | .is_some_and(|git| git.name == "polkadot-sdk") 98 | { 99 | return; 100 | } 101 | 102 | if let Some(new_git) = git { 103 | *dep.get_or_insert("git", "") = Value::from(new_git.as_str()).decorated(" ", ""); 104 | } 105 | 106 | dep.remove("tag"); 107 | dep.remove("branch"); 108 | dep.remove("rev"); 109 | 110 | match version { 111 | Version::Tag(tag) => { 112 | *dep.get_or_insert("tag", "") = Value::from(tag.as_str()).decorated(" ", " "); 113 | } 114 | Version::Branch(branch) => { 115 | *dep.get_or_insert("branch", "") = Value::from(branch.as_str()).decorated(" ", " "); 116 | } 117 | Version::Rev(rev) => { 118 | *dep.get_or_insert("rev", "") = Value::from(rev.as_str()).decorated(" ", " "); 119 | } 120 | } 121 | log::debug!(" updated: {:?} <= {}", version, name); 122 | } 123 | 124 | /// Handle a given `Cargo.toml`. 125 | /// 126 | /// This means scanning all dependencies and rewrite the requested onces. 127 | fn handle_toml_file(path: PathBuf, git: &Option, version: &Version) -> Result<()> { 128 | log::info!("Processing: {}", path.display()); 129 | 130 | let mut toml_doc = Document::from_str(&fs::read_to_string(&path)?)?; 131 | 132 | // Iterate over all tables in the document 133 | toml_doc 134 | .clone() 135 | .iter() 136 | // filter out everything that is not a dependency table 137 | .filter(|(k, _)| k.contains("dependencies")) 138 | .filter_map(|(k, v)| v.as_table().map(|t| (k, t))) 139 | .for_each(|(k, t)| { 140 | t.iter() 141 | // Filter everything that is not an inline table (`{ foo = bar }`) 142 | .filter_map(|v| v.1.as_inline_table().map(|_| v.0)) 143 | .for_each(|dn| { 144 | // Get the actual inline table from the document that we modify 145 | let table = toml_doc[k][dn] 146 | .as_inline_table_mut() 147 | .expect("We filter by `is_inline_table`; qed"); 148 | handle_dependency(dn, table, git, version); 149 | }) 150 | }); 151 | 152 | fs::write(&path, toml_doc.to_string())?; 153 | Ok(()) 154 | } 155 | -------------------------------------------------------------------------------- /src/workspacify.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{anyhow, bail, ensure, Context, Result}; 2 | use std::{ 3 | collections::HashMap, 4 | env::current_dir, 5 | fs::{self, OpenOptions}, 6 | io::Read, 7 | path::{Path, PathBuf}, 8 | str::FromStr, 9 | }; 10 | use structopt::StructOpt; 11 | use toml_edit::{value, Array, Document, Formatted, InlineTable, Item, KeyMut, Table, Value}; 12 | use walkdir::WalkDir; 13 | 14 | const FILES_HAVE_PARENTS: &str = "This is a file. Every file has a parent; qed"; 15 | 16 | #[derive(Debug, StructOpt)] 17 | pub struct Workspacify { 18 | /// The path to the workspace root directory. 19 | /// 20 | /// This is the directory where your workspace `Cargo.toml` is or should be located. 21 | /// Uses the working directory if none is supplied. 22 | #[structopt(long)] 23 | path: Option, 24 | } 25 | 26 | impl Workspacify { 27 | pub fn run(self) -> Result<()> { 28 | let workspace = self 29 | .path 30 | .map(Ok) 31 | .unwrap_or_else(|| current_dir().with_context(|| "Working directory is invalid."))?; 32 | ensure!( 33 | workspace.is_dir(), 34 | "Path '{}' is not a directory.", 35 | workspace.display() 36 | ); 37 | 38 | // Create a mapping of package_name -> manifest 39 | let mut packages = HashMap::::new(); 40 | let mut duplicates = HashMap::>::new(); 41 | for manifest in manifest_iter(&workspace) { 42 | if let Some(name) = package_name(&manifest)? { 43 | if let Some(existing) = packages.insert(name.clone(), manifest.clone()) { 44 | duplicates 45 | .entry(name) 46 | .or_insert_with(|| vec![existing.display().to_string()]) 47 | .push(manifest.display().to_string()); 48 | } 49 | } 50 | } 51 | if !duplicates.is_empty() { 52 | bail!("Duplicate crates detected:\n{:#?}", duplicates); 53 | } 54 | 55 | // make sure all crates are recorded in the workspace manifest 56 | update_workspace_members(&workspace, &packages) 57 | .context("Failed to update member list in workspace manifest.")?; 58 | 59 | // transform every package manifest to point to the correct place 60 | // and use the correct version 61 | for (name, path) in packages.iter() { 62 | rewrite_manifest(path, &packages).with_context(|| { 63 | anyhow!( 64 | "Failed to rewrite manifest for {} at {}", 65 | name, 66 | path.display() 67 | ) 68 | })?; 69 | } 70 | 71 | Ok(()) 72 | } 73 | } 74 | 75 | fn manifest_iter(workspace: &Path) -> impl Iterator { 76 | WalkDir::new(workspace) 77 | .follow_links(false) 78 | .into_iter() 79 | .filter_entry(|e| { 80 | !(e.file_name() == "target" || e.file_name().to_string_lossy().starts_with('.')) 81 | }) 82 | .filter_map(|e| e.ok()) 83 | .filter(|e| e.file_type().is_file() && e.file_name().to_string_lossy() == "Cargo.toml") 84 | .map(|dir| dir.into_path()) 85 | } 86 | 87 | fn package_name(path: &Path) -> Result> { 88 | let ret = read_toml(path, false)? 89 | .get("package") 90 | .and_then(|p| p.as_table()) 91 | .and_then(|p| p.get("name")) 92 | .and_then(|p| p.as_str()) 93 | .map(Into::into); 94 | Ok(ret) 95 | } 96 | 97 | fn update_workspace_members(workspace: &Path, packages: &HashMap) -> Result<()> { 98 | let manifest = workspace.join("Cargo.toml"); 99 | 100 | // turn packages into a sorted array of pathes 101 | let members: Array = { 102 | let mut members: Vec<_> = packages.values().collect(); 103 | members.sort_unstable(); 104 | let mut members: Array = members 105 | .iter() 106 | .map(|path| { 107 | let member = path 108 | .parent() 109 | .expect(FILES_HAVE_PARENTS) 110 | .strip_prefix(workspace) 111 | .expect("All packages are within the workspace root dir; qed") 112 | .display() 113 | .to_string(); 114 | let mut formatted = Formatted::new(member); 115 | formatted.decor_mut().set_prefix("\n\t"); 116 | Value::String(formatted) 117 | }) 118 | .collect(); 119 | members.set_trailing("\n"); 120 | members.set_trailing_comma(true); 121 | members 122 | }; 123 | 124 | let mut toml = read_toml(&manifest, true).context("Failed to parse workspace manifest")?; 125 | toml.entry("workspace") 126 | .or_insert(Item::Table(Table::new())) 127 | .as_table_mut() 128 | .ok_or_else(|| anyhow!("`workspace` is not a table"))? 129 | .insert("members", value(members)); 130 | 131 | fs::write(&manifest, toml.to_string()).context("Failed to write workspace manifest") 132 | } 133 | 134 | fn rewrite_manifest(path: &Path, packages: &HashMap) -> Result<()> { 135 | let mut toml = read_toml(path, false)?; 136 | 137 | toml.iter_mut() 138 | .filter(|(k, _)| k.contains("dependencies")) 139 | .filter_map(|(_, v)| v.as_table_mut()) 140 | .flat_map(|deps| deps.iter_mut()) 141 | .filter_map(|dep| dep.1.as_inline_table_mut().map(|v| (dep.0, v))) 142 | .try_for_each(|dep| handle_dep((dep.0, dep.1, path), packages))?; 143 | 144 | fs::write(path, toml.to_string()) 145 | .with_context(|| anyhow!("Failed to write manifest to {}", path.display())) 146 | } 147 | 148 | fn handle_dep( 149 | dep: (KeyMut, &mut InlineTable, &Path), 150 | packages: &HashMap, 151 | ) -> Result<()> { 152 | let name = dep 153 | .1 154 | .get("package") 155 | .and_then(|p| p.as_str()) 156 | .unwrap_or_else(|| dep.0.get()); 157 | 158 | // dependency exists within this workspace 159 | let (dependee, dependency) = if let Some(path) = packages.get(name) { 160 | let dependee = path.parent().expect(FILES_HAVE_PARENTS); 161 | let dependency = dep.2.parent().expect(FILES_HAVE_PARENTS); 162 | (dependee, dependency) 163 | } else { 164 | return Ok(()); 165 | }; 166 | 167 | // path in manifests are relative 168 | let relpath = pathdiff::diff_paths(dependee, dependency).ok_or_else(|| { 169 | anyhow!( 170 | "Cannot make {} relative to {}", 171 | dependee.display(), 172 | dependency.display() 173 | ) 174 | })?; 175 | dep.1.remove("git"); 176 | dep.1.remove("branch"); 177 | dep.1.remove("version"); 178 | dep.1 179 | .insert("path", Value::from(relpath.to_string_lossy().as_ref())); 180 | dep.1 181 | .sort_values_by(|k0, _, k1, _| dep_key_order(k0).cmp(&dep_key_order(k1))); 182 | 183 | Ok(()) 184 | } 185 | 186 | fn read_toml(path: &Path, create: bool) -> Result { 187 | let mut content = String::new(); 188 | OpenOptions::new() 189 | .read(true) 190 | .create(create) 191 | .write(create) 192 | .open(path) 193 | .with_context(|| anyhow!("Failed to to open manifest at: {}", path.display()))? 194 | .read_to_string(&mut content) 195 | .with_context(|| anyhow!("Failed to to read manifest at: {}", path.display()))?; 196 | 197 | Document::from_str(&content) 198 | .with_context(|| anyhow!("Failed to to parse manifest at: {}", path.display())) 199 | } 200 | 201 | fn dep_key_order(dep_key: &str) -> u32 { 202 | match dep_key { 203 | "package" => 0, 204 | 205 | "git" => 10, 206 | "path" => 10, 207 | 208 | "version" => 30, 209 | "branch" => 30, 210 | "tag" => 30, 211 | 212 | "default-features" => 40, 213 | 214 | "features" => 50, 215 | 216 | "optional" => 60, 217 | 218 | _ => u32::MAX, 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /templates/formula.rb: -------------------------------------------------------------------------------- 1 | {% set BIN = BIN | default(value=NAME | lower) %} 2 | {%- set HOMEPAGE = HOMEPAGE | default(value=SITE ~ "/" ~ REPO) -%} 3 | 4 | class {{ NAME }} < Formula 5 | desc "{{ DESCRIPTION }}" 6 | homepage "{{ HOMEPAGE }}" 7 | url "{{ SITE }}/{{ REPO }}/releases/download/v{{ VERSION }}/{{ ARCHIVE | default(value=BIN ~"_macos_v" ~ VERSION) }}.tar.gz" 8 | sha256 "{{ SHA256 }}" 9 | version "{{ VERSION }}" 10 | 11 | def install 12 | bin.install "{{ BIN }}" 13 | end 14 | end 15 | --------------------------------------------------------------------------------