├── .cargo-husky └── hooks │ └── commit-msg ├── .cargo └── config.toml ├── .github ├── banner.png └── workflows │ └── test.yml ├── .gitignore ├── .rustfmt.toml ├── CHANGELOG.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── cliff.toml ├── committed.toml ├── deny.toml ├── rust-toolchain.toml ├── src ├── binary.rs ├── cargo_config.rs ├── cli.rs ├── lib.rs ├── main.rs ├── metadata.rs ├── metadata_test.rs └── shims.rs ├── tests ├── binary_test.rs ├── cargo_config_test.rs ├── cli_integration_test.rs └── shims_test.rs └── tools └── cargo-bin ├── Cargo.toml └── src └── main.rs /.cargo-husky/hooks/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | cargo bin committed --fixup --wip --commit-file $1 6 | -------------------------------------------------------------------------------- /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [alias] 2 | bin = ["run", "--package", "cargo-bin", "--"] 3 | cmd = ["bin", "cargo-cmd"] 4 | deny = ["bin", "cargo-deny"] 5 | gha = ["bin", "cargo-gha"] 6 | insta = ["bin", "cargo-insta"] 7 | llvm-cov = ["bin", "cargo-llvm-cov"] 8 | nextest = ["bin", "cargo-nextest"] 9 | watch = ["bin", "cargo-watch"] 10 | 11 | [env] 12 | BINSTALL_STRATEGIES = "crate-meta-data,compile" 13 | 14 | [net] 15 | git-fetch-with-cli = true 16 | -------------------------------------------------------------------------------- /.github/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinblackman/cargo-run-bin/991dda0185c6fad71f549cfb078bbeb33433aa34/.github/banner.png -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | 3 | name: ci 4 | 5 | jobs: 6 | test_coverage: 7 | name: cargo-run-bin 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | - uses: actions-rs/toolchain@v1 12 | with: 13 | toolchain: stable 14 | - uses: Swatinem/rust-cache@v2 15 | with: 16 | cache-directories: ".bin" 17 | 18 | - name: Install deps 19 | run: | 20 | cargo bin --build 21 | cargo cmd setup-nightly 22 | - name: Lint 23 | run: cargo cmd lint 24 | - name: Test 25 | run: cargo cmd test-coverage-lcov 26 | 27 | - name: Coveralls 28 | uses: coverallsapp/github-action@master 29 | with: 30 | github-token: ${{ secrets.GITHUB_TOKEN }} 31 | path-to-lcov: ./lcov.info 32 | 33 | test: 34 | name: cargo-run-bin 35 | strategy: 36 | matrix: 37 | os: [macos-latest, windows-latest] 38 | runs-on: ${{ matrix.os }} 39 | steps: 40 | - uses: actions/checkout@v2 41 | - uses: actions-rs/toolchain@v1 42 | with: 43 | toolchain: stable 44 | - uses: Swatinem/rust-cache@v2 45 | with: 46 | cache-directories: ".bin" 47 | - name: Install deps 48 | run: | 49 | cargo nextest --help 50 | - name: Test 51 | run: | 52 | cargo build 53 | cargo nextest run 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /.bin 3 | /.tmp 4 | .gha/ 5 | *.profraw 6 | lcov.info 7 | .idea/ 8 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | edition = "2021" 2 | force_multiline_blocks = true 3 | group_imports = "StdExternalCrate" 4 | imports_granularity = "Item" 5 | imports_layout = "HorizontalVertical" 6 | normalize_comments = true 7 | wrap_comments = true 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## [1.7.4] - 2024-11-25 6 | [v1.7.3..v1.7.4](https://github.com/dustinblackman/cargo-run-bin/compare/v1.7.3..v1.7.4) 7 | 8 | 9 | ### 🐛 Bug Fixes 10 | 11 | - Handle plain strings in --sync-aliases ([#25](https://github.com/dustinblackman/cargo-run-bin/issues/25)) - ([3c4d168](https://github.com/dustinblackman/cargo-run-bin/commit/3c4d168f34bf19e2da1099b6351f00b0ced2383c)) 12 | 13 | ## [1.7.3] - 2024-07-05 14 | [v1.7.2..v1.7.3](https://github.com/dustinblackman/cargo-run-bin/compare/v1.7.2..v1.7.3) 15 | 16 | 17 | ### ⛰️ Features 18 | 19 | - Release v1.7.3 - ([c6bd9ec](https://github.com/dustinblackman/cargo-run-bin/commit/c6bd9ecf95fdc54c955090837b57d6fdca82b7d1)) 20 | 21 | ### 🐛 Bug Fixes 22 | 23 | - Fallback to sh for non POSIX shells - ([7281bbb](https://github.com/dustinblackman/cargo-run-bin/commit/7281bbbf0a15b043d66e8f9f307485e210877df0)) 24 | 25 | ### 📚 Documentation 26 | 27 | - Add distro packages section ([#22](https://github.com/dustinblackman/cargo-run-bin/issues/22)) - ([7e8378c](https://github.com/dustinblackman/cargo-run-bin/commit/7e8378c0ebff7c044e475407583ed8caf6bf2ec0)) 28 | - Update version in README - ([42f87f9](https://github.com/dustinblackman/cargo-run-bin/commit/42f87f989cda444b841608db79c83cec2435a618)) 29 | 30 | ### ⚙️ Miscellaneous Tasks 31 | 32 | - Fix lint - ([a8a5d45](https://github.com/dustinblackman/cargo-run-bin/commit/a8a5d452f81eb29483f584d4bc636cfe2393386c)) 33 | - Drop owo - ([1dd54c4](https://github.com/dustinblackman/cargo-run-bin/commit/1dd54c478e35f22e4ba7fd1e0d46c100ecd64b62)) 34 | - Update bin deps - ([33a2c0f](https://github.com/dustinblackman/cargo-run-bin/commit/33a2c0ff5694f75e9ddc7af8f65b223ab090a32f)) 35 | - Drop dprint - ([02a968f](https://github.com/dustinblackman/cargo-run-bin/commit/02a968fc095cf8afc1615ea4cd4e936b4fc1e7e6)) 36 | - Update binstall - ([ea0de75](https://github.com/dustinblackman/cargo-run-bin/commit/ea0de75ef4b0ff8d4c99ce3ab0cdd051da9f7006)) 37 | - Update cargo-gha to latest - ([0dd4f2d](https://github.com/dustinblackman/cargo-run-bin/commit/0dd4f2d23d5909374f4513424490ff887a41d742)) 38 | 39 | ## [1.7.2] - 2024-01-02 40 | [v1.7.1..v1.7.2](https://github.com/dustinblackman/cargo-run-bin/compare/v1.7.1..v1.7.2) 41 | 42 | 43 | ### ⛰️ Features 44 | 45 | - Release v1.7.2 - ([d11b188](https://github.com/dustinblackman/cargo-run-bin/commit/d11b1885a946214e4027a4f564f108b93c0ef0ea)) 46 | 47 | ### ⚙️ Miscellaneous Tasks 48 | 49 | - Reduce MSRV - ([813f0bc](https://github.com/dustinblackman/cargo-run-bin/commit/813f0bc35ece0092cf04be043cc89571dea12ff2)) 50 | - Remove version pinning - ([d466351](https://github.com/dustinblackman/cargo-run-bin/commit/d466351f0ea2098d063959b63585d24c9fd0e06d)) 51 | 52 | ## [1.7.1] - 2024-01-01 53 | [v1.7.0..v1.7.1](https://github.com/dustinblackman/cargo-run-bin/compare/v1.7.0..v1.7.1) 54 | 55 | 56 | ### ⛰️ Features 57 | 58 | - Release v1.7.1 - ([c4c0861](https://github.com/dustinblackman/cargo-run-bin/commit/c4c0861672c77e0315070e30cf86719fa8e377b9)) 59 | 60 | ### 🐛 Bug Fixes 61 | 62 | - Version flag, no parameters - ([e00ebe3](https://github.com/dustinblackman/cargo-run-bin/commit/e00ebe3c93367df53c91a6eb08fe3e8dc6e9fda8)) 63 | 64 | ## [1.7.0] - 2024-01-01 65 | [v1.6.1..v1.7.0](https://github.com/dustinblackman/cargo-run-bin/compare/v1.6.1..v1.7.0) 66 | 67 | 68 | ### ⛰️ Features 69 | 70 | - Release v1.7.0 - ([416012f](https://github.com/dustinblackman/cargo-run-bin/commit/416012fa4cf20bc8c1a233a76f738c71c25e7d08)) 71 | - Add get_shim_paths - ([fd60a88](https://github.com/dustinblackman/cargo-run-bin/commit/fd60a88054b194cd56e71faaff57044f47c7ce7f)) 72 | - Add docs and features to support library usage - ([e180db6](https://github.com/dustinblackman/cargo-run-bin/commit/e180db69aee09faff006435fb83da3c59155f1d8)) 73 | 74 | ### 🐛 Bug Fixes 75 | 76 | - Show help when no args are passed - ([6951082](https://github.com/dustinblackman/cargo-run-bin/commit/69510826e8c144093aeb0bfb7eb20475028e2d9d)) 77 | 78 | ### 🚜 Refactor 79 | 80 | - Run tests as integration test ([#17](https://github.com/dustinblackman/cargo-run-bin/issues/17)) - ([4c5c49a](https://github.com/dustinblackman/cargo-run-bin/commit/4c5c49aeff217333024945d51f5483160c8be8ec)) 81 | - Run tests as integration test - ([1e51847](https://github.com/dustinblackman/cargo-run-bin/commit/1e518477918de1d900702134b604f8a10d7ad265)) 82 | 83 | ### 🧪 Testing 84 | 85 | - Shims imports - ([ca5da68](https://github.com/dustinblackman/cargo-run-bin/commit/ca5da684618025b4ea19fa6699c5978d9e67298a)) 86 | - Move artifacts out of target - ([2f2fd57](https://github.com/dustinblackman/cargo-run-bin/commit/2f2fd579b60d0b5639c83dc7dc7dc8bd9cb337a9)) 87 | 88 | ### ⚙️ Miscellaneous Tasks 89 | 90 | - Merge branch 'lib-support' - ([c21ce48](https://github.com/dustinblackman/cargo-run-bin/commit/c21ce487ccbf72626f32a54e71fac531905a2a61)) 91 | - Fix warning on Windows builds - ([cadddd7](https://github.com/dustinblackman/cargo-run-bin/commit/cadddd77d84a072b62fdd6281cee4d87136d3539)) 92 | - Revert unit test move - ([cfb552e](https://github.com/dustinblackman/cargo-run-bin/commit/cfb552ebf08403dda681f8c4b5b2cb5c811b0173)) 93 | - Lint - ([834d089](https://github.com/dustinblackman/cargo-run-bin/commit/834d0898739fe86e47f5fa9f901b50dbcb041797)) 94 | - Fix the rust-version field in Cargo.toml ([#19](https://github.com/dustinblackman/cargo-run-bin/issues/19)) - ([23b2f39](https://github.com/dustinblackman/cargo-run-bin/commit/23b2f398f1cbff666384089bf88bb16430630ba7)) 95 | 96 | ## [1.6.1] - 2023-12-16 97 | [v1.6.0..v1.6.1](https://github.com/dustinblackman/cargo-run-bin/compare/v1.6.0..v1.6.1) 98 | 99 | 100 | ### ⛰️ Features 101 | 102 | - Release v1.6.1 - ([5d18ad7](https://github.com/dustinblackman/cargo-run-bin/commit/5d18ad7e827fb7bb0417218610a13a23bf7b5fd0)) 103 | 104 | ### 🐛 Bug Fixes 105 | 106 | - Set MSRV - ([a5fc8ac](https://github.com/dustinblackman/cargo-run-bin/commit/a5fc8ac68dbba9f4f8a4b5d02bfd1e031bcdc56d)) 107 | - Release command - ([032e97f](https://github.com/dustinblackman/cargo-run-bin/commit/032e97f52c612d68c4668d333e46cf56015b7eb6)) 108 | 109 | ## [1.6.0] - 2023-12-01 110 | [v1.5.0..v1.6.0](https://github.com/dustinblackman/cargo-run-bin/compare/v1.5.0..v1.6.0) 111 | 112 | 113 | ### ⛰️ Features 114 | 115 | - Release v1.6.0 - ([fd34f2b](https://github.com/dustinblackman/cargo-run-bin/commit/fd34f2bd1713eefacd59d429d73d71da3c638325)) 116 | - Merge branch 'windows' - ([a559325](https://github.com/dustinblackman/cargo-run-bin/commit/a5593250fc83922d9327a6896fed1c27625af73e)) 117 | - Add Windows support - ([8e4a6cc](https://github.com/dustinblackman/cargo-run-bin/commit/8e4a6cc298a94190fe4ab209d9fa48a9a1afc791)) 118 | 119 | ### ⚙️ Miscellaneous Tasks 120 | 121 | - Remove cargo-dist - ([553852d](https://github.com/dustinblackman/cargo-run-bin/commit/553852d8af838d7d5665e57ff5c4f8b9642c661e)) 122 | - Cleanup CI - ([42403a2](https://github.com/dustinblackman/cargo-run-bin/commit/42403a2d311e346f78d5d28f729229639f69bb4b)) 123 | - Add release script - ([2b10208](https://github.com/dustinblackman/cargo-run-bin/commit/2b10208d1e4a7be7fcf4a38a367525a82046ce2f)) 124 | - Add banner - ([ddca279](https://github.com/dustinblackman/cargo-run-bin/commit/ddca279206775df41a98d05f476d579e6145c586)) 125 | 126 | ## [1.5.0] - 2023-10-27 127 | [v1.4.1..v1.5.0](https://github.com/dustinblackman/cargo-run-bin/compare/v1.4.1..v1.5.0) 128 | 129 | 130 | ### ⛰️ Features 131 | 132 | - Support path in package source - ([d4c8c39](https://github.com/dustinblackman/cargo-run-bin/commit/d4c8c392e5f8b40e330cd5b596eda68b1d378e79)) 133 | 134 | ### 🐛 Bug Fixes 135 | 136 | - Cargo.lock - ([505a155](https://github.com/dustinblackman/cargo-run-bin/commit/505a1559ae74893d55b9712ddafec0b57f7e1c5d)) 137 | - Upgrade cargo-binstall dep - ([e2f746c](https://github.com/dustinblackman/cargo-run-bin/commit/e2f746c37f3954688fb535318d73cddc4255daf4)) 138 | - Changelog - ([1ac6a3d](https://github.com/dustinblackman/cargo-run-bin/commit/1ac6a3d7cd331967c3bd5d9061d6b6862e33c030)) 139 | 140 | ### 📚 Documentation 141 | 142 | - Add path - ([21fc3db](https://github.com/dustinblackman/cargo-run-bin/commit/21fc3db067967e36994e297cc09236c089ecc9b9)) 143 | 144 | ### ⚙️ Miscellaneous Tasks 145 | 146 | - Release cargo-run-bin version 1.5.0 - ([7b1d981](https://github.com/dustinblackman/cargo-run-bin/commit/7b1d98199b17aa241f063e47a0ce3b1087968104)) 147 | - Fix binary.rs lint - ([8f50248](https://github.com/dustinblackman/cargo-run-bin/commit/8f5024858944f82a9660a8cc49b69ad244e6d6c3)) 148 | 149 | ## [1.4.1] - 2023-10-06 150 | [v1.4.0..v1.4.1](https://github.com/dustinblackman/cargo-run-bin/compare/v1.4.0..v1.4.1) 151 | 152 | 153 | ### 📚 Documentation 154 | 155 | - Change changelog format - ([b784580](https://github.com/dustinblackman/cargo-run-bin/commit/b784580ebd613f273527bec147baad6b385b848a)) 156 | 157 | ### ⚙️ Miscellaneous Tasks 158 | 159 | - Release cargo-run-bin version 1.4.1 - ([4529a15](https://github.com/dustinblackman/cargo-run-bin/commit/4529a155562985e8a893317664997252eb389947)) 160 | - Lint - ([16124e7](https://github.com/dustinblackman/cargo-run-bin/commit/16124e7f64308981c902fca5d8e5c3e42863e086)) 161 | - Aliases -> Shims - ([00ca465](https://github.com/dustinblackman/cargo-run-bin/commit/00ca465948bc27afaaf767f263ff3c62e464f003)) 162 | - `tauri-mobile` -> `cargo-mobile2` - ([e2130fe](https://github.com/dustinblackman/cargo-run-bin/commit/e2130fe1b0813e153ac49ac78bdbb3d289d64bc2)) 163 | 164 | ## [1.4.0] - 2023-10-04 165 | [v1.3.2..v1.4.0](https://github.com/dustinblackman/cargo-run-bin/compare/v1.3.2..v1.4.0) 166 | 167 | 168 | ### ⛰️ Features 169 | 170 | - Support git in package source - ([7151499](https://github.com/dustinblackman/cargo-run-bin/commit/7151499b4b47861f84c63b958af8cd36aa8648a9)) 171 | 172 | ### 📚 Documentation 173 | 174 | - Add git - ([a97993c](https://github.com/dustinblackman/cargo-run-bin/commit/a97993c9abb74259084f37857a40c3f6b2dad576)) 175 | 176 | ### 🧪 Testing 177 | 178 | - Additional git flows - ([a6144eb](https://github.com/dustinblackman/cargo-run-bin/commit/a6144ebcb9bb38479a78b8caf50afbd27551983d)) 179 | 180 | ### ⚙️ Miscellaneous Tasks 181 | 182 | - Release cargo-run-bin version 1.4.0 - ([32f72e8](https://github.com/dustinblackman/cargo-run-bin/commit/32f72e8b600164ae188af332af66954e177f88e7)) 183 | - Lint - ([ebba9c4](https://github.com/dustinblackman/cargo-run-bin/commit/ebba9c44f97ab0331f8114b72a99caf60c0d8de4)) 184 | 185 | ## [1.3.2] - 2023-09-20 186 | [v1.3.1..v1.3.2](https://github.com/dustinblackman/cargo-run-bin/compare/v1.3.1..v1.3.2) 187 | 188 | 189 | ### 🐛 Bug Fixes 190 | 191 | - Deserailizing default-features - ([3c15340](https://github.com/dustinblackman/cargo-run-bin/commit/3c153408947f3aee7a09d7041c9a1d9fdfe5f3a5)) 192 | 193 | ### ⚙️ Miscellaneous Tasks 194 | 195 | - Release cargo-run-bin version 1.3.2 - ([be3cc40](https://github.com/dustinblackman/cargo-run-bin/commit/be3cc4059b7d961819d3c47268f30ee1b87b0ec1)) 196 | 197 | ## [1.3.1] - 2023-09-20 198 | [v1.3.0..v1.3.1](https://github.com/dustinblackman/cargo-run-bin/compare/v1.3.0..v1.3.1) 199 | 200 | 201 | ### 🐛 Bug Fixes 202 | 203 | - Duplicate PATH entries - ([0914ff7](https://github.com/dustinblackman/cargo-run-bin/commit/0914ff7ba3316d3b9cddc025febf75df3135a002)) 204 | 205 | ### ⚙️ Miscellaneous Tasks 206 | 207 | - Release cargo-run-bin version 1.3.1 - ([83349f9](https://github.com/dustinblackman/cargo-run-bin/commit/83349f99e01d665336d26ff7753ffb2a5a6ffb12)) 208 | 209 | ## [1.3.0] - 2023-09-20 210 | [v1.2.0..v1.3.0](https://github.com/dustinblackman/cargo-run-bin/compare/v1.2.0..v1.3.0) 211 | 212 | 213 | ### ⛰️ Features 214 | 215 | - Add cargo-gha to path if it exists - ([c404b48](https://github.com/dustinblackman/cargo-run-bin/commit/c404b480e17e9abf12586dc865111d7546609849)) 216 | - Add alias scripts - ([3c6dbac](https://github.com/dustinblackman/cargo-run-bin/commit/3c6dbace4e5f2e1442f7da9805aa5a61e8ba5c9b)) 217 | - Add crate features config - ([e7d0f4d](https://github.com/dustinblackman/cargo-run-bin/commit/e7d0f4d9ccff32aeb9a04088d84ce933d85d4885)) 218 | 219 | ### ⚙️ Miscellaneous Tasks 220 | 221 | - Release cargo-run-bin version 1.3.0 - ([f044465](https://github.com/dustinblackman/cargo-run-bin/commit/f044465c6df800fd4694334982cffa76a7157ec2)) 222 | - Update lockfile - ([c6f752f](https://github.com/dustinblackman/cargo-run-bin/commit/c6f752f24a01077fb260c9561c7b4aeed1972fdf)) 223 | 224 | ## [1.2.0] - 2023-08-26 225 | [v1.1.5..v1.2.0](https://github.com/dustinblackman/cargo-run-bin/compare/v1.1.5..v1.2.0) 226 | 227 | 228 | ### ⛰️ Features 229 | 230 | - Add support for Cargo workspaces - ([208b000](https://github.com/dustinblackman/cargo-run-bin/commit/208b000f47ee7666009a066a9f2a5124275ea381)) 231 | 232 | ### 🐛 Bug Fixes 233 | 234 | - Nightly setup - ([c50b3a5](https://github.com/dustinblackman/cargo-run-bin/commit/c50b3a520f5f0aee7579f816fc8b89b6309fd5d5)) 235 | 236 | ### 📚 Documentation 237 | 238 | - Add commit hashes to changelog - ([28e7c84](https://github.com/dustinblackman/cargo-run-bin/commit/28e7c8488da0972b382cb729ad07e208b3535e81)) 239 | 240 | ### ⚙️ Miscellaneous Tasks 241 | 242 | - Release cargo-run-bin version 1.2.0 - ([b600075](https://github.com/dustinblackman/cargo-run-bin/commit/b600075b1af551d509fdf9fcfeeff97d74c5d446)) 243 | 244 | ## [1.1.5] - 2023-08-12 245 | [v1.1.4..v1.1.5](https://github.com/dustinblackman/cargo-run-bin/compare/v1.1.4..v1.1.5) 246 | 247 | 248 | ### 🐛 Bug Fixes 249 | 250 | - Help command when using cargo - ([25ace47](https://github.com/dustinblackman/cargo-run-bin/commit/25ace47c61a1c7d4e46d734619917ac8539fa2df)) 251 | 252 | ### 📚 Documentation 253 | 254 | - Fix links - ([c40edbf](https://github.com/dustinblackman/cargo-run-bin/commit/c40edbfb888aec37400dd70bc5dc39b60d5e65b8)) 255 | - Update parameters table - ([5eae9a9](https://github.com/dustinblackman/cargo-run-bin/commit/5eae9a9968478e7fc1eeae6b14333ef83e8283c7)) 256 | 257 | ### 🧪 Testing 258 | 259 | - CLI integration snapshots - ([2524b71](https://github.com/dustinblackman/cargo-run-bin/commit/2524b7111f7cb2ac6cbc31f07143c6702f0844ac)) 260 | 261 | ### ⚙️ Miscellaneous Tasks 262 | 263 | - Release cargo-run-bin version 1.1.5 - ([d803d74](https://github.com/dustinblackman/cargo-run-bin/commit/d803d74f79384f6b9707eecc6bc58a156f7d3ba4)) 264 | - Update dprint - ([499c1bc](https://github.com/dustinblackman/cargo-run-bin/commit/499c1bccc3e1b5b7cb4a61f6610892c2c9fbb5b6)) 265 | - Speed up nightly setup command - ([dd30048](https://github.com/dustinblackman/cargo-run-bin/commit/dd30048696a9e7e013415a0ba8820d6afeb763a7)) 266 | - Add release profile - ([e12575c](https://github.com/dustinblackman/cargo-run-bin/commit/e12575ced1d842c29158f17c9826e6fd24517883)) 267 | - Upgrade binstall to 1.2.0 - ([f015f5c](https://github.com/dustinblackman/cargo-run-bin/commit/f015f5ca265c7d0ac9af9db364e7e1456355d956)) 268 | - Remove unused deps - ([2562b7f](https://github.com/dustinblackman/cargo-run-bin/commit/2562b7f16e7b0bed1c92bc1a83301fae5d1697eb)) 269 | - Add commit linting - ([b6b358c](https://github.com/dustinblackman/cargo-run-bin/commit/b6b358cc5781b899d8362ae153564ff9060feda5)) 270 | - Add release and changelog scripts - ([6b0e2b0](https://github.com/dustinblackman/cargo-run-bin/commit/6b0e2b0d9b6ce0bd6302ca87f38d592ef22824a4)) 271 | 272 | ## [1.1.4] - 2023-08-08 273 | [v1.1.3..v1.1.4](https://github.com/dustinblackman/cargo-run-bin/compare/v1.1.3..v1.1.4) 274 | 275 | 276 | ### ⚙️ Miscellaneous Tasks 277 | 278 | - Release v1.1.4 - ([494d7ac](https://github.com/dustinblackman/cargo-run-bin/commit/494d7acfefc7ac8a3e2124b50fcd3f951fc5d196)) 279 | - Drop windows releases - ([d65fb49](https://github.com/dustinblackman/cargo-run-bin/commit/d65fb495283573ee2ecac0c7edba66c9551b6a95)) 280 | 281 | ## [1.1.3] - 2023-08-08 282 | [v1.1.2..v1.1.3](https://github.com/dustinblackman/cargo-run-bin/compare/v1.1.2..v1.1.3) 283 | 284 | 285 | ### 🐛 Bug Fixes 286 | 287 | - Release workflow - ([f012617](https://github.com/dustinblackman/cargo-run-bin/commit/f012617a3993c58608bcffe9e2d4b9379bbc25d9)) 288 | 289 | ### ⚙️ Miscellaneous Tasks 290 | 291 | - Release v1.1.3 - ([7783dbd](https://github.com/dustinblackman/cargo-run-bin/commit/7783dbd4b9f2460c5900c7e00b65d9ec2ab4e54b)) 292 | 293 | ## [1.1.2] - 2023-08-08 294 | [v1.1.1..v1.1.2](https://github.com/dustinblackman/cargo-run-bin/compare/v1.1.1..v1.1.2) 295 | 296 | 297 | ### 🐛 Bug Fixes 298 | 299 | - Release workflow - ([27ce8e0](https://github.com/dustinblackman/cargo-run-bin/commit/27ce8e0f63a4a7181ba780791ac8a206fbbe5d5d)) 300 | 301 | ### ⚙️ Miscellaneous Tasks 302 | 303 | - Release v1.1.2 - ([883a75f](https://github.com/dustinblackman/cargo-run-bin/commit/883a75ffad28d62d29c7ab87b7cc8bc186898dea)) 304 | 305 | ## [1.1.1] - 2023-08-08 306 | [v1.0.1..v1.1.1](https://github.com/dustinblackman/cargo-run-bin/compare/v1.0.1..v1.1.1) 307 | 308 | 309 | ### ⛰️ Features 310 | 311 | - Add binstall support - ([f702124](https://github.com/dustinblackman/cargo-run-bin/commit/f702124692e23f8c14040cf0935b90c4877ed4ee)) 312 | 313 | ### 🐛 Bug Fixes 314 | 315 | - Release command - ([af9715b](https://github.com/dustinblackman/cargo-run-bin/commit/af9715b4f741ede4556a6fecfb8d70a9dbd32a9a)) 316 | 317 | ### ⚙️ Miscellaneous Tasks 318 | 319 | - Release v1.1.1 - ([a6ddf14](https://github.com/dustinblackman/cargo-run-bin/commit/a6ddf14394f1c251f55899257931a374466bed76)) 320 | - Drop cargo release - ([f87e73c](https://github.com/dustinblackman/cargo-run-bin/commit/f87e73c8a2b6fa68832363b0e28f3c106f5a622b)) 321 | - Add artifact releases - ([ced0630](https://github.com/dustinblackman/cargo-run-bin/commit/ced06305199c2a47b3465ba23efeeccfd9dfb722)) 322 | - Add cargo-cmd - ([150af5b](https://github.com/dustinblackman/cargo-run-bin/commit/150af5b4e1a75f5ca7b816716dbbcd2be0c66000)) 323 | - Add clippy to toolchain - ([aa7161e](https://github.com/dustinblackman/cargo-run-bin/commit/aa7161e0bf3ff522144e318b26746359801b0b07)) 324 | 325 | ## [1.0.1] - 2023-08-07 326 | [v1.0.0..v1.0.1](https://github.com/dustinblackman/cargo-run-bin/compare/v1.0.0..v1.0.1) 327 | 328 | 329 | ### 🐛 Bug Fixes 330 | 331 | - Sorting aliases - ([b4ccdd1](https://github.com/dustinblackman/cargo-run-bin/commit/b4ccdd189376506d64d1911de0f17e3c49dda0d0)) 332 | - Integration tests with code coverage commands - ([9a940f7](https://github.com/dustinblackman/cargo-run-bin/commit/9a940f7dee59fca6136d4f82a39b141fae95f580)) 333 | - Test lcov - ([49ea7c1](https://github.com/dustinblackman/cargo-run-bin/commit/49ea7c10cb3a311dc10dd4bef2f9a76668419378)) 334 | - Test scripts exiting - ([1440910](https://github.com/dustinblackman/cargo-run-bin/commit/1440910eadfc638cb6a1da65807a2e24bb7e0a97)) 335 | - Lint - ([74b66ad](https://github.com/dustinblackman/cargo-run-bin/commit/74b66ad09d2346e7def0ea7275e16f4bd37bd5e6)) 336 | 337 | ## [1.0.0] - 2023-08-07 338 | [..v1.0.0](https://github.com/dustinblackman/cargo-run-bin/compare/..v1.0.0) 339 | 340 | 341 | ### ⛰️ Features 342 | 343 | - Add sync aliases - ([5d7ffed](https://github.com/dustinblackman/cargo-run-bin/commit/5d7ffed87bb9ff7b78ce7a228379a35492e45f11)) 344 | - Add build and run functionality - ([9a7218c](https://github.com/dustinblackman/cargo-run-bin/commit/9a7218c20c09797097b518a605c1d2b6c365ec30)) 345 | - Rewrite reading cargo.toml - ([12bccba](https://github.com/dustinblackman/cargo-run-bin/commit/12bccbaf5e60f7781f27b6b28fb9c4bd0922acc4)) 346 | - Add metadata options for binaries - ([3d176a1](https://github.com/dustinblackman/cargo-run-bin/commit/3d176a170b7b1bec81eb8a06d98706164b218657)) 347 | 348 | ### 🐛 Bug Fixes 349 | 350 | - Llvm-cov - ([257af9d](https://github.com/dustinblackman/cargo-run-bin/commit/257af9dc7903eddcf923e0ab55b3575917d0baaf)) 351 | - Cargo commands, add initial tests - ([66a2271](https://github.com/dustinblackman/cargo-run-bin/commit/66a2271ca4ea57013d85d36a528c749d057d2959)) 352 | 353 | ### 📚 Documentation 354 | 355 | - Format - ([9f1b0db](https://github.com/dustinblackman/cargo-run-bin/commit/9f1b0dbba03293a3f120bfc8f4dcf0eeb1540734)) 356 | - Update readme - ([8ab7f77](https://github.com/dustinblackman/cargo-run-bin/commit/8ab7f777fcbd99bb1e50067476ad621b0102013e)) 357 | 358 | ### 🧪 Testing 359 | 360 | - Cli integration tests - ([d087a06](https://github.com/dustinblackman/cargo-run-bin/commit/d087a066c3b160240a33c7096e38d3414b8fcaf1)) 361 | - Cargo_config - ([281b18b](https://github.com/dustinblackman/cargo-run-bin/commit/281b18b52516c8af89f16e2266c11aa33e321939)) 362 | - Binary - ([12146af](https://github.com/dustinblackman/cargo-run-bin/commit/12146afcb515b837a36900afcc3185a0987aec36)) 363 | - Bin target packages - ([edf2c1f](https://github.com/dustinblackman/cargo-run-bin/commit/edf2c1f905c28f68244f5af65bdf79e55b233d8f)) 364 | 365 | ### ⚙️ Miscellaneous Tasks 366 | 367 | - Add release command - ([b40f043](https://github.com/dustinblackman/cargo-run-bin/commit/b40f0436e8eb231975168fda87fdb8da0f675d0a)) 368 | - Update test commands - ([c12a4d6](https://github.com/dustinblackman/cargo-run-bin/commit/c12a4d6c90aed2cc944082dae4f779a5cd8cc5cf)) 369 | - Update ci - ([6671333](https://github.com/dustinblackman/cargo-run-bin/commit/6671333b5978890d804b2be71f2d3f2f1299f83e)) 370 | - Lint - ([cd157a7](https://github.com/dustinblackman/cargo-run-bin/commit/cd157a727734d06322a4941ff35aa3db6a092670)) 371 | - Clean error outputs, unused deps - ([b0171f4](https://github.com/dustinblackman/cargo-run-bin/commit/b0171f4a4d321dae6c783d224ab645ffaa67a555)) 372 | - Clean - ([10216bb](https://github.com/dustinblackman/cargo-run-bin/commit/10216bb2399e3d22ef71f6d87954cf207eab1ee0)) 373 | - Upgrade cargo_toml - ([b81dcd6](https://github.com/dustinblackman/cargo-run-bin/commit/b81dcd607089b05eb939e915514334b070a4bb35)) 374 | - Drop fstrings - ([b5388e3](https://github.com/dustinblackman/cargo-run-bin/commit/b5388e33b000d54444fa5213472546eb3164872d)) 375 | - Format - ([cbc9e3a](https://github.com/dustinblackman/cargo-run-bin/commit/cbc9e3ab710c863ef28fcb68583ab4bb07c9dadc)) 376 | 377 | 378 | -------------------------------------------------------------------------------- /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 = "anstream" 7 | version = "0.3.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" 10 | dependencies = [ 11 | "anstyle", 12 | "anstyle-parse", 13 | "anstyle-query", 14 | "anstyle-wincon", 15 | "colorchoice", 16 | "is-terminal", 17 | "utf8parse", 18 | ] 19 | 20 | [[package]] 21 | name = "anstyle" 22 | version = "1.0.3" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46" 25 | 26 | [[package]] 27 | name = "anstyle-parse" 28 | version = "0.2.1" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" 31 | dependencies = [ 32 | "utf8parse", 33 | ] 34 | 35 | [[package]] 36 | name = "anstyle-query" 37 | version = "1.0.0" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" 40 | dependencies = [ 41 | "windows-sys 0.48.0", 42 | ] 43 | 44 | [[package]] 45 | name = "anstyle-wincon" 46 | version = "1.0.2" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c" 49 | dependencies = [ 50 | "anstyle", 51 | "windows-sys 0.48.0", 52 | ] 53 | 54 | [[package]] 55 | name = "anyhow" 56 | version = "1.0.40" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" 59 | 60 | [[package]] 61 | name = "assert_cmd" 62 | version = "2.0.12" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | checksum = "88903cb14723e4d4003335bb7f8a14f27691649105346a0f0957466c096adfe6" 65 | dependencies = [ 66 | "anstyle", 67 | "bstr", 68 | "doc-comment", 69 | "predicates", 70 | "predicates-core", 71 | "predicates-tree", 72 | "wait-timeout", 73 | ] 74 | 75 | [[package]] 76 | name = "bitflags" 77 | version = "2.4.0" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" 80 | 81 | [[package]] 82 | name = "bstr" 83 | version = "1.6.2" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "4c2f7349907b712260e64b0afe2f84692af14a454be26187d9df565c7f69266a" 86 | dependencies = [ 87 | "memchr", 88 | "regex-automata", 89 | "serde", 90 | ] 91 | 92 | [[package]] 93 | name = "cargo-bin" 94 | version = "0.0.0" 95 | dependencies = [ 96 | "cargo-run-bin 1.7.4 (registry+https://github.com/rust-lang/crates.io-index)", 97 | ] 98 | 99 | [[package]] 100 | name = "cargo-husky" 101 | version = "1.5.0" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "7b02b629252fe8ef6460461409564e2c21d0c8e77e0944f3d189ff06c4e932ad" 104 | 105 | [[package]] 106 | name = "cargo-run-bin" 107 | version = "1.7.4" 108 | dependencies = [ 109 | "anyhow", 110 | "assert_cmd", 111 | "cargo-husky", 112 | "cfg-if", 113 | "clap", 114 | "insta", 115 | "rustversion", 116 | "serde", 117 | "toml", 118 | "toml_edit", 119 | "version_check", 120 | "which", 121 | ] 122 | 123 | [[package]] 124 | name = "cargo-run-bin" 125 | version = "1.7.4" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "0770bfdecb25f182aa143e443765b8ecf6f0e6431d8c42ad997b17900c9b6c48" 128 | dependencies = [ 129 | "anyhow", 130 | "cfg-if", 131 | "clap", 132 | "rustversion", 133 | "serde", 134 | "toml", 135 | "toml_edit", 136 | "version_check", 137 | "which", 138 | ] 139 | 140 | [[package]] 141 | name = "cfg-if" 142 | version = "1.0.0" 143 | source = "registry+https://github.com/rust-lang/crates.io-index" 144 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 145 | 146 | [[package]] 147 | name = "clap" 148 | version = "4.3.19" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "5fd304a20bff958a57f04c4e96a2e7594cc4490a0e809cbd48bb6437edaa452d" 151 | dependencies = [ 152 | "clap_builder", 153 | ] 154 | 155 | [[package]] 156 | name = "clap_builder" 157 | version = "4.3.19" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1" 160 | dependencies = [ 161 | "anstream", 162 | "anstyle", 163 | "clap_lex", 164 | "strsim", 165 | ] 166 | 167 | [[package]] 168 | name = "clap_lex" 169 | version = "0.5.1" 170 | source = "registry+https://github.com/rust-lang/crates.io-index" 171 | checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" 172 | 173 | [[package]] 174 | name = "colorchoice" 175 | version = "1.0.0" 176 | source = "registry+https://github.com/rust-lang/crates.io-index" 177 | checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" 178 | 179 | [[package]] 180 | name = "console" 181 | version = "0.15.7" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" 184 | dependencies = [ 185 | "encode_unicode", 186 | "lazy_static", 187 | "libc", 188 | "windows-sys 0.45.0", 189 | ] 190 | 191 | [[package]] 192 | name = "difflib" 193 | version = "0.4.0" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" 196 | 197 | [[package]] 198 | name = "doc-comment" 199 | version = "0.3.3" 200 | source = "registry+https://github.com/rust-lang/crates.io-index" 201 | checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" 202 | 203 | [[package]] 204 | name = "either" 205 | version = "1.9.0" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" 208 | 209 | [[package]] 210 | name = "encode_unicode" 211 | version = "0.3.6" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 214 | 215 | [[package]] 216 | name = "equivalent" 217 | version = "1.0.1" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 220 | 221 | [[package]] 222 | name = "errno" 223 | version = "0.3.8" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" 226 | dependencies = [ 227 | "libc", 228 | "windows-sys 0.52.0", 229 | ] 230 | 231 | [[package]] 232 | name = "hashbrown" 233 | version = "0.14.0" 234 | source = "registry+https://github.com/rust-lang/crates.io-index" 235 | checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" 236 | 237 | [[package]] 238 | name = "hermit-abi" 239 | version = "0.3.3" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" 242 | 243 | [[package]] 244 | name = "indexmap" 245 | version = "2.0.0" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" 248 | dependencies = [ 249 | "equivalent", 250 | "hashbrown", 251 | ] 252 | 253 | [[package]] 254 | name = "insta" 255 | version = "1.31.0" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "a0770b0a3d4c70567f0d58331f3088b0e4c4f56c9b8d764efe654b4a5d46de3a" 258 | dependencies = [ 259 | "console", 260 | "lazy_static", 261 | "linked-hash-map", 262 | "serde", 263 | "similar", 264 | "yaml-rust", 265 | ] 266 | 267 | [[package]] 268 | name = "is-terminal" 269 | version = "0.4.9" 270 | source = "registry+https://github.com/rust-lang/crates.io-index" 271 | checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" 272 | dependencies = [ 273 | "hermit-abi", 274 | "rustix", 275 | "windows-sys 0.48.0", 276 | ] 277 | 278 | [[package]] 279 | name = "itertools" 280 | version = "0.11.0" 281 | source = "registry+https://github.com/rust-lang/crates.io-index" 282 | checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" 283 | dependencies = [ 284 | "either", 285 | ] 286 | 287 | [[package]] 288 | name = "lazy_static" 289 | version = "1.4.0" 290 | source = "registry+https://github.com/rust-lang/crates.io-index" 291 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 292 | 293 | [[package]] 294 | name = "libc" 295 | version = "0.2.151" 296 | source = "registry+https://github.com/rust-lang/crates.io-index" 297 | checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" 298 | 299 | [[package]] 300 | name = "linked-hash-map" 301 | version = "0.5.6" 302 | source = "registry+https://github.com/rust-lang/crates.io-index" 303 | checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" 304 | 305 | [[package]] 306 | name = "linux-raw-sys" 307 | version = "0.4.12" 308 | source = "registry+https://github.com/rust-lang/crates.io-index" 309 | checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" 310 | 311 | [[package]] 312 | name = "memchr" 313 | version = "2.6.3" 314 | source = "registry+https://github.com/rust-lang/crates.io-index" 315 | checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" 316 | 317 | [[package]] 318 | name = "once_cell" 319 | version = "1.18.0" 320 | source = "registry+https://github.com/rust-lang/crates.io-index" 321 | checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" 322 | 323 | [[package]] 324 | name = "predicates" 325 | version = "3.0.4" 326 | source = "registry+https://github.com/rust-lang/crates.io-index" 327 | checksum = "6dfc28575c2e3f19cb3c73b93af36460ae898d426eba6fc15b9bd2a5220758a0" 328 | dependencies = [ 329 | "anstyle", 330 | "difflib", 331 | "itertools", 332 | "predicates-core", 333 | ] 334 | 335 | [[package]] 336 | name = "predicates-core" 337 | version = "1.0.6" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" 340 | 341 | [[package]] 342 | name = "predicates-tree" 343 | version = "1.0.9" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" 346 | dependencies = [ 347 | "predicates-core", 348 | "termtree", 349 | ] 350 | 351 | [[package]] 352 | name = "proc-macro2" 353 | version = "1.0.67" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" 356 | dependencies = [ 357 | "unicode-ident", 358 | ] 359 | 360 | [[package]] 361 | name = "quote" 362 | version = "1.0.33" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" 365 | dependencies = [ 366 | "proc-macro2", 367 | ] 368 | 369 | [[package]] 370 | name = "regex-automata" 371 | version = "0.3.8" 372 | source = "registry+https://github.com/rust-lang/crates.io-index" 373 | checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" 374 | 375 | [[package]] 376 | name = "rustix" 377 | version = "0.38.28" 378 | source = "registry+https://github.com/rust-lang/crates.io-index" 379 | checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" 380 | dependencies = [ 381 | "bitflags", 382 | "errno", 383 | "libc", 384 | "linux-raw-sys", 385 | "windows-sys 0.52.0", 386 | ] 387 | 388 | [[package]] 389 | name = "rustversion" 390 | version = "1.0.14" 391 | source = "registry+https://github.com/rust-lang/crates.io-index" 392 | checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" 393 | 394 | [[package]] 395 | name = "serde" 396 | version = "1.0.149" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "256b9932320c590e707b94576e3cc1f7c9024d0ee6612dfbcf1cb106cbe8e055" 399 | dependencies = [ 400 | "serde_derive", 401 | ] 402 | 403 | [[package]] 404 | name = "serde_derive" 405 | version = "1.0.149" 406 | source = "registry+https://github.com/rust-lang/crates.io-index" 407 | checksum = "b4eae9b04cbffdfd550eb462ed33bc6a1b68c935127d008b27444d08380f94e4" 408 | dependencies = [ 409 | "proc-macro2", 410 | "quote", 411 | "syn", 412 | ] 413 | 414 | [[package]] 415 | name = "similar" 416 | version = "2.2.1" 417 | source = "registry+https://github.com/rust-lang/crates.io-index" 418 | checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf" 419 | 420 | [[package]] 421 | name = "strsim" 422 | version = "0.10.0" 423 | source = "registry+https://github.com/rust-lang/crates.io-index" 424 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 425 | 426 | [[package]] 427 | name = "syn" 428 | version = "1.0.109" 429 | source = "registry+https://github.com/rust-lang/crates.io-index" 430 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 431 | dependencies = [ 432 | "proc-macro2", 433 | "quote", 434 | "unicode-ident", 435 | ] 436 | 437 | [[package]] 438 | name = "termtree" 439 | version = "0.4.1" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" 442 | 443 | [[package]] 444 | name = "toml" 445 | version = "0.5.9" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" 448 | dependencies = [ 449 | "serde", 450 | ] 451 | 452 | [[package]] 453 | name = "toml_datetime" 454 | version = "0.6.3" 455 | source = "registry+https://github.com/rust-lang/crates.io-index" 456 | checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" 457 | 458 | [[package]] 459 | name = "toml_edit" 460 | version = "0.19.14" 461 | source = "registry+https://github.com/rust-lang/crates.io-index" 462 | checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" 463 | dependencies = [ 464 | "indexmap", 465 | "toml_datetime", 466 | "winnow", 467 | ] 468 | 469 | [[package]] 470 | name = "unicode-ident" 471 | version = "1.0.12" 472 | source = "registry+https://github.com/rust-lang/crates.io-index" 473 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 474 | 475 | [[package]] 476 | name = "utf8parse" 477 | version = "0.2.1" 478 | source = "registry+https://github.com/rust-lang/crates.io-index" 479 | checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" 480 | 481 | [[package]] 482 | name = "version_check" 483 | version = "0.9.3" 484 | source = "registry+https://github.com/rust-lang/crates.io-index" 485 | checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" 486 | 487 | [[package]] 488 | name = "wait-timeout" 489 | version = "0.2.0" 490 | source = "registry+https://github.com/rust-lang/crates.io-index" 491 | checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" 492 | dependencies = [ 493 | "libc", 494 | ] 495 | 496 | [[package]] 497 | name = "which" 498 | version = "4.4.0" 499 | source = "registry+https://github.com/rust-lang/crates.io-index" 500 | checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" 501 | dependencies = [ 502 | "either", 503 | "libc", 504 | "once_cell", 505 | ] 506 | 507 | [[package]] 508 | name = "windows-sys" 509 | version = "0.45.0" 510 | source = "registry+https://github.com/rust-lang/crates.io-index" 511 | checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" 512 | dependencies = [ 513 | "windows-targets 0.42.2", 514 | ] 515 | 516 | [[package]] 517 | name = "windows-sys" 518 | version = "0.48.0" 519 | source = "registry+https://github.com/rust-lang/crates.io-index" 520 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 521 | dependencies = [ 522 | "windows-targets 0.48.5", 523 | ] 524 | 525 | [[package]] 526 | name = "windows-sys" 527 | version = "0.52.0" 528 | source = "registry+https://github.com/rust-lang/crates.io-index" 529 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 530 | dependencies = [ 531 | "windows-targets 0.52.0", 532 | ] 533 | 534 | [[package]] 535 | name = "windows-targets" 536 | version = "0.42.2" 537 | source = "registry+https://github.com/rust-lang/crates.io-index" 538 | checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" 539 | dependencies = [ 540 | "windows_aarch64_gnullvm 0.42.2", 541 | "windows_aarch64_msvc 0.42.2", 542 | "windows_i686_gnu 0.42.2", 543 | "windows_i686_msvc 0.42.2", 544 | "windows_x86_64_gnu 0.42.2", 545 | "windows_x86_64_gnullvm 0.42.2", 546 | "windows_x86_64_msvc 0.42.2", 547 | ] 548 | 549 | [[package]] 550 | name = "windows-targets" 551 | version = "0.48.5" 552 | source = "registry+https://github.com/rust-lang/crates.io-index" 553 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 554 | dependencies = [ 555 | "windows_aarch64_gnullvm 0.48.5", 556 | "windows_aarch64_msvc 0.48.5", 557 | "windows_i686_gnu 0.48.5", 558 | "windows_i686_msvc 0.48.5", 559 | "windows_x86_64_gnu 0.48.5", 560 | "windows_x86_64_gnullvm 0.48.5", 561 | "windows_x86_64_msvc 0.48.5", 562 | ] 563 | 564 | [[package]] 565 | name = "windows-targets" 566 | version = "0.52.0" 567 | source = "registry+https://github.com/rust-lang/crates.io-index" 568 | checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" 569 | dependencies = [ 570 | "windows_aarch64_gnullvm 0.52.0", 571 | "windows_aarch64_msvc 0.52.0", 572 | "windows_i686_gnu 0.52.0", 573 | "windows_i686_msvc 0.52.0", 574 | "windows_x86_64_gnu 0.52.0", 575 | "windows_x86_64_gnullvm 0.52.0", 576 | "windows_x86_64_msvc 0.52.0", 577 | ] 578 | 579 | [[package]] 580 | name = "windows_aarch64_gnullvm" 581 | version = "0.42.2" 582 | source = "registry+https://github.com/rust-lang/crates.io-index" 583 | checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" 584 | 585 | [[package]] 586 | name = "windows_aarch64_gnullvm" 587 | version = "0.48.5" 588 | source = "registry+https://github.com/rust-lang/crates.io-index" 589 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 590 | 591 | [[package]] 592 | name = "windows_aarch64_gnullvm" 593 | version = "0.52.0" 594 | source = "registry+https://github.com/rust-lang/crates.io-index" 595 | checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" 596 | 597 | [[package]] 598 | name = "windows_aarch64_msvc" 599 | version = "0.42.2" 600 | source = "registry+https://github.com/rust-lang/crates.io-index" 601 | checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" 602 | 603 | [[package]] 604 | name = "windows_aarch64_msvc" 605 | version = "0.48.5" 606 | source = "registry+https://github.com/rust-lang/crates.io-index" 607 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 608 | 609 | [[package]] 610 | name = "windows_aarch64_msvc" 611 | version = "0.52.0" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" 614 | 615 | [[package]] 616 | name = "windows_i686_gnu" 617 | version = "0.42.2" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" 620 | 621 | [[package]] 622 | name = "windows_i686_gnu" 623 | version = "0.48.5" 624 | source = "registry+https://github.com/rust-lang/crates.io-index" 625 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 626 | 627 | [[package]] 628 | name = "windows_i686_gnu" 629 | version = "0.52.0" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" 632 | 633 | [[package]] 634 | name = "windows_i686_msvc" 635 | version = "0.42.2" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" 638 | 639 | [[package]] 640 | name = "windows_i686_msvc" 641 | version = "0.48.5" 642 | source = "registry+https://github.com/rust-lang/crates.io-index" 643 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 644 | 645 | [[package]] 646 | name = "windows_i686_msvc" 647 | version = "0.52.0" 648 | source = "registry+https://github.com/rust-lang/crates.io-index" 649 | checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" 650 | 651 | [[package]] 652 | name = "windows_x86_64_gnu" 653 | version = "0.42.2" 654 | source = "registry+https://github.com/rust-lang/crates.io-index" 655 | checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" 656 | 657 | [[package]] 658 | name = "windows_x86_64_gnu" 659 | version = "0.48.5" 660 | source = "registry+https://github.com/rust-lang/crates.io-index" 661 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 662 | 663 | [[package]] 664 | name = "windows_x86_64_gnu" 665 | version = "0.52.0" 666 | source = "registry+https://github.com/rust-lang/crates.io-index" 667 | checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" 668 | 669 | [[package]] 670 | name = "windows_x86_64_gnullvm" 671 | version = "0.42.2" 672 | source = "registry+https://github.com/rust-lang/crates.io-index" 673 | checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" 674 | 675 | [[package]] 676 | name = "windows_x86_64_gnullvm" 677 | version = "0.48.5" 678 | source = "registry+https://github.com/rust-lang/crates.io-index" 679 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 680 | 681 | [[package]] 682 | name = "windows_x86_64_gnullvm" 683 | version = "0.52.0" 684 | source = "registry+https://github.com/rust-lang/crates.io-index" 685 | checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" 686 | 687 | [[package]] 688 | name = "windows_x86_64_msvc" 689 | version = "0.42.2" 690 | source = "registry+https://github.com/rust-lang/crates.io-index" 691 | checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" 692 | 693 | [[package]] 694 | name = "windows_x86_64_msvc" 695 | version = "0.48.5" 696 | source = "registry+https://github.com/rust-lang/crates.io-index" 697 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 698 | 699 | [[package]] 700 | name = "windows_x86_64_msvc" 701 | version = "0.52.0" 702 | source = "registry+https://github.com/rust-lang/crates.io-index" 703 | checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" 704 | 705 | [[package]] 706 | name = "winnow" 707 | version = "0.5.15" 708 | source = "registry+https://github.com/rust-lang/crates.io-index" 709 | checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" 710 | dependencies = [ 711 | "memchr", 712 | ] 713 | 714 | [[package]] 715 | name = "yaml-rust" 716 | version = "0.4.5" 717 | source = "registry+https://github.com/rust-lang/crates.io-index" 718 | checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" 719 | dependencies = [ 720 | "linked-hash-map", 721 | ] 722 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cargo-run-bin" 3 | version = "1.7.4" 4 | authors = ["Dustin Blackman"] 5 | categories = ["command-line-utilities", "development-tools::cargo-plugins"] 6 | edition = "2021" 7 | homepage = "https://github.com/dustinblackman/cargo-run-bin" 8 | keywords = ["dev-experiance", "developer-experiance", "bin", "cache", "cli"] 9 | license = "MIT" 10 | readme = "README.md" 11 | repository = "https://github.com/dustinblackman/cargo-run-bin" 12 | rust-version = "1.70.0" 13 | description = "Build, cache, and run binaries scoped in Cargo.toml rather than installing globally. This acts similarly to npm run and gomodrun, and allows your teams to always be running the same tooling versions." 14 | exclude = [ 15 | ".cargo-husky", 16 | "tests/", 17 | "cliff.toml", 18 | "deny.toml", 19 | "rust-toolchain.toml" 20 | ] 21 | 22 | [[bin]] 23 | name = "cargo-bin" 24 | path = "src/main.rs" 25 | required-features = ["cli"] 26 | 27 | [features] 28 | default = ["cli"] 29 | cli = ["dep:clap"] 30 | 31 | [dependencies] 32 | anyhow = "1.0.40" 33 | cfg-if = "1.0.0" 34 | clap = { version = "4.3.19", optional = true } 35 | rustversion = "1.0.14" 36 | serde = { version = "1.0.149", features = ["derive"] } 37 | toml = "0.5.9" 38 | toml_edit = "0.19.14" 39 | version_check = "0.9.3" 40 | which = "4.4.0" 41 | 42 | [dev-dependencies] 43 | assert_cmd = "2.0.12" 44 | cargo-husky = { version = "1.5.0", default-features = false, features = ["user-hooks"] } 45 | insta = { version = "1.31.0", features = ["yaml"] } 46 | 47 | [package.metadata.bin] 48 | cargo-cmd = { version = "0.3.1", locked = true } 49 | cargo-deny = { version = "0.13.5", locked = true } 50 | cargo-gha = { version = "1.0.2", locked = true } 51 | cargo-insta = { version = "1.31.0", locked = true } 52 | cargo-llvm-cov = { version = "0.5.25", locked = true } 53 | cargo-nextest = { version = "0.9.57", locked = true } 54 | cargo-watch = { version = "8.4.0", locked = true } 55 | committed = { version = "1.0.20", locked = true } 56 | git-cliff = { version = "1.3.1", locked = true } 57 | # Just added for testing 58 | dustinblackman-hello-world = { version = "0.2.1", git = "https://github.com/dustinblackman/rust-hello-world", bins = ["hello-world-first", "hello-world-second"] } 59 | 60 | [package.metadata.docs.rs] 61 | all-features = false 62 | features = [] 63 | 64 | [package.metadata.gha] 65 | targets = ["aarch64-apple-darwin"] 66 | 67 | [[package.metadata.gha.assets]] 68 | owner_repo = "cli/cli" 69 | tag = "v2.40.1" 70 | binaries = ["gh"] 71 | target_archives = { aarch64-apple-darwin = "gh_{NOVTAG}_macOS_arm64.zip" } 72 | 73 | [profile.dev.package.insta] 74 | opt-level = 3 75 | 76 | [profile.dev.package.similar] 77 | opt-level = 3 78 | 79 | [profile.release] 80 | opt-level = 3 81 | lto = "thin" 82 | strip = "symbols" 83 | 84 | [profile.dist] 85 | inherits = "release" 86 | 87 | [package.metadata.commands] 88 | lint = '''set -e 89 | cargo cmd setup-nightly 90 | cargo +runbin-nightly fmt -- --check 91 | cargo clippy 92 | cargo deny check licenses -s 93 | ''' 94 | lint-fix = '''set -e 95 | cargo cmd setup-nightly 96 | cargo clippy --fix --allow-dirty 97 | cargo fix --allow-dirty 98 | cargo +runbin-nightly fmt 99 | ''' 100 | 101 | get-nightly-name = 'echo runbin-nightly' 102 | setup-nightly = ''' 103 | export NIGHTLY=nightly-2023-06-16 104 | rustup toolchain list -v | grep -q "$NIGHTLY" || rustup toolchain install "$NIGHTLY" --force --component llvm-tools-preview rustfmt 105 | rustup toolchain link runbin-nightly "$(rustup toolchain list -v | grep $NIGHTLY | grep '^nightly-' | awk '{print $2}')" 106 | ''' 107 | 108 | release = '''set -e 109 | export RB_VERSION=$(cat Cargo.toml | grep version | head -n1 | awk -F '"' '{print $2}') 110 | 111 | cargo check 112 | cargo bin git-cliff -o CHANGELOG.md --tag "v$RB_VERSION" 113 | 114 | git add . 115 | git commit -m "feat: Release v$RB_VERSION" 116 | git tag -a "v$RB_VERSION" -m "v$RB_VERSION" 117 | 118 | git push 119 | git push --tags 120 | 121 | cargo publish 122 | cargo gha gh release create "v$RB_VERSION" --generate-notes 123 | cargo bin git-cliff --latest --strip header | cargo gha gh release edit "v$RB_VERSION" --notes-file - 124 | ''' 125 | 126 | test-coverage = '''set -e 127 | rm -rf .tmp 128 | cargo build 129 | cargo llvm-cov nextest -j 1 --ignore-filename-regex='_test.rs' 130 | ''' 131 | test-coverage-html = '''set -e 132 | rm -rf .tmp 133 | cargo build 134 | cargo llvm-cov nextest -j 1 --open --ignore-filename-regex='_test.rs' 135 | ''' 136 | test-coverage-lcov = '''set -e 137 | rm -rf .tmp 138 | cargo build 139 | rm -f lcov.info 140 | cargo llvm-cov nextest -j 1 --lcov --output-path lcov.info --ignore-filename-regex='_test.rs' 141 | ''' 142 | test = '''set -e 143 | rm -rf .tmp 144 | cargo build 145 | cargo nextest run -j 1 146 | ''' 147 | test-watch = '''set -e 148 | cargo watch -i .cargo -x 'cmd test' 149 | ''' 150 | 151 | [workspace] 152 | members = ["tools/cargo-bin"] 153 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 Dustin Blackman 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 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

cargo-run-bin

2 | 3 | ![cargo-run-bin](.github/banner.png) 4 | 5 | [![Build status](https://github.com/dustinblackman/cargo-run-bin/workflows/ci/badge.svg)](https://github.com/dustinblackman/cargo-run-bin/actions) 6 | [![Coverage Status](https://coveralls.io/repos/github/dustinblackman/cargo-run-bin/badge.svg?branch=master)](https://coveralls.io/github/dustinblackman/cargo-run-bin?branch=master) 7 | [![Crates.io](https://img.shields.io/crates/v/cargo-run-bin.svg)](https://crates.io/crates/cargo-run-bin) 8 | 9 | > Build, cache, and run CLI tools scoped in `Cargo.toml` rather than installing globally. Stop the version drifts across your team, keep it all in sync within your project! 10 | 11 | - [Overview](#overview) 12 | - [Install](#install) 13 | - [Usage](#usage) 14 | - [cargo bin CRATE](#cargo-bin-crate) 15 | - [cargo bin --sync-aliases](#cargo-bin---sync-aliases) 16 | - [cargo bin --install](#cargo-bin---install) 17 | - [Library](#library) 18 | - [License](#license) 19 | 20 | ## Overview 21 | 22 | Installing tooling globally when working in teams or on CI is a silly problem to manage. `cargo-run-bin` builds, caches, and executes binaries from their locked down versions in `Cargo.toml`. This acts similarly to [`npm run`](https://docs.npmjs.com/cli/v7/commands/npm-run-script) and [`gomodrun`](https://github.com/dustinblackman/gomodrun), and allows your teams to always be running the same tooling versions. 23 | 24 | For command lines that extend cargo such as `cargo-nextest`, run-bin will create and manage cargo aliases to allow using cargo extensions without any changes to your command line scripts! `cargo-run-bin` gets out of your way, and you'll forget you're even using it! 25 | 26 | ## Install 27 | 28 | Minimum Rust Version: 1.70.0 29 | 30 | There are a few different ways you can install `cargo-run-bin`. I'd recommend giving each a read, and picking the best that suits you! 31 | 32 | ### Global Install 33 | 34 | Run the following to install `cargo-run-bin`, and ignore the cache directory in your project. 35 | 36 | ```sh 37 | cargo install cargo-run-bin 38 | cd my/rust/project 39 | echo ".bin/" >> .gitignore 40 | ``` 41 | 42 | ### Using wrapper 43 | 44 | Installing with a minimal wrapper and an alias in your project. This gives you the best onboarding experiance in to your project for you and your team as it does not require any global installs! Git pull, and you're ready to consume all your CLI tools! 45 | 46 | These instructions assume you'd like to place the wrapper in `tools/cargo-bin` within your project. Change it to fit your needs! 47 | 48 | ```sh 49 | cd my/rust/project 50 | echo ".bin/" >> .gitignore 51 | cargo new --vcs none --bin tools/cargo-bin 52 | curl --output tools/cargo-bin/src/main.rs https://raw.githubusercontent.com/dustinblackman/cargo-run-bin/refs/tags/v1.7.4/src/main.rs 53 | cd tools/cargo-bin 54 | cargo add --features cli cargo-run-bin 55 | ``` 56 | 57 | Ensure the tool binary is added to the workspace within `Cargo.toml`. 58 | 59 | ```toml 60 | [workspace] 61 | members = ["tools/cargo-bin"] 62 | ``` 63 | 64 | Now add an alias in `.cargo/config.toml`. If the file doesn't exist yet, then this will be the first entry! 65 | 66 | ```toml 67 | [alias] 68 | bin = ["run", "--package", "cargo-bin", "--"] 69 | ``` 70 | 71 | Done! Now it can be used as if installed globally. 72 | 73 | ```sh 74 | cargo bin --version 75 | ``` 76 | 77 | ### As a library 78 | 79 | You can also use it as a library within your existing logic. 80 | 81 | ```toml 82 | [dependencies] 83 | cargo-run-bin = { version = "1.7.4", default-features = false } 84 | ``` 85 | 86 | ### Distro packages 87 | 88 |
89 | Packaging status 90 | 91 | [![Packaging status](https://repology.org/badge/vertical-allrepos/cargo-run-bin.svg)](https://repology.org/project/cargo-run-bin/versions) 92 | 93 |
94 | 95 | If your distribution has packaged `cargo-run-bin`, you can use that package for the installation. 96 | 97 | ### Arch Linux 98 | 99 | You can use [pacman](https://wiki.archlinux.org/title/Pacman) to install from the [extra repository](https://archlinux.org/packages/extra/x86_64/cargo-run-bin/): 100 | 101 | ```sh 102 | pacman -S cargo-run-bin 103 | ``` 104 | 105 | ### Alpine Linux 106 | 107 | `cargo-run-bin` is available for [Alpine Edge](https://pkgs.alpinelinux.org/packages?name=cargo-run-bin&branch=edge). It can be installed via [apk](https://wiki.alpinelinux.org/wiki/Alpine_Package_Keeper) after enabling the [testing repository](https://wiki.alpinelinux.org/wiki/Repositories). 108 | 109 | ```sh 110 | apk add cargo-run-bin 111 | ``` 112 | 113 | ## Usage 114 | 115 | `cargo-run-bin` keeps track of the binaries and their versions from within `Cargo.toml` under the `[package.metadata.bin]`. 116 | table. A quick example taken from this repo: 117 | 118 | ```toml 119 | [package.metadata.bin] 120 | cargo-binstall = { version = "1.1.2" } 121 | cargo-nextest = { version = "0.9.57", locked = true } 122 | dprint = { version = "0.30.3" } 123 | cargo-mobile2 = { version = "0.5.2", bins = ["cargo-android", "cargo-mobile"], locked = true } 124 | ``` 125 | 126 | Or if you're setting up in a workspace: 127 | 128 | ```toml 129 | [workspace.metadata.bin] 130 | cargo-binstall = { version = "1.1.2" } 131 | cargo-nextest = { version = "0.9.57", locked = true } 132 | ``` 133 | 134 | | Parameter | Type | Required | Description | 135 | | ---------------- | ------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 136 | | version | `String` | true | Specifies the version of the crate. It is not treated as a caret requirement automatically. Corresponds to the `cargo install` [`--version`](https://doc.rust-lang.org/cargo/commands/cargo-install.html#install-options) argument. | 137 | | bins | `Vec` | false | An array of binaries that the crate contains that you wish to build. These can be found in a crates `Cargo.toml` file. See [`cargo-mobile2`](https://github.com/tauri-apps/cargo-mobile2/blob/a5f3783870f48886e3266e43f92a6768fb1eb3d4/Cargo.toml#L18-L28) as an example. | 138 | | locked | `Boolean` | false | A parameter when set to `true` runs `cargo install` with the [`--locked`](https://doc.rust-lang.org/cargo/commands/cargo-install.html#dealing-with-the-lockfile) parameter. | 139 | | features | `Vec` | false | An array of crate features to enable. | 140 | | default-features | `Boolean` | false | When set to `false`, disables all default features. | 141 | | git | String | false | A git URL to install from rather than from crates.io. This will also be used by Binstall to look up Cargo manifist if Binstall is available. | 142 | | branch | String | false | A git branch to install from when `git` is set. This takes priority over `tag` and `rev` | 143 | | tag | String | false | A git tag to install from when `git` is set. `branch` will take priority if set, and takes priority over `rev`. | 144 | | rev | String | false | A git revision to install from when `git` is set. `branch` and `tag` will take priority if set. | 145 | | path | String | false | The path to a local crate to install. | 146 | 147 | If you're a fan of prebuilt binaries and fast downloads, run-bin will use [`cargo-binstall`](https://github.com/cargo-bins/cargo-binstall) if it's installed globally, or configured within `[package.metadata.bin]`, rather than building tools from source. 148 | 149 | ### `cargo bin CRATE` 150 | 151 | Taking an example of `dprint`, running `cargo bin dprint --help` with install/build and cache the dprint binary with the 152 | specified version in `Cargo.toml`. All future executions will run instantly without an install step, and dprint can be used 153 | as you wish! 154 | 155 | ### `cargo bin --sync-aliases` 156 | 157 | With the power of [cargo aliases](https://doc.rust-lang.org/cargo/reference/config.html#alias), `cargo bin --sync-aliases` 158 | will create aliases for any `cargo-*` crate, allowing you to execute commands such `cargo nextest run` that will use 159 | `cargo bin` under the hood. Check out some of the example from [this repo](.cargo/config.toml). 160 | 161 | ### `cargo bin --install` 162 | 163 | When pulling down a new repo, or adding a step to CI, `cargo bin --install` will install or build all binaries that have not been 164 | cached which are configured in `Cargo.toml`. 165 | 166 | ### Library 167 | 168 | `run-bin` can also be used as a library and paired nicely with your `build.rs` or any other scripts. The following 169 | example demos having `dprint` configured within `[package.metadata.bin]`, and executing `dprint --help`. 170 | 171 | ```toml 172 | [package.metadata.bin] 173 | dprint = { version = "0.40.2" } 174 | ``` 175 | 176 | ```rust 177 | use anyhow::Result; 178 | use cargo_run_bin::{binary, metadata}; 179 | 180 | fn main() -> Result<()> { 181 | let binary_package = metadata::get_binary_packages()? 182 | .iter() 183 | .find(|e| e.package == "dprint") 184 | .unwrap() 185 | .to_owned(); 186 | let bin_path = binary::install(binary_package)?; 187 | binary::run(bin_path, vec!["--help".to_string()])?; 188 | 189 | return Ok(()); 190 | } 191 | ``` 192 | 193 | Using `binary::run` is optional. You can recreate it and make changes to your liking using `std::process`, with shims included! 194 | 195 | ```rust 196 | use std::process; 197 | 198 | use anyhow::Result; 199 | use cargo_run_bin::{binary, metadata, shims}; 200 | 201 | fn main() -> Result<()> { 202 | let binary_package = metadata::get_binary_packages()? 203 | .iter() 204 | .find(|e| e.package == "dprint") 205 | .unwrap() 206 | .to_owned(); 207 | let bin_path = binary::install(binary_package)?; 208 | 209 | let mut shell_paths = shims::get_shim_paths()?; 210 | shell_paths.push(env::var("PATH").unwrap_or("".to_string())); 211 | 212 | process::Command::new(bin_path) 213 | .args(["--help"]) 214 | .env("PATH", shell_paths.join(":")) 215 | .spawn(); 216 | 217 | return Ok(()); 218 | } 219 | ``` 220 | 221 | ## [License](./LICENSE) 222 | 223 | MIT. 224 | -------------------------------------------------------------------------------- /cliff.toml: -------------------------------------------------------------------------------- 1 | # git-cliff ~ configuration file 2 | # https://git-cliff.org/docs/configuration 3 | # 4 | # Lines starting with "#" are comments. 5 | # Configuration options are organized into tables and keys. 6 | # See documentation for more information on available options. 7 | 8 | [changelog] 9 | # changelog header 10 | header = """ 11 | # Changelog\n 12 | All notable changes to this project will be documented in this file.\n 13 | """ 14 | # template for the changelog body 15 | # https://keats.github.io/tera/docs/#introduction 16 | body = """ 17 | {% if version %}\ 18 | ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} 19 | {% else %}\ 20 | ## [unreleased] 21 | {% endif %}\ 22 | 23 | [{{ previous.version }}..{{ version }}](/compare/{{ previous.version }}..{{ version }}) 24 | 25 | {% macro commit(commit) -%} 26 | - {% if commit.scope %}*({{ commit.scope }})* {% endif %}{% if commit.breaking %}[**breaking**] {% endif %}\ 27 | {{ commit.message | upper_first }} - ([{{ commit.id | truncate(length=7, end="") }}](/commit/{{ commit.id }}))\ 28 | {% endmacro -%} 29 | 30 | {% for group, commits in commits | group_by(attribute="group") %} 31 | ### {{ group | striptags | trim | upper_first }} 32 | {% for commit in commits 33 | | filter(attribute="scope") 34 | | sort(attribute="scope") %} 35 | {{ self::commit(commit=commit) }} 36 | {%- endfor -%} 37 | {% raw %}\n{% endraw %}\ 38 | {%- for commit in commits %} 39 | {%- if not commit.scope -%} 40 | {{ self::commit(commit=commit) }} 41 | {% endif -%} 42 | {% endfor -%} 43 | {% endfor %}\n 44 | """ 45 | # remove the leading and trailing whitespace from the template 46 | trim = true 47 | # changelog footer 48 | footer = """ 49 | 50 | """ 51 | # postprocessors 52 | postprocessors = [ 53 | { pattern = '', replace = "https://github.com/dustinblackman/cargo-run-bin" }, # replace repository URL 54 | ] 55 | 56 | [git] 57 | # parse the commits based on https://www.conventionalcommits.org 58 | conventional_commits = true 59 | # filter out the commits that are not conventional 60 | filter_unconventional = true 61 | # process each line of a commit as an individual commit 62 | split_commits = false 63 | # regex for preprocessing the commit messages 64 | commit_preprocessors = [ 65 | { pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](/issues/${2}))" }, 66 | ] 67 | # regex for parsing and grouping commits 68 | commit_parsers = [ 69 | { message = "^feat", group = "⛰️ Features" }, 70 | { message = "^fix", group = "🐛 Bug Fixes" }, 71 | { message = "^doc", group = "📚 Documentation" }, 72 | { message = "^perf", group = "⚡ Performance" }, 73 | { message = "^refactor", group = "🚜 Refactor" }, 74 | { message = "^style", group = "🎨 Styling" }, 75 | { message = "^test", group = "🧪 Testing" }, 76 | { message = "^chore\\(release\\): prepare for", skip = true }, 77 | { message = "^chore\\(deps\\)", skip = true }, 78 | { message = "^chore\\(pr\\)", skip = true }, 79 | { message = "^chore\\(pull\\)", skip = true }, 80 | { message = "^chore|ci", group = "⚙️ Miscellaneous Tasks" }, 81 | { body = ".*security", group = "🛡️ Security" }, 82 | { message = "^revert", group = "◀️ Revert" }, 83 | ] 84 | # protect breaking changes from being skipped due to matching a skipping commit_parser 85 | protect_breaking_commits = false 86 | # filter out the commits that are not matched by commit parsers 87 | filter_commits = false 88 | # glob pattern for matching git tags 89 | tag_pattern = "v[0-9]*" 90 | # regex for skipping tags 91 | skip_tags = "beta|alpha" 92 | # regex for ignoring tags 93 | ignore_tags = "rc" 94 | # sort the tags topologically 95 | topo_order = false 96 | # sort the commits inside sections by oldest/newest order 97 | sort_commits = "newest" 98 | -------------------------------------------------------------------------------- /committed.toml: -------------------------------------------------------------------------------- 1 | style = "conventional" 2 | ignore_author_re = "(dependabot)" 3 | merge_commit = false 4 | -------------------------------------------------------------------------------- /deny.toml: -------------------------------------------------------------------------------- 1 | [advisories] 2 | git-fetch-with-cli = true 3 | 4 | [licenses] 5 | unlicensed = "deny" 6 | copyleft = "deny" 7 | allow = [ 8 | "MIT", 9 | "Apache-2.0", 10 | ] 11 | exceptions = [ 12 | { allow = ["Unicode-DFS-2016"], name = "unicode-ident" }, 13 | ] 14 | 15 | [[licenses.clarify]] 16 | name = "ring" 17 | expression = "MIT AND ISC AND OpenSSL" 18 | license-files = [ 19 | { path = "LICENSE", hash = 0xbd0eed23 }, 20 | ] 21 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "1.75.0" 3 | components = ["rustfmt", "clippy", "llvm-tools-preview"] 4 | -------------------------------------------------------------------------------- /src/binary.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::fs; 3 | use std::io; 4 | use std::path; 5 | use std::process; 6 | 7 | use anyhow::anyhow; 8 | use anyhow::bail; 9 | use anyhow::Result; 10 | use cfg_if::cfg_if; 11 | use version_check as rustc; 12 | use which::which; 13 | 14 | use crate::cargo_config; 15 | use crate::metadata; 16 | use crate::shims; 17 | 18 | #[rustversion::since(1.74)] 19 | fn stderr_to_stdio() -> io::Result { 20 | return Ok(io::stderr().into()); 21 | } 22 | 23 | #[rustversion::before(1.74)] 24 | #[cfg(target_family = "unix")] 25 | fn stderr_to_stdio() -> io::Result { 26 | use std::os::fd::AsFd; 27 | 28 | return Ok(io::stderr().as_fd().try_clone_to_owned()?.into()); 29 | } 30 | 31 | #[rustversion::before(1.74)] 32 | #[cfg(target_family = "windows")] 33 | fn stderr_to_stdio() -> io::Result { 34 | use std::os::windows::io::AsHandle; 35 | 36 | return Ok(io::stderr().as_handle().try_clone_to_owned()?.into()); 37 | } 38 | 39 | /// INTERNAL: Install binary with cargo install. 40 | pub fn cargo_install( 41 | binary_package: metadata::BinaryPackage, 42 | cache_path: path::PathBuf, 43 | ) -> Result<()> { 44 | let mut cmd_prefix = process::Command::new("cargo"); 45 | 46 | cmd_prefix 47 | .stdout(stderr_to_stdio()?) 48 | .stderr(process::Stdio::inherit()) 49 | .arg("install") 50 | .arg("--root") 51 | .arg(&cache_path) 52 | .arg("--version") 53 | .arg(binary_package.version); 54 | 55 | if let Some(git) = &binary_package.git { 56 | cmd_prefix.arg("--git").arg(git); 57 | if let Some(branch) = &binary_package.branch { 58 | cmd_prefix.arg("--branch").arg(branch); 59 | } else if let Some(tag) = &binary_package.tag { 60 | cmd_prefix.arg("--tag").arg(tag); 61 | } else if let Some(rev) = &binary_package.rev { 62 | cmd_prefix.arg("--rev").arg(rev); 63 | } 64 | } else if let Some(path) = &binary_package.path { 65 | cmd_prefix.arg("--path").arg(path); 66 | } 67 | 68 | if let Some(bin_target) = &binary_package.bin_target { 69 | cmd_prefix.arg("--bin").arg(bin_target); 70 | } 71 | 72 | if let Some(locked) = &binary_package.locked { 73 | if *locked { 74 | cmd_prefix.arg("--locked"); 75 | } 76 | } 77 | 78 | if let Some(features) = &binary_package.features { 79 | cmd_prefix.arg("--features"); 80 | cmd_prefix.arg(features.join(",")); 81 | } 82 | 83 | if let Some(default_features) = &binary_package.default_features { 84 | if !*default_features { 85 | cmd_prefix.arg("--no-default-features"); 86 | } 87 | } 88 | 89 | cmd_prefix.arg(binary_package.package).output()?; 90 | 91 | return Ok(()); 92 | } 93 | 94 | /// INTERNAL: Install binary with binstall 95 | pub fn binstall(binary_package: metadata::BinaryPackage, cache_path: path::PathBuf) -> Result<()> { 96 | let mut cmd_prefix = process::Command::new("cargo"); 97 | 98 | cmd_prefix 99 | .stdout(stderr_to_stdio()?) 100 | .stderr(process::Stdio::inherit()) 101 | .arg("binstall") 102 | .arg("--no-confirm") 103 | .arg("--no-symlinks") 104 | .arg("--root") 105 | .arg(&cache_path) 106 | .arg("--install-path") 107 | .arg(cache_path.join("bin")); 108 | 109 | if let Some(git) = &binary_package.git { 110 | cmd_prefix.arg("--git").arg(git); 111 | } 112 | 113 | if let Some(locked) = &binary_package.locked { 114 | if *locked { 115 | cmd_prefix.arg("--locked"); 116 | } 117 | } 118 | 119 | cmd_prefix 120 | .arg(format!( 121 | "{package}@{version}", 122 | package = binary_package.package, 123 | version = binary_package.version, 124 | )) 125 | .output()?; 126 | 127 | return Ok(()); 128 | } 129 | 130 | /// Install the provided binary package if it has not been built already. 131 | pub fn install(binary_package: metadata::BinaryPackage) -> Result { 132 | let mut rust_version = "unknown".to_string(); 133 | if let Some(res) = rustc::triple() { 134 | if res.1.is_nightly() { 135 | rust_version = "nightly".to_string(); 136 | } else { 137 | rust_version = res.0.to_string(); 138 | } 139 | } 140 | 141 | let mut bin_name = binary_package.package.to_owned(); 142 | if let Some(bin_target) = &binary_package.bin_target { 143 | bin_name = bin_target.to_string(); 144 | } 145 | 146 | let cache_path = metadata::get_project_root()? 147 | .join(".bin") 148 | .join(format!("rust-{rust_version}")) 149 | .join(binary_package.package.clone()) 150 | .join(binary_package.version.clone()); 151 | 152 | let mut cache_bin_path = cache_path.join("bin").join(bin_name); 153 | cache_bin_path = cache_bin_path.clone(); 154 | 155 | cfg_if! { 156 | if #[cfg(not(target_family = "unix"))] { 157 | cache_bin_path.set_extension("exe"); 158 | } 159 | } 160 | 161 | if !path::Path::new(&cache_bin_path).exists() { 162 | fs::create_dir_all(&cache_path)?; 163 | if binary_package.bin_target.is_none() 164 | && binary_package.features.is_none() 165 | && binary_package.default_features.is_none() 166 | && binary_package.branch.is_none() 167 | && binary_package.tag.is_none() 168 | && binary_package.rev.is_none() 169 | && binary_package.package != "cargo-binstall" 170 | && (cargo_config::binstall_alias_exists()? || which("cargo-binstall").is_ok()) 171 | { 172 | binstall(binary_package, cache_path)?; 173 | } else { 174 | cargo_install(binary_package, cache_path)?; 175 | } 176 | } 177 | 178 | return Ok(cache_bin_path.to_str().unwrap().to_string()); 179 | } 180 | 181 | /// Executes provided binary and arguments, adding shims to PATH so any 182 | /// other run-bin configured binaries are available. 183 | pub fn run(bin_path: String, args: Vec) -> Result<()> { 184 | // Silly hack to make cargo commands parse arguments correctly. 185 | let mut final_args = args.clone(); 186 | let bin_name = path::Path::new(&bin_path) 187 | .file_name() 188 | .unwrap() 189 | .to_str() 190 | .unwrap(); 191 | if bin_name.starts_with("cargo-") { 192 | final_args = vec![bin_name 193 | .to_string() 194 | .replace("cargo-", "") 195 | .replace(".exe", "")]; 196 | final_args.append(&mut args.clone()); 197 | } 198 | 199 | let mut shell_paths = shims::get_shim_paths()?; 200 | shell_paths.push(env::var("PATH").unwrap_or("".to_string())); 201 | 202 | let spawn = process::Command::new(bin_path.clone()) 203 | .stdout(process::Stdio::inherit()) 204 | .stderr(process::Stdio::inherit()) 205 | .stdin(process::Stdio::inherit()) 206 | .args(&final_args) 207 | .env("PATH", shell_paths.join(":")) 208 | .spawn(); 209 | 210 | if let Ok(mut spawn) = spawn { 211 | let status = spawn 212 | .wait()? 213 | .code() 214 | .ok_or_else(|| return anyhow!("Failed to get spawn exit code"))?; 215 | 216 | process::exit(status); 217 | } 218 | 219 | bail!(format!("Process failed to start: {bin_path}")); 220 | } 221 | -------------------------------------------------------------------------------- /src/cargo_config.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | 3 | use anyhow::bail; 4 | use anyhow::Context; 5 | use anyhow::Result; 6 | use toml_edit::table; 7 | use toml_edit::value; 8 | use toml_edit::Array; 9 | use toml_edit::Document; 10 | use toml_edit::Value; 11 | 12 | use crate::metadata; 13 | 14 | /// Updates alias' in .cargo/config.toml with all configured cargo extensions. 15 | pub fn sync_aliases() -> Result<()> { 16 | let mut toml_str = "".to_string(); 17 | let config_path = metadata::get_project_root()?.join(".cargo/config.toml"); 18 | if config_path.exists() { 19 | toml_str = fs::read_to_string(&config_path)?.parse()?; 20 | } 21 | 22 | let binary_packages = metadata::get_binary_packages()?; 23 | let new_config = update_aliases_toml(&toml_str, binary_packages) 24 | .context("failed to update aliases in .cargo/config.toml")?; 25 | 26 | if !config_path.parent().unwrap().exists() { 27 | fs::create_dir(config_path.parent().unwrap())?; 28 | } 29 | 30 | fs::write(config_path, new_config)?; 31 | 32 | return Ok(()); 33 | } 34 | 35 | fn update_aliases_toml( 36 | toml_str: &str, 37 | binary_packages: Vec, 38 | ) -> Result { 39 | let mut doc = toml_str.parse::()?; 40 | if doc.get("alias").is_none() { 41 | doc["alias"] = table(); 42 | } 43 | 44 | // If the TOML structure is not as and we panic because of that, that makes for 45 | // poor user experience, so try to report errors for everything that could 46 | // go wrong. 47 | let aliases = doc["alias"] 48 | .as_table_mut() 49 | .context("alias key should be a table")?; 50 | let mut remove_keys: Vec = vec![]; 51 | for (key, value) in aliases.get_values() { 52 | let [name] = key.as_slice() else { 53 | bail!("unexpected nested table: {key:?}") 54 | }; 55 | // The value can be either a single string (implicitly split on spaces) or an 56 | // array of strings. We always create an array, but a user might use a 57 | // single string for other aliases, so we have to at least not crash on 58 | // such values. 59 | if let Value::Array(parts) = value { 60 | let first_part = parts 61 | .get(0) 62 | .with_context(|| format!("alias {name:?} is empty array"))? 63 | .as_str() 64 | .with_context(|| format!("alias {name:?} should be array of strings"))?; 65 | if first_part == "bin" { 66 | remove_keys.push(name.get().to_owned()); 67 | } 68 | } 69 | } 70 | for key in remove_keys { 71 | aliases.remove(&key); 72 | } 73 | 74 | for binary_package in binary_packages { 75 | let mut bin = binary_package.package; 76 | if let Some(bin_target) = binary_package.bin_target { 77 | bin = bin_target; 78 | } 79 | 80 | if !bin.starts_with("cargo-") { 81 | continue; 82 | } 83 | 84 | let mut arr = Array::new(); 85 | arr.push("bin"); 86 | arr.push(bin.clone()); 87 | doc["alias"][bin.replace("cargo-", "")] = value(arr); 88 | } 89 | return Ok(doc.to_string()); 90 | } 91 | 92 | /// Verifies in cargo-binstall is available in alias'. 93 | pub fn binstall_alias_exists() -> Result { 94 | let config_path = metadata::get_project_root()?.join(".cargo/config.toml"); 95 | if !config_path.exists() { 96 | return Ok(false); 97 | } 98 | 99 | let toml_str: String = fs::read_to_string(&config_path)?.parse()?; 100 | let mut doc = toml_str.parse::()?; 101 | if doc.get("alias").is_none() { 102 | return Ok(false); 103 | } 104 | 105 | let aliases = doc["alias"].as_table_mut().unwrap(); 106 | return Ok(aliases.contains_key("binstall")); 107 | } 108 | 109 | #[cfg(test)] 110 | mod tests { 111 | use super::update_aliases_toml; 112 | 113 | #[test] 114 | fn skips_bare_string_alias() { 115 | let original_toml = r#" 116 | [alias] 117 | xtask = "run --package xtask --" 118 | "#; 119 | let new_toml = update_aliases_toml(original_toml, Vec::new()).unwrap(); 120 | assert_eq!(original_toml, new_toml); 121 | } 122 | 123 | #[test] 124 | fn doesnt_panic_on_empty_array() { 125 | let result = update_aliases_toml("alias.mistake = []", Vec::new()); 126 | // Currently an error, could be skipped instead, in that case the Ok(..) result 127 | // should be tested a bit. 128 | assert!(result.is_err()); 129 | } 130 | 131 | #[test] 132 | fn doesnt_panic_on_nested_keys() { 133 | let result = update_aliases_toml("alias.alias.alias = 'test'", Vec::new()); 134 | // Currently an error, could be skipped instead, in that case the Ok(..) result 135 | // should be tested a bit. 136 | assert!(result.is_err()); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/cli.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | use anyhow::bail; 4 | use anyhow::Result; 5 | use clap::Arg; 6 | use clap::ArgMatches; 7 | use clap::Command; 8 | 9 | use crate::binary; 10 | use crate::cargo_config; 11 | use crate::metadata; 12 | use crate::shims; 13 | 14 | fn install_all_binaries() -> Result<()> { 15 | let binary_packages = metadata::get_binary_packages()?; 16 | for binary_package in binary_packages { 17 | binary::install(binary_package)?; 18 | } 19 | 20 | println!("\x1b[32mDone!\x1b[0m"); 21 | return Ok(()); 22 | } 23 | 24 | fn sync_aliases() -> Result<()> { 25 | cargo_config::sync_aliases()?; 26 | println!("\x1b[32mDone!\x1b[0m"); 27 | return Ok(()); 28 | } 29 | 30 | fn run_binary(binary_name: String, args: Vec) -> Result<()> { 31 | let binary_packages = metadata::get_binary_packages()?; 32 | let binary_package = binary_packages.iter().find(|&e| { 33 | return e.package == binary_name 34 | || (e.bin_target.is_some() && e.bin_target.as_deref().unwrap() == binary_name); 35 | }); 36 | if binary_package.is_none() { 37 | bail!(format!("No package found for binary {binary_name}")); 38 | } 39 | 40 | let bin_path = binary::install(binary_package.unwrap().clone())?; 41 | shims::sync()?; 42 | binary::run(bin_path, args)?; 43 | 44 | return Ok(()); 45 | } 46 | 47 | fn arg_used(matches: &ArgMatches, arg_long: &str) -> bool { 48 | if let Some(used) = matches.get_one::(arg_long) { 49 | if *used { 50 | return true; 51 | } 52 | } 53 | 54 | if let Some(sub) = matches.subcommand_matches("bin") { 55 | if let Some(used) = sub.get_one::(arg_long) { 56 | if *used { 57 | return true; 58 | } 59 | } 60 | } 61 | 62 | return false; 63 | } 64 | 65 | pub fn run() -> Result<()> { 66 | let arg_sync_aliases = Arg::new("sync-aliases") 67 | .short('s') 68 | .long("sync-aliases") 69 | .num_args(0) 70 | .help("Sync aliases for cargo-* commands in .cargo/config.toml"); 71 | 72 | let arg_install = Arg::new("install") 73 | .short('i') 74 | .long("install") 75 | .num_args(0) 76 | .help("Install/build all configured binaries, skips entries that are already installed."); 77 | 78 | let arg_help = Arg::new("help") 79 | .short('h') 80 | .long("help") 81 | .num_args(0) 82 | .help("Print help"); 83 | 84 | let arg_version = Arg::new("version") 85 | .short('V') 86 | .long("version") 87 | .num_args(0) 88 | .help("Print version"); 89 | 90 | // @deprecated: Use --install. 91 | let arg_build = Arg::new("build") 92 | .short('b') 93 | .long("build") 94 | .hide(true) 95 | .num_args(0); 96 | 97 | let mut app = Command::new("cargo-bin") 98 | .about(env!("CARGO_PKG_DESCRIPTION")) 99 | .author(env!("CARGO_PKG_AUTHORS")) 100 | .version(env!("CARGO_PKG_VERSION")) 101 | .arg_required_else_help(false) 102 | .ignore_errors(true) 103 | .disable_version_flag(true) 104 | .arg(arg_sync_aliases.clone()) 105 | .arg(arg_install.clone()) 106 | .arg(arg_build.clone()) 107 | .arg(arg_version.clone()) 108 | .subcommand( 109 | Command::new("bin") 110 | .hide(true) 111 | .disable_help_flag(true) 112 | .arg(arg_sync_aliases) 113 | .arg(arg_install) 114 | .arg(arg_build) 115 | .arg(arg_help) 116 | .arg(arg_version), 117 | ); 118 | 119 | let matches = app.clone().get_matches(); 120 | 121 | if arg_used(&matches, "sync-aliases") { 122 | sync_aliases()?; 123 | } else if arg_used(&matches, "install") || arg_used(&matches, "build") { 124 | install_all_binaries()?; 125 | } else if arg_used(&matches, "help") { 126 | app.print_long_help()?; 127 | } else if arg_used(&matches, "version") { 128 | println!("cargo-run-bin {}", env!("CARGO_PKG_VERSION")); 129 | } else { 130 | let mut args: Vec<_> = env::args().collect(); 131 | let start_index = args 132 | .iter() 133 | .position(|e| return e.ends_with("/cargo-bin") || e.ends_with("cargo-bin.exe")); 134 | if start_index.is_none() || start_index.unwrap() == (args.len() + 1) { 135 | app.print_long_help()?; 136 | return Ok(()); 137 | } 138 | 139 | let mut bin_index = start_index.unwrap() + 1; 140 | if args[bin_index] == "bin" { 141 | bin_index += 1; 142 | } 143 | if bin_index >= args.len() { 144 | app.print_long_help()?; 145 | return Ok(()); 146 | } 147 | 148 | let binary_name = args[bin_index].clone(); 149 | args.drain(0..(bin_index + 1)); 150 | 151 | run_binary(binary_name, args)?; 152 | } 153 | 154 | return Ok(()); 155 | } 156 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Installing tooling globally when working in teams or on CI is a silly 2 | //! problem to manage. `cargo-run-bin` builds, caches, and executes binaries 3 | //! from their locked down versions in `Cargo.toml`, and allows your teams to 4 | //! always be running the same tooling versions. 5 | //! 6 | //! For command lines that extend cargo such as `cargo-nextest`, run-bin will 7 | //! create and manage cargo aliases to allow using cargo extensions without any 8 | //! changes to your command line scripts! `cargo-run-bin` gets out of your way, 9 | //! and you'll forget you're even using it! 10 | //! 11 | //! ## Usage 12 | //! 13 | //! For command line usage, see the [GitHub repo](https://github.com/dustinblackman/cargo-run-bin). 14 | //! 15 | //! `run-bin` can also be used as a library and paired nicely with your 16 | //! `build.rs` or any other scripts. The following example demos having `dprint` 17 | //! configured within `[package.metadata.bin]`, and executing `dprint --help`. 18 | //! 19 | //! ```toml 20 | //! [package.metadata.bin] 21 | //! dprint = { version = "0.40.2" } 22 | //! ``` 23 | //! 24 | //! ```rust 25 | //! use anyhow::Result; 26 | //! use cargo_run_bin::{binary, metadata}; 27 | //! 28 | //! fn main() -> Result<()> { 29 | //! let binary_package = metadata::get_binary_packages()? 30 | //! .iter() 31 | //! .find(|e| e.package == "dprint") 32 | //! .unwrap() 33 | //! .to_owned(); 34 | //! let bin_path = binary::install(binary_package)?; 35 | //! binary::run(bin_path, vec!["--help".to_string()])?; 36 | //! 37 | //! return Ok(()); 38 | //! } 39 | //! ``` 40 | //! 41 | //! Using `binary::run` is optional. You can recreate it and make changes to 42 | //! your liking using `std::process`, with shims included! 43 | //! 44 | //! ```rust 45 | //! use std::process; 46 | //! 47 | //! use anyhow::Result; 48 | //! use cargo_run_bin::{binary, metadata, shims}; 49 | //! 50 | //! fn main() -> Result<()> { 51 | //! let binary_package = metadata::get_binary_packages()? 52 | //! .iter() 53 | //! .find(|e| e.package == "dprint") 54 | //! .unwrap() 55 | //! .to_owned(); 56 | //! let bin_path = binary::install(binary_package)?; 57 | //! 58 | //! let mut shell_paths = shims::get_shim_paths()?; 59 | //! shell_paths.push(env::var("PATH").unwrap_or("".to_string())); 60 | //! 61 | //! process::Command::new(bin_path) 62 | //! .args(["--help"]) 63 | //! .env("PATH", shell_paths.join(":")) 64 | //! .spawn(); 65 | //! 66 | //! return Ok(()); 67 | //! } 68 | //! ``` 69 | 70 | #![deny(clippy::implicit_return)] 71 | #![allow(clippy::needless_return)] 72 | 73 | pub mod binary; 74 | pub mod cargo_config; 75 | #[cfg(not(doc))] 76 | #[cfg(feature = "cli")] 77 | pub mod cli; 78 | pub mod metadata; 79 | pub mod shims; 80 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::process; 2 | 3 | fn main() { 4 | let res = cargo_run_bin::cli::run(); 5 | 6 | // Only reached if run-bin code fails, otherwise process exits early from within 7 | // binary::run. 8 | if let Err(res) = res { 9 | eprintln!("\x1b[31m{}\x1b[0m", format!("run-bin failed: {res}")); 10 | process::exit(1); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/metadata.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::env; 3 | use std::fs; 4 | use std::path::PathBuf; 5 | 6 | use anyhow::anyhow; 7 | use anyhow::bail; 8 | use anyhow::Result; 9 | use serde::Deserialize; 10 | use toml_edit::Document; 11 | use toml_edit::Item; 12 | 13 | #[cfg(test)] 14 | #[path = "metadata_test.rs"] 15 | mod metadata_test; 16 | 17 | #[derive(Deserialize, Debug, PartialEq)] 18 | struct MetadataValue { 19 | version: String, 20 | git: Option, 21 | branch: Option, 22 | tag: Option, 23 | rev: Option, 24 | path: Option, 25 | locked: Option, 26 | bins: Option>, 27 | #[serde(alias = "default-features")] 28 | default_features: Option, 29 | features: Option>, 30 | } 31 | 32 | type MetadataBins = HashMap; 33 | 34 | #[derive(Clone)] 35 | pub struct BinaryPackage { 36 | pub bin_target: Option, 37 | pub package: String, 38 | pub locked: Option, 39 | pub version: String, 40 | pub git: Option, 41 | pub branch: Option, 42 | pub tag: Option, 43 | pub rev: Option, 44 | pub path: Option, 45 | pub default_features: Option, 46 | pub features: Option>, 47 | } 48 | 49 | pub fn get_project_root() -> Result { 50 | let path = env::current_dir()?; 51 | let path_ancestors = path.as_path().ancestors(); 52 | 53 | for p in path_ancestors { 54 | let has_cargo = fs::read_dir(p)?.any(|p| return p.unwrap().file_name() == *"Cargo.lock"); 55 | 56 | if has_cargo { 57 | return Ok(PathBuf::from(p)); 58 | } 59 | } 60 | 61 | return Err(anyhow!("Root directory for rust project not found.")); 62 | } 63 | 64 | fn toml_has_path(doc: &Item, keys: Vec<&str>) -> bool { 65 | let mut item = doc; 66 | for key in keys { 67 | if item.get(key).is_none() { 68 | return false; 69 | } 70 | item = &item[key]; 71 | } 72 | 73 | return true; 74 | } 75 | 76 | fn get_metadata_binaries() -> Result { 77 | let toml_str: String = fs::read_to_string(get_project_root()?.join("Cargo.toml"))?.parse()?; 78 | let doc = toml_str.parse::()?; 79 | 80 | let mut metadata_str = "".to_string(); 81 | if toml_has_path(doc.as_item(), vec!["package", "metadata", "bin"]) { 82 | metadata_str = doc["package"]["metadata"]["bin"].to_string(); 83 | } else if toml_has_path(doc.as_item(), vec!["workspace", "metadata", "bin"]) { 84 | metadata_str = doc["workspace"]["metadata"]["bin"].to_string(); 85 | } 86 | 87 | if metadata_str.is_empty() { 88 | bail!("No binaries configured in Cargo.toml"); 89 | } 90 | 91 | let metadata_res: Result = toml::from_str(&metadata_str); 92 | return Ok(metadata_res?); 93 | } 94 | 95 | /// Returns all configured binary packages set in Cargo.toml. 96 | pub fn get_binary_packages() -> Result> { 97 | let metadata = get_metadata_binaries()?; 98 | 99 | let mut binary_details: Vec = Vec::new(); 100 | 101 | for (pkg_name, pkg_details) in metadata.into_iter() { 102 | if let Some(pkg_bins) = pkg_details.bins { 103 | for bin_target in pkg_bins.iter() { 104 | binary_details.push(BinaryPackage { 105 | bin_target: Some(bin_target.to_string()), 106 | package: pkg_name.clone(), 107 | locked: pkg_details.locked, 108 | version: pkg_details.version.clone(), 109 | git: pkg_details.git.clone(), 110 | branch: pkg_details.branch.clone(), 111 | tag: pkg_details.tag.clone(), 112 | rev: pkg_details.rev.clone(), 113 | path: pkg_details.path.clone(), 114 | default_features: pkg_details.default_features, 115 | features: pkg_details.features.clone(), 116 | }); 117 | } 118 | } else { 119 | binary_details.push(BinaryPackage { 120 | bin_target: None, 121 | package: pkg_name, 122 | locked: pkg_details.locked, 123 | version: pkg_details.version, 124 | git: pkg_details.git, 125 | branch: pkg_details.branch, 126 | tag: pkg_details.tag, 127 | rev: pkg_details.rev, 128 | path: pkg_details.path, 129 | default_features: pkg_details.default_features, 130 | features: pkg_details.features, 131 | }); 132 | } 133 | } 134 | 135 | binary_details.sort_by_key(|e| { 136 | if e.bin_target.is_some() { 137 | return e.bin_target.as_ref().unwrap().to_string(); 138 | } 139 | return e.package.to_string(); 140 | }); 141 | 142 | return Ok(binary_details); 143 | } 144 | -------------------------------------------------------------------------------- /src/metadata_test.rs: -------------------------------------------------------------------------------- 1 | use super::get_binary_packages; 2 | 3 | mod get_binary_packages { 4 | use super::*; 5 | 6 | #[test] 7 | fn it_returns_locked_packages() { 8 | let binary_packages = get_binary_packages().unwrap(); 9 | let nextest = binary_packages 10 | .iter() 11 | .find(|&e| return e.package == "cargo-nextest"); 12 | 13 | assert!(nextest.is_some()); 14 | let res = nextest.unwrap(); 15 | assert_eq!(&res.package, "cargo-nextest"); 16 | assert_ne!(&res.version, ""); 17 | assert!(res.locked.unwrap()); 18 | } 19 | 20 | #[test] 21 | fn it_returns_bin_target_packages() { 22 | let binary_packages = get_binary_packages().unwrap(); 23 | let android = binary_packages.iter().find(|&e| { 24 | return e.bin_target.is_some() && e.bin_target.clone().unwrap() == "hello-world-first"; 25 | }); 26 | 27 | assert!(android.is_some()); 28 | let res = android.unwrap(); 29 | assert_eq!(&res.package, "dustinblackman-hello-world"); 30 | assert_ne!(&res.version, ""); 31 | assert_eq!( 32 | &res.git, 33 | &Some("https://github.com/dustinblackman/rust-hello-world".to_string()) 34 | ); 35 | assert_eq!(res.bin_target.clone().unwrap(), "hello-world-first"); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/shims.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::fs; 3 | use std::io::Write; 4 | use std::path; 5 | 6 | use anyhow::Result; 7 | use cfg_if::cfg_if; 8 | 9 | use crate::metadata; 10 | 11 | #[cfg(target_family = "unix")] 12 | fn create_shim(binary: &str, bin_path: path::PathBuf) -> Result<()> { 13 | use std::os::unix::prelude::OpenOptionsExt; 14 | 15 | let mut shell = env::var("SHELL") 16 | .unwrap_or("bash".to_string()) 17 | .split('/') 18 | .last() 19 | .unwrap() 20 | .to_string(); 21 | 22 | if !["bash", "zsh", "sh"].contains(&&*shell) { 23 | shell = "sh".to_string(); 24 | } 25 | 26 | let script = format!( 27 | r#"#!/usr/bin/env {shell} 28 | 29 | if [ ! -t 0 ]; then 30 | cat - | cargo bin {binary} "$@" 31 | else 32 | cargo bin {binary} "$@" 33 | fi"# 34 | ); 35 | 36 | let mut f = fs::OpenOptions::new() 37 | .create(true) 38 | .write(true) 39 | .mode(0o770) 40 | .open(bin_path)?; 41 | 42 | write!(f, "{}", script)?; 43 | 44 | return Ok(()); 45 | } 46 | 47 | #[cfg(not(target_family = "unix"))] 48 | fn create_shim(binary: &str, bin_path: path::PathBuf) -> Result<()> { 49 | let script = format!( 50 | r#"@echo off 51 | cargo bin {binary} %* 52 | "# 53 | ); 54 | 55 | let mut f = fs::OpenOptions::new() 56 | .create(true) 57 | .write(true) 58 | .open(bin_path)?; 59 | 60 | write!(f, "{}", script)?; 61 | 62 | return Ok(()); 63 | } 64 | 65 | /// Creates shims in `.bin/shims` for all non cargo extensions configured in 66 | /// Cargo.toml. This directory is added to PATH For all executes of `cargo bin`. 67 | pub fn sync() -> Result<()> { 68 | let bin_dir = metadata::get_project_root()?.join(".bin/.shims"); 69 | if !bin_dir.exists() { 70 | fs::create_dir_all(&bin_dir)?; 71 | } 72 | 73 | for pkg in metadata::get_binary_packages()? { 74 | let mut bin = pkg.package; 75 | if let Some(bin_target) = pkg.bin_target { 76 | bin = bin_target; 77 | } 78 | 79 | if bin.starts_with("cargo-") { 80 | continue; 81 | } 82 | 83 | let mut bin_path = bin_dir.join(&bin); 84 | bin_path.set_extension(""); 85 | cfg_if! { 86 | if #[cfg(not(target_family = "unix"))] { 87 | bin_path.set_extension("cmd"); 88 | } 89 | } 90 | if bin_path.exists() { 91 | continue; 92 | } 93 | 94 | create_shim(&bin, bin_path)?; 95 | } 96 | 97 | return Ok(()); 98 | } 99 | 100 | /// Return an array of entries that can be added to PATH to provide shims to 101 | /// other configured run-bin packages. Results be empty if entries already exist 102 | /// in PATH. 103 | pub fn get_shim_paths() -> Result> { 104 | let mut shim_paths = vec![]; 105 | let system_shell_paths = env::var("PATH") 106 | .unwrap_or("".to_string()) 107 | .split(':') 108 | .map(|e| return e.to_string()) 109 | .collect::>(); 110 | 111 | let project_root = metadata::get_project_root()?; 112 | let runbin = project_root 113 | .join(".bin/.shims") 114 | .to_string_lossy() 115 | .to_string(); 116 | 117 | if !system_shell_paths.contains(&runbin) { 118 | shim_paths.push(runbin); 119 | } 120 | 121 | let gha = project_root.join(".gha/.shims"); 122 | if gha.exists() && !system_shell_paths.contains(&gha.to_string_lossy().to_string()) { 123 | shim_paths.push(gha.to_string_lossy().to_string()); 124 | } 125 | 126 | return Ok(shim_paths); 127 | } 128 | -------------------------------------------------------------------------------- /tests/binary_test.rs: -------------------------------------------------------------------------------- 1 | mod install { 2 | use cargo_run_bin::binary::install; 3 | use cargo_run_bin::metadata; 4 | use cfg_if::cfg_if; 5 | 6 | #[test] 7 | fn it_returns_bin_path() { 8 | let binary_packages = metadata::get_binary_packages().unwrap(); 9 | let nextest = binary_packages 10 | .iter() 11 | .find(|&e| e.package == "cargo-nextest") 12 | .unwrap(); 13 | 14 | let cache_bin_path = install(nextest.clone()).unwrap(); 15 | 16 | cfg_if! { 17 | if #[cfg(not(target_family = "unix"))] { 18 | assert!(cache_bin_path.ends_with("\\bin\\cargo-nextest.exe")); 19 | } else { 20 | assert!(cache_bin_path.ends_with("/bin/cargo-nextest")); 21 | } 22 | } 23 | } 24 | } 25 | 26 | mod cargo_install { 27 | use cargo_run_bin::binary::cargo_install; 28 | use cargo_run_bin::metadata; 29 | 30 | #[test] 31 | fn it_builds_successfully() { 32 | let res = cargo_install( 33 | metadata::BinaryPackage { 34 | bin_target: None, 35 | package: "dustinblackman-hello-world".to_string(), 36 | locked: None, 37 | version: "0.1.0".to_string(), 38 | git: None, 39 | branch: None, 40 | tag: None, 41 | rev: None, 42 | path: None, 43 | default_features: None, 44 | features: None, 45 | }, 46 | "./.tmp".into(), 47 | ); 48 | 49 | assert!(res.is_ok()); 50 | } 51 | 52 | #[test] 53 | fn it_builds_successfully_with_git() { 54 | let res = cargo_install( 55 | metadata::BinaryPackage { 56 | bin_target: None, 57 | package: "dustinblackman-hello-world".to_string(), 58 | locked: None, 59 | version: "0.2.0".to_string(), 60 | git: Some("https://github.com/dustinblackman/rust-hello-world".to_string()), 61 | branch: None, 62 | tag: None, 63 | rev: None, 64 | path: None, 65 | default_features: None, 66 | features: None, 67 | }, 68 | "./.tmp".into(), 69 | ); 70 | 71 | assert!(res.is_ok()); 72 | } 73 | 74 | #[test] 75 | fn it_builds_successfully_with_git_rev() { 76 | let res = cargo_install( 77 | metadata::BinaryPackage { 78 | bin_target: None, 79 | package: "dustinblackman-hello-world".to_string(), 80 | locked: None, 81 | version: "0.2.0".to_string(), 82 | git: Some("https://github.com/dustinblackman/rust-hello-world".to_string()), 83 | branch: None, 84 | tag: None, 85 | rev: Some("8a1cd3d2538460d1e8920bf86cf6e2aa982eb69d".to_string()), 86 | path: None, 87 | default_features: None, 88 | features: None, 89 | }, 90 | "./.tmp".into(), 91 | ); 92 | 93 | assert!(res.is_ok()); 94 | } 95 | 96 | #[test] 97 | fn it_builds_successfully_with_git_branch() { 98 | let res = cargo_install( 99 | metadata::BinaryPackage { 100 | bin_target: None, 101 | package: "dustinblackman-hello-world".to_string(), 102 | locked: None, 103 | version: "0.2.0".to_string(), 104 | git: Some("https://github.com/dustinblackman/rust-hello-world".to_string()), 105 | branch: Some("testbranch".to_string()), 106 | tag: None, 107 | rev: None, 108 | path: None, 109 | default_features: None, 110 | features: None, 111 | }, 112 | "./.tmp".into(), 113 | ); 114 | 115 | assert!(res.is_ok()); 116 | } 117 | 118 | #[test] 119 | fn it_builds_successfully_with_git_tag() { 120 | let res = cargo_install( 121 | metadata::BinaryPackage { 122 | bin_target: None, 123 | package: "dustinblackman-hello-world".to_string(), 124 | locked: None, 125 | version: "0.2.1".to_string(), 126 | git: Some("https://github.com/dustinblackman/rust-hello-world".to_string()), 127 | branch: None, 128 | tag: Some("v0.2.1".to_string()), 129 | rev: None, 130 | path: None, 131 | default_features: None, 132 | features: None, 133 | }, 134 | "./.tmp".into(), 135 | ); 136 | 137 | assert!(res.is_ok()); 138 | } 139 | 140 | #[test] 141 | fn it_builds_successfully_with_path() { 142 | let res = cargo_install( 143 | metadata::BinaryPackage { 144 | bin_target: None, 145 | package: "cargo-run-bin".to_string(), 146 | locked: None, 147 | version: "1.4.1".to_string(), 148 | git: None, 149 | branch: None, 150 | tag: None, 151 | rev: None, 152 | path: Some(String::from(".")), 153 | default_features: None, 154 | features: None, 155 | }, 156 | "./.tmp".into(), 157 | ); 158 | 159 | assert!(res.is_ok()); 160 | } 161 | } 162 | 163 | mod binstall { 164 | use cargo_run_bin::binary::binstall; 165 | use cargo_run_bin::metadata; 166 | 167 | #[test] 168 | fn it_builds_successfully() { 169 | let res = binstall( 170 | metadata::BinaryPackage { 171 | bin_target: None, 172 | package: "dustinblackman-hello-world".to_string(), 173 | locked: None, 174 | version: "0.1.0".to_string(), 175 | git: None, 176 | branch: None, 177 | tag: None, 178 | rev: None, 179 | path: None, 180 | default_features: None, 181 | features: None, 182 | }, 183 | "./.tmp".into(), 184 | ); 185 | 186 | assert!(res.is_ok()); 187 | } 188 | 189 | #[test] 190 | fn it_builds_successfully_with_git() { 191 | let res = binstall( 192 | metadata::BinaryPackage { 193 | bin_target: None, 194 | package: "dustinblackman-hello-world".to_string(), 195 | locked: None, 196 | version: "0.1.0".to_string(), 197 | git: Some("https://github.com/dustinblackman/rust-hello-world".to_string()), 198 | branch: None, 199 | tag: None, 200 | rev: None, 201 | path: None, 202 | default_features: None, 203 | features: None, 204 | }, 205 | "./.tmp".into(), 206 | ); 207 | 208 | assert!(res.is_ok()); 209 | } 210 | } 211 | 212 | mod run { 213 | use cargo_run_bin::binary::install; 214 | use cargo_run_bin::binary::run; 215 | use cargo_run_bin::metadata; 216 | 217 | #[test] 218 | fn it_runs_help_successfully() { 219 | let binary_packages = metadata::get_binary_packages().unwrap(); 220 | let nextest = binary_packages 221 | .iter() 222 | .find(|&e| e.package == "cargo-nextest") 223 | .unwrap(); 224 | let cache_bin_path = install(nextest.clone()).unwrap(); 225 | 226 | let res = run(cache_bin_path, vec!["--help".to_string()]); 227 | assert!(res.is_ok()); 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /tests/cargo_config_test.rs: -------------------------------------------------------------------------------- 1 | mod sync_aliases { 2 | use std::fs; 3 | 4 | use cargo_run_bin::cargo_config::sync_aliases; 5 | 6 | #[test] 7 | fn it_removes_and_adds_aliases() { 8 | let res = sync_aliases(); 9 | let toml_str: String = fs::read_to_string(".cargo/config.toml") 10 | .unwrap() 11 | .parse() 12 | .unwrap(); 13 | 14 | assert!(res.is_ok()); 15 | assert!(toml_str.contains("nextest = [\"bin\", \"cargo-nextest\"]")); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/cli_integration_test.rs: -------------------------------------------------------------------------------- 1 | mod direct { 2 | use assert_cmd::Command; 3 | 4 | #[test] 5 | fn it_syncs_aliases_successfully() { 6 | let mut cmd = Command::cargo_bin("cargo-bin").unwrap(); 7 | let assert = cmd.arg("--sync-aliases").assert(); 8 | 9 | let res = assert.success(); 10 | let stdout = String::from_utf8(res.get_output().stdout.clone()).unwrap(); 11 | insta::assert_snapshot!(stdout, @r###" 12 | Done! 13 | "###); 14 | } 15 | 16 | #[test] 17 | fn it_install_all_bins_successfully() { 18 | let mut cmd = Command::cargo_bin("cargo-bin").unwrap(); 19 | let assert = cmd.arg("--install").assert(); 20 | 21 | let res = assert.success(); 22 | let stdout = String::from_utf8(res.get_output().stdout.clone()).unwrap(); 23 | insta::assert_snapshot!(stdout, @r###" 24 | Done! 25 | "###); 26 | } 27 | 28 | #[test] 29 | fn it_builds_all_bins_successfully() { 30 | let mut cmd = Command::cargo_bin("cargo-bin").unwrap(); 31 | let assert = cmd.arg("--build").assert(); 32 | 33 | let res = assert.success(); 34 | let stdout = String::from_utf8(res.get_output().stdout.clone()).unwrap(); 35 | insta::assert_snapshot!(stdout, @r###" 36 | Done! 37 | "###); 38 | } 39 | 40 | #[test] 41 | fn it_runs_help_successfully() { 42 | let mut cmd = Command::cargo_bin("cargo-bin").unwrap(); 43 | let assert = cmd.arg("--help").assert(); 44 | 45 | let res = assert.success(); 46 | let stdout = String::from_utf8(res.get_output().stdout.clone()).unwrap(); 47 | assert!(stdout.contains(env!("CARGO_PKG_DESCRIPTION"))); 48 | } 49 | 50 | #[test] 51 | fn it_runs_nextest_help_successfully() { 52 | let mut cmd = Command::cargo_bin("cargo-bin").unwrap(); 53 | let assert = cmd.arg("cargo-nextest").arg("--help").assert(); 54 | 55 | let res = assert.success(); 56 | let stdout = String::from_utf8(res.get_output().stdout.clone()).unwrap(); 57 | assert!(stdout.contains("cargo nextest")); 58 | } 59 | 60 | #[test] 61 | fn it_fails_when_binary_is_not_configured() { 62 | let mut cmd = Command::cargo_bin("cargo-bin").unwrap(); 63 | let assert = cmd.arg("not-real").assert(); 64 | 65 | let res = assert.failure(); 66 | let stderr = String::from_utf8(res.get_output().stderr.clone()).unwrap(); 67 | insta::assert_snapshot!(stderr, @r###" 68 | run-bin failed: No package found for binary not-real 69 | "###); 70 | } 71 | } 72 | 73 | mod bin_prefix { 74 | use assert_cmd::Command; 75 | 76 | #[test] 77 | fn it_syncs_aliases_successfully() { 78 | let mut cmd = Command::cargo_bin("cargo-bin").unwrap(); 79 | let assert = cmd.arg("bin").arg("--sync-aliases").assert(); 80 | 81 | let res = assert.success(); 82 | let stdout = String::from_utf8(res.get_output().stdout.clone()).unwrap(); 83 | insta::assert_snapshot!(stdout, @r###" 84 | Done! 85 | "###); 86 | } 87 | 88 | #[test] 89 | fn it_install_all_bins_successfully() { 90 | let mut cmd = Command::cargo_bin("cargo-bin").unwrap(); 91 | let assert = cmd.arg("bin").arg("--install").assert(); 92 | 93 | let res = assert.success(); 94 | let stdout = String::from_utf8(res.get_output().stdout.clone()).unwrap(); 95 | insta::assert_snapshot!(stdout, @r###" 96 | Done! 97 | "###); 98 | } 99 | 100 | #[test] 101 | fn it_builds_all_bins_successfully() { 102 | let mut cmd = Command::cargo_bin("cargo-bin").unwrap(); 103 | let assert = cmd.arg("bin").arg("--build").assert(); 104 | 105 | let res = assert.success(); 106 | let stdout = String::from_utf8(res.get_output().stdout.clone()).unwrap(); 107 | insta::assert_snapshot!(stdout, @r###" 108 | Done! 109 | "###); 110 | } 111 | 112 | #[test] 113 | fn it_runs_nextest_help_successfully() { 114 | let mut cmd = Command::cargo_bin("cargo-bin").unwrap(); 115 | let assert = cmd.arg("bin").arg("cargo-nextest").arg("--help").assert(); 116 | 117 | let res = assert.success(); 118 | let stdout = String::from_utf8(res.get_output().stdout.clone()).unwrap(); 119 | assert!(stdout.contains("cargo nextest")); 120 | } 121 | 122 | #[test] 123 | fn it_runs_help_successfully() { 124 | let mut cmd = Command::cargo_bin("cargo-bin").unwrap(); 125 | let assert = cmd.arg("bin").arg("--help").assert(); 126 | 127 | let res = assert.success(); 128 | let stdout = String::from_utf8(res.get_output().stdout.clone()).unwrap(); 129 | assert!(stdout.contains(env!("CARGO_PKG_DESCRIPTION"))); 130 | } 131 | 132 | #[test] 133 | fn it_fails_when_binary_is_not_configured() { 134 | let mut cmd = Command::cargo_bin("cargo-bin").unwrap(); 135 | let assert = cmd.arg("bin").arg("not-real").assert(); 136 | 137 | let res = assert.failure(); 138 | let stderr = String::from_utf8(res.get_output().stderr.clone()).unwrap(); 139 | insta::assert_snapshot!(stderr, @r###" 140 | run-bin failed: No package found for binary not-real 141 | "###); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /tests/shims_test.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | 3 | use anyhow::Result; 4 | use cargo_run_bin::metadata; 5 | 6 | fn clean_shims() -> Result<()> { 7 | let bin_dir = metadata::get_project_root()?.join(".bin/.shims"); 8 | if bin_dir.exists() { 9 | fs::remove_dir_all(&bin_dir)?; 10 | } 11 | 12 | Ok(()) 13 | } 14 | 15 | mod sync_shims { 16 | use std::fs; 17 | 18 | use cargo_run_bin::metadata; 19 | use cargo_run_bin::shims::sync; 20 | 21 | use super::clean_shims; 22 | 23 | #[test] 24 | #[cfg(target_family = "unix")] 25 | fn it_creates_shims() { 26 | clean_shims().unwrap(); 27 | let res = sync(); 28 | let exists = metadata::get_project_root() 29 | .unwrap() 30 | .join(".bin/.shims/hello-world-first") 31 | .exists(); 32 | 33 | clean_shims().unwrap(); 34 | assert!(res.is_ok()); 35 | assert!(exists); 36 | } 37 | 38 | #[test] 39 | #[cfg(target_family = "unix")] 40 | fn it_creates_shims_for_zsh() { 41 | std::env::set_var("SHELL", "zsh"); 42 | clean_shims().unwrap(); 43 | let res = sync(); 44 | assert!(res.is_ok()); 45 | 46 | let shim_path = metadata::get_project_root() 47 | .unwrap() 48 | .join(".bin/.shims/hello-world-first"); 49 | 50 | let content = fs::read_to_string(shim_path).unwrap(); 51 | 52 | clean_shims().unwrap(); 53 | assert!(content.starts_with("#!/usr/bin/env zsh")); 54 | } 55 | 56 | #[test] 57 | #[cfg(target_family = "unix")] 58 | fn it_creates_shims_falling_back_to_sh() { 59 | std::env::set_var("SHELL", "fish"); 60 | clean_shims().unwrap(); 61 | let res = sync(); 62 | assert!(res.is_ok()); 63 | 64 | let shim_path = metadata::get_project_root() 65 | .unwrap() 66 | .join(".bin/.shims/hello-world-first"); 67 | 68 | let content = fs::read_to_string(shim_path).unwrap(); 69 | 70 | clean_shims().unwrap(); 71 | assert!(content.starts_with("#!/usr/bin/env sh")); 72 | } 73 | 74 | #[test] 75 | #[cfg(not(target_family = "unix"))] 76 | fn it_creates_shims() { 77 | let res = sync(); 78 | let exists = metadata::get_project_root() 79 | .unwrap() 80 | .join(".bin/.shims/hello-world-first.cmd") 81 | .exists(); 82 | 83 | assert!(res.is_ok()); 84 | assert!(exists); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /tools/cargo-bin/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cargo-bin" 3 | 4 | [dependencies] 5 | cargo-run-bin = { version = "1.7.4", features = ["cli"]} -------------------------------------------------------------------------------- /tools/cargo-bin/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::process; 2 | 3 | fn main() { 4 | let res = cargo_run_bin::cli::run(); 5 | 6 | // Only reached if run-bin code fails, otherwise process exits early from within 7 | // binary::run. 8 | if let Err(res) = res { 9 | eprintln!("\x1b[31m{}\x1b[0m", format!("run-bin failed: {res}")); 10 | process::exit(1); 11 | } 12 | } 13 | --------------------------------------------------------------------------------