├── .github └── workflows │ └── rust.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md └── src ├── lib.rs └── main.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | tags: 8 | - 'v[0-9]+.[0-9]+.[0-9]+**' 9 | pull_request: 10 | 11 | jobs: 12 | rustfmt: 13 | name: Rustfmt 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v1 19 | 20 | - name: rust-toolchain 21 | uses: actions-rs/toolchain@v1 22 | with: 23 | toolchain: stable-x86_64-unknown-linux-gnu 24 | default: true 25 | 26 | - name: rustup component add 27 | run: rustup component add rustfmt 28 | 29 | - name: cargo fmt -- --check 30 | uses: actions-rs/cargo@v1 31 | with: 32 | command: fmt 33 | args: --all -- --check 34 | 35 | build: 36 | strategy: 37 | fail-fast: false 38 | matrix: 39 | toolchain: 40 | - stable-x86_64-pc-windows-msvc 41 | - stable-x86_64-apple-darwin 42 | - stable-x86_64-unknown-linux-gnu 43 | include: 44 | - toolchain: stable-x86_64-pc-windows-msvc 45 | os: windows-latest 46 | - toolchain: stable-x86_64-apple-darwin 47 | os: macOS-latest 48 | - toolchain: stable-x86_64-unknown-linux-gnu 49 | os: ubuntu-latest 50 | 51 | name: ${{ matrix.toolchain }} 52 | runs-on: ${{ matrix.os }} 53 | 54 | steps: 55 | - name: Checkout 56 | uses: actions/checkout@v1 57 | 58 | - name: rust-toolchain 59 | uses: actions-rs/toolchain@v1 60 | with: 61 | toolchain: ${{ matrix.toolchain }} 62 | default: true 63 | 64 | - name: rustup component add 65 | run: rustup component add clippy 66 | 67 | - name: Lint 68 | uses: actions-rs/cargo@v1 69 | with: 70 | command: clippy 71 | args: --verbose --all --all-targets --all-features -- -D warnings 72 | 73 | - name: Build 74 | uses: actions-rs/cargo@v1 75 | with: 76 | command: build 77 | args: --verbose --all --all-targets --all-features 78 | 79 | - name: Run tests 80 | uses: actions-rs/cargo@v1 81 | with: 82 | command: test 83 | args: --verbose --all --all-targets --all-features 84 | 85 | release: 86 | strategy: 87 | fail-fast: false 88 | matrix: 89 | target: 90 | - x86_64-pc-windows-msvc 91 | - x86_64-apple-darwin 92 | - x86_64-unknown-linux-gnu 93 | include: 94 | - target: x86_64-pc-windows-msvc 95 | os: windows-latest 96 | - target: x86_64-apple-darwin 97 | os: macOS-latest 98 | - target: x86_64-unknown-linux-gnu 99 | os: ubuntu-latest 100 | 101 | name: GitHub Release (${{ matrix.target }}) 102 | runs-on: ${{ matrix.os }} 103 | needs: [rustfmt, build] 104 | if: startsWith(github.ref, 'refs/tags/') 105 | 106 | steps: 107 | - name: Checkout 108 | uses: actions/checkout@v1 109 | 110 | - name: rust-toolchain 111 | uses: actions-rs/toolchain@v1 112 | with: 113 | toolchain: stable-${{ matrix.target }} 114 | default: true 115 | 116 | - name: Build 117 | uses: actions-rs/cargo@v1 118 | with: 119 | command: build 120 | args: --release --all-features 121 | 122 | - name: Create an asset 123 | id: asset 124 | run: | 125 | if ${{ contains(matrix.target, 'pc-windows') }}; then 126 | EXE=.exe 127 | fi 128 | EXECUTABLE="./target/release/${GITHUB_REPOSITORY#*/}$EXE" 129 | ASSET_STEM="${GITHUB_REPOSITORY#*/}-${GITHUB_REF#refs/tags/}-${{ matrix.target }}" 130 | git archive -o "./$ASSET_STEM.tar" --prefix "$ASSET_STEM/" HEAD 131 | tar -xf "./$ASSET_STEM.tar" 132 | mv "$EXECUTABLE" "./$ASSET_STEM/" 133 | if ${{ contains(matrix.target, 'pc-windows') }}; then 134 | ASSET="./$ASSET_STEM.zip" 135 | 7z a "$ASSET" "./$ASSET_STEM" 136 | zipinfo "$ASSET" 137 | else 138 | ASSET="./$ASSET_STEM.tar.gz" 139 | tar -czvf "$ASSET" "./$ASSET_STEM" 140 | fi 141 | echo "::set-output name=asset::$ASSET" 142 | shell: bash 143 | 144 | - name: Upload 145 | uses: softprops/action-gh-release@v1 146 | with: 147 | files: ${{ steps.asset.outputs.asset }} 148 | env: 149 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 150 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | .rustfm 4 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.17.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "ansi_term" 22 | version = "0.12.1" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" 25 | dependencies = [ 26 | "winapi", 27 | ] 28 | 29 | [[package]] 30 | name = "atty" 31 | version = "0.2.14" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 34 | dependencies = [ 35 | "hermit-abi", 36 | "libc", 37 | "winapi", 38 | ] 39 | 40 | [[package]] 41 | name = "autocfg" 42 | version = "1.1.0" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 45 | 46 | [[package]] 47 | name = "backtrace" 48 | version = "0.3.65" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" 51 | dependencies = [ 52 | "addr2line", 53 | "cc", 54 | "cfg-if 1.0.0", 55 | "libc", 56 | "miniz_oxide", 57 | "object", 58 | "rustc-demangle", 59 | ] 60 | 61 | [[package]] 62 | name = "bitflags" 63 | version = "1.3.2" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 66 | 67 | [[package]] 68 | name = "cc" 69 | version = "1.0.73" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" 72 | dependencies = [ 73 | "jobserver", 74 | ] 75 | 76 | [[package]] 77 | name = "cfg-if" 78 | version = "0.1.10" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 81 | 82 | [[package]] 83 | name = "cfg-if" 84 | version = "1.0.0" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 87 | 88 | [[package]] 89 | name = "clap" 90 | version = "2.34.0" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" 93 | dependencies = [ 94 | "ansi_term", 95 | "atty", 96 | "bitflags", 97 | "strsim", 98 | "textwrap", 99 | "unicode-width", 100 | "vec_map", 101 | ] 102 | 103 | [[package]] 104 | name = "dirs" 105 | version = "2.0.2" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" 108 | dependencies = [ 109 | "cfg-if 0.1.10", 110 | "dirs-sys", 111 | ] 112 | 113 | [[package]] 114 | name = "dirs-sys" 115 | version = "0.3.7" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" 118 | dependencies = [ 119 | "libc", 120 | "redox_users", 121 | "winapi", 122 | ] 123 | 124 | [[package]] 125 | name = "envy" 126 | version = "0.4.2" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "3f47e0157f2cb54f5ae1bd371b30a2ae4311e1c028f575cd4e81de7353215965" 129 | dependencies = [ 130 | "serde", 131 | ] 132 | 133 | [[package]] 134 | name = "failure" 135 | version = "0.1.8" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" 138 | dependencies = [ 139 | "backtrace", 140 | "failure_derive", 141 | ] 142 | 143 | [[package]] 144 | name = "failure_derive" 145 | version = "0.1.8" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" 148 | dependencies = [ 149 | "proc-macro2", 150 | "quote", 151 | "syn", 152 | "synstructure", 153 | ] 154 | 155 | [[package]] 156 | name = "fastrand" 157 | version = "1.7.0" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" 160 | dependencies = [ 161 | "instant", 162 | ] 163 | 164 | [[package]] 165 | name = "form_urlencoded" 166 | version = "1.0.1" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" 169 | dependencies = [ 170 | "matches", 171 | "percent-encoding", 172 | ] 173 | 174 | [[package]] 175 | name = "getrandom" 176 | version = "0.2.6" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" 179 | dependencies = [ 180 | "cfg-if 1.0.0", 181 | "libc", 182 | "wasi", 183 | ] 184 | 185 | [[package]] 186 | name = "gimli" 187 | version = "0.26.1" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" 190 | 191 | [[package]] 192 | name = "git2" 193 | version = "0.10.2" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "7c1af51ea8a906616af45a4ce78eacf25860f7a13ae7bf8a814693f0f4037a26" 196 | dependencies = [ 197 | "bitflags", 198 | "libc", 199 | "libgit2-sys", 200 | "log", 201 | "openssl-probe", 202 | "openssl-sys", 203 | "url", 204 | ] 205 | 206 | [[package]] 207 | name = "gitconfig" 208 | version = "0.1.0" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "4daba70c66c9b9ec765b6ccdbee6a8e054376b0dd3ead1770da9ba8fa9b70ef9" 211 | 212 | [[package]] 213 | name = "hermit-abi" 214 | version = "0.1.19" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 217 | dependencies = [ 218 | "libc", 219 | ] 220 | 221 | [[package]] 222 | name = "idna" 223 | version = "0.2.3" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" 226 | dependencies = [ 227 | "matches", 228 | "unicode-bidi", 229 | "unicode-normalization", 230 | ] 231 | 232 | [[package]] 233 | name = "instant" 234 | version = "0.1.12" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 237 | dependencies = [ 238 | "cfg-if 1.0.0", 239 | ] 240 | 241 | [[package]] 242 | name = "jobserver" 243 | version = "0.1.24" 244 | source = "registry+https://github.com/rust-lang/crates.io-index" 245 | checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" 246 | dependencies = [ 247 | "libc", 248 | ] 249 | 250 | [[package]] 251 | name = "libc" 252 | version = "0.2.126" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" 255 | 256 | [[package]] 257 | name = "libgit2-sys" 258 | version = "0.9.2" 259 | source = "registry+https://github.com/rust-lang/crates.io-index" 260 | checksum = "4870c781f6063efb83150cd22c1ddf6ecf58531419e7570cdcced46970f64a16" 261 | dependencies = [ 262 | "cc", 263 | "libc", 264 | "libssh2-sys", 265 | "libz-sys", 266 | "openssl-sys", 267 | "pkg-config", 268 | ] 269 | 270 | [[package]] 271 | name = "libssh2-sys" 272 | version = "0.2.23" 273 | source = "registry+https://github.com/rust-lang/crates.io-index" 274 | checksum = "b094a36eb4b8b8c8a7b4b8ae43b2944502be3e59cd87687595cf6b0a71b3f4ca" 275 | dependencies = [ 276 | "cc", 277 | "libc", 278 | "libz-sys", 279 | "openssl-sys", 280 | "pkg-config", 281 | "vcpkg", 282 | ] 283 | 284 | [[package]] 285 | name = "libz-sys" 286 | version = "1.1.8" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" 289 | dependencies = [ 290 | "cc", 291 | "libc", 292 | "pkg-config", 293 | "vcpkg", 294 | ] 295 | 296 | [[package]] 297 | name = "log" 298 | version = "0.4.17" 299 | source = "registry+https://github.com/rust-lang/crates.io-index" 300 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 301 | dependencies = [ 302 | "cfg-if 1.0.0", 303 | ] 304 | 305 | [[package]] 306 | name = "matches" 307 | version = "0.1.9" 308 | source = "registry+https://github.com/rust-lang/crates.io-index" 309 | checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" 310 | 311 | [[package]] 312 | name = "memchr" 313 | version = "2.5.0" 314 | source = "registry+https://github.com/rust-lang/crates.io-index" 315 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 316 | 317 | [[package]] 318 | name = "miniz_oxide" 319 | version = "0.5.3" 320 | source = "registry+https://github.com/rust-lang/crates.io-index" 321 | checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" 322 | dependencies = [ 323 | "adler", 324 | ] 325 | 326 | [[package]] 327 | name = "mkrepo" 328 | version = "0.1.3" 329 | dependencies = [ 330 | "clap", 331 | "dirs", 332 | "envy", 333 | "failure", 334 | "git2", 335 | "gitconfig", 336 | "serde", 337 | "serde_derive", 338 | "shellexpand", 339 | "tempfile", 340 | "toml", 341 | ] 342 | 343 | [[package]] 344 | name = "object" 345 | version = "0.28.4" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" 348 | dependencies = [ 349 | "memchr", 350 | ] 351 | 352 | [[package]] 353 | name = "openssl-probe" 354 | version = "0.1.5" 355 | source = "registry+https://github.com/rust-lang/crates.io-index" 356 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 357 | 358 | [[package]] 359 | name = "openssl-sys" 360 | version = "0.9.74" 361 | source = "registry+https://github.com/rust-lang/crates.io-index" 362 | checksum = "835363342df5fba8354c5b453325b110ffd54044e588c539cf2f20a8014e4cb1" 363 | dependencies = [ 364 | "autocfg", 365 | "cc", 366 | "libc", 367 | "pkg-config", 368 | "vcpkg", 369 | ] 370 | 371 | [[package]] 372 | name = "percent-encoding" 373 | version = "2.1.0" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 376 | 377 | [[package]] 378 | name = "pkg-config" 379 | version = "0.3.25" 380 | source = "registry+https://github.com/rust-lang/crates.io-index" 381 | checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" 382 | 383 | [[package]] 384 | name = "proc-macro2" 385 | version = "1.0.39" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" 388 | dependencies = [ 389 | "unicode-ident", 390 | ] 391 | 392 | [[package]] 393 | name = "quote" 394 | version = "1.0.18" 395 | source = "registry+https://github.com/rust-lang/crates.io-index" 396 | checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" 397 | dependencies = [ 398 | "proc-macro2", 399 | ] 400 | 401 | [[package]] 402 | name = "redox_syscall" 403 | version = "0.2.13" 404 | source = "registry+https://github.com/rust-lang/crates.io-index" 405 | checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" 406 | dependencies = [ 407 | "bitflags", 408 | ] 409 | 410 | [[package]] 411 | name = "redox_users" 412 | version = "0.4.3" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" 415 | dependencies = [ 416 | "getrandom", 417 | "redox_syscall", 418 | "thiserror", 419 | ] 420 | 421 | [[package]] 422 | name = "remove_dir_all" 423 | version = "0.5.3" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" 426 | dependencies = [ 427 | "winapi", 428 | ] 429 | 430 | [[package]] 431 | name = "rustc-demangle" 432 | version = "0.1.21" 433 | source = "registry+https://github.com/rust-lang/crates.io-index" 434 | checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" 435 | 436 | [[package]] 437 | name = "serde" 438 | version = "1.0.137" 439 | source = "registry+https://github.com/rust-lang/crates.io-index" 440 | checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" 441 | 442 | [[package]] 443 | name = "serde_derive" 444 | version = "1.0.137" 445 | source = "registry+https://github.com/rust-lang/crates.io-index" 446 | checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" 447 | dependencies = [ 448 | "proc-macro2", 449 | "quote", 450 | "syn", 451 | ] 452 | 453 | [[package]] 454 | name = "shellexpand" 455 | version = "1.1.1" 456 | source = "registry+https://github.com/rust-lang/crates.io-index" 457 | checksum = "2c7e79eddc7b411f9beeaaf2d421de7e7cb3b1ab9eaf1b79704c0e4130cba6b5" 458 | dependencies = [ 459 | "dirs", 460 | ] 461 | 462 | [[package]] 463 | name = "strsim" 464 | version = "0.8.0" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 467 | 468 | [[package]] 469 | name = "syn" 470 | version = "1.0.96" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" 473 | dependencies = [ 474 | "proc-macro2", 475 | "quote", 476 | "unicode-ident", 477 | ] 478 | 479 | [[package]] 480 | name = "synstructure" 481 | version = "0.12.6" 482 | source = "registry+https://github.com/rust-lang/crates.io-index" 483 | checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" 484 | dependencies = [ 485 | "proc-macro2", 486 | "quote", 487 | "syn", 488 | "unicode-xid", 489 | ] 490 | 491 | [[package]] 492 | name = "tempfile" 493 | version = "3.3.0" 494 | source = "registry+https://github.com/rust-lang/crates.io-index" 495 | checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" 496 | dependencies = [ 497 | "cfg-if 1.0.0", 498 | "fastrand", 499 | "libc", 500 | "redox_syscall", 501 | "remove_dir_all", 502 | "winapi", 503 | ] 504 | 505 | [[package]] 506 | name = "textwrap" 507 | version = "0.11.0" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 510 | dependencies = [ 511 | "unicode-width", 512 | ] 513 | 514 | [[package]] 515 | name = "thiserror" 516 | version = "1.0.31" 517 | source = "registry+https://github.com/rust-lang/crates.io-index" 518 | checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" 519 | dependencies = [ 520 | "thiserror-impl", 521 | ] 522 | 523 | [[package]] 524 | name = "thiserror-impl" 525 | version = "1.0.31" 526 | source = "registry+https://github.com/rust-lang/crates.io-index" 527 | checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" 528 | dependencies = [ 529 | "proc-macro2", 530 | "quote", 531 | "syn", 532 | ] 533 | 534 | [[package]] 535 | name = "tinyvec" 536 | version = "1.6.0" 537 | source = "registry+https://github.com/rust-lang/crates.io-index" 538 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 539 | dependencies = [ 540 | "tinyvec_macros", 541 | ] 542 | 543 | [[package]] 544 | name = "tinyvec_macros" 545 | version = "0.1.0" 546 | source = "registry+https://github.com/rust-lang/crates.io-index" 547 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 548 | 549 | [[package]] 550 | name = "toml" 551 | version = "0.5.9" 552 | source = "registry+https://github.com/rust-lang/crates.io-index" 553 | checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" 554 | dependencies = [ 555 | "serde", 556 | ] 557 | 558 | [[package]] 559 | name = "unicode-bidi" 560 | version = "0.3.8" 561 | source = "registry+https://github.com/rust-lang/crates.io-index" 562 | checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" 563 | 564 | [[package]] 565 | name = "unicode-ident" 566 | version = "1.0.0" 567 | source = "registry+https://github.com/rust-lang/crates.io-index" 568 | checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" 569 | 570 | [[package]] 571 | name = "unicode-normalization" 572 | version = "0.1.19" 573 | source = "registry+https://github.com/rust-lang/crates.io-index" 574 | checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" 575 | dependencies = [ 576 | "tinyvec", 577 | ] 578 | 579 | [[package]] 580 | name = "unicode-width" 581 | version = "0.1.9" 582 | source = "registry+https://github.com/rust-lang/crates.io-index" 583 | checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" 584 | 585 | [[package]] 586 | name = "unicode-xid" 587 | version = "0.2.3" 588 | source = "registry+https://github.com/rust-lang/crates.io-index" 589 | checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" 590 | 591 | [[package]] 592 | name = "url" 593 | version = "2.2.2" 594 | source = "registry+https://github.com/rust-lang/crates.io-index" 595 | checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" 596 | dependencies = [ 597 | "form_urlencoded", 598 | "idna", 599 | "matches", 600 | "percent-encoding", 601 | ] 602 | 603 | [[package]] 604 | name = "vcpkg" 605 | version = "0.2.15" 606 | source = "registry+https://github.com/rust-lang/crates.io-index" 607 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 608 | 609 | [[package]] 610 | name = "vec_map" 611 | version = "0.8.2" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 614 | 615 | [[package]] 616 | name = "wasi" 617 | version = "0.10.2+wasi-snapshot-preview1" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" 620 | 621 | [[package]] 622 | name = "winapi" 623 | version = "0.3.9" 624 | source = "registry+https://github.com/rust-lang/crates.io-index" 625 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 626 | dependencies = [ 627 | "winapi-i686-pc-windows-gnu", 628 | "winapi-x86_64-pc-windows-gnu", 629 | ] 630 | 631 | [[package]] 632 | name = "winapi-i686-pc-windows-gnu" 633 | version = "0.4.0" 634 | source = "registry+https://github.com/rust-lang/crates.io-index" 635 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 636 | 637 | [[package]] 638 | name = "winapi-x86_64-pc-windows-gnu" 639 | version = "0.4.0" 640 | source = "registry+https://github.com/rust-lang/crates.io-index" 641 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 642 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["himanoa "] 3 | edition = "2018" 4 | name = "mkrepo" 5 | version = "0.1.3" 6 | license = "MIT" 7 | homepage = "https://github.com/himanoa/mkrepo" 8 | repository = "https://github.com/himanoa/mkrepo" 9 | keywords = ["cli", "ghq"] 10 | categories = ["command-line-utilities"] 11 | readme="README.md" 12 | description = "Create repository directory for ghq style" 13 | [[bin]] 14 | name = "mkrepo" 15 | path = "src/main.rs" 16 | [dependencies] 17 | clap = "2.33.0" 18 | envy = "0.4.0" 19 | failure = "0.1.5" 20 | gitconfig = "0.1.0" 21 | serde = "1.0.101" 22 | serde_derive = "1.0.101" 23 | toml = "0.5.3" 24 | dirs = "2.0.2" 25 | git2 = "0.10" 26 | shellexpand = "1.0.0" 27 | [dev-dependencies] 28 | tempfile = "3.1.0" 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 himanoa 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## mkrepo 2 | 3 | Create directory and `git init` and initial commit in imitation of [ghq](https://github.com/motemen/ghq)'s management directory structure. 4 | 5 | ### Installation 6 | 7 | ``` 8 | cargo install mkrepo 9 | ``` 10 | 11 | ### Usage 12 | 13 | `mkrepo` requires following `.gitconfig` values. 14 | 15 | - `ghq.root` 16 | - `mkrepo.service` 17 | - `mkrepo.username` or `user.name` 18 | 19 | Add these values to your `~/.gitconfig`. 20 | 21 | ``` 22 | [user] 23 | name="himanoa" 24 | [ghq] 25 | root="~/src" 26 | [mkrepo] 27 | service="github.com" 28 | username="himanoa" 29 | ``` 30 | 31 | #### Simple 32 | 33 | ``` 34 | $ mkrepo sample-repository 35 | $ ls -al ~/src/github.com/himanoa/sample-repository 36 | ./ ../ .git/ 37 | ``` 38 | 39 | #### Overwrite author name 40 | 41 | ``` 42 | $ mkrepo -a himanoa-sandbox sample-repository 43 | $ ls -al ~/src/github.com/himanoa-sandbox/sample-repository 44 | ./ ../ .git/ 45 | ``` 46 | 47 | #### Overwrite service name 48 | 49 | ``` 50 | $ mkrepo -s example.com sample-repository 51 | $ ls -al ~/src/example.com/himanoa/sample-repository 52 | ./ ../ .git/ 53 | ``` 54 | 55 | #### Overwrite first commit message 56 | 57 | ``` 58 | $ mkrepo -m "Custom initial commit message" sample-repository 59 | $ cd ~/src/github.com/himanoa/sample-repository 60 | $ git show 61 | 62 | commit 838a05bebd96e04a21d539946c92f78f9eb233d0 (HEAD -> master) 63 | Author: himanoa 64 | Date: Fri Oct 25 05:20:10 2019 +0900 65 | 66 | Custom initial commit message 67 | ``` 68 | 69 | ### Author 70 | 71 | - [himanoa](https://twitter.com/h1manoa) 72 | 73 | ### LICENSE 74 | 75 | MIT 76 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod makerepo { 2 | use failure::{Error, Fail}; 3 | use git2::Config as GitConfig; 4 | use git2::ConfigEntries; 5 | use serde_derive::Deserialize; 6 | use shellexpand::tilde; 7 | use std::fs::create_dir_all; 8 | use std::iter::Iterator; 9 | use std::ops::Deref; 10 | use std::path; 11 | use std::path::PathBuf; 12 | use std::process::Command; 13 | 14 | #[derive(Debug, PartialEq)] 15 | pub enum CommandType { 16 | CreateDirectory { 17 | path: String, 18 | }, 19 | InitializeGit { 20 | first_commit_message: String, 21 | path: String, 22 | }, 23 | } 24 | 25 | pub trait Executor { 26 | fn execute(&self, commands: Vec) -> Result<(), ExecutorError>; 27 | } 28 | 29 | #[derive(Debug, Default)] 30 | pub struct DryRunExecutor {} 31 | 32 | impl DryRunExecutor { 33 | pub fn new() -> DryRunExecutor { 34 | Self::default() 35 | } 36 | } 37 | 38 | impl Executor for DryRunExecutor { 39 | fn execute(&self, commands: Vec) -> Result<(), ExecutorError> { 40 | for command in commands { 41 | match command { 42 | CommandType::CreateDirectory { path } => println!("CreateDirectory: {}", path), 43 | CommandType::InitializeGit { 44 | first_commit_message, 45 | path, 46 | } => println!("InitializeGit: {} {}", first_commit_message, path), 47 | } 48 | } 49 | Ok(()) 50 | } 51 | } 52 | 53 | pub fn create_directory(path: &str) -> Result<(), std::io::Error> { 54 | create_dir_all(path) 55 | } 56 | 57 | #[derive(Debug, Fail)] 58 | pub enum GitError { 59 | #[fail(display = "fail git repository initialize")] 60 | Initialize, 61 | #[fail(display = "git repository already exist")] 62 | AlreadyExist, 63 | } 64 | 65 | impl From for GitError { 66 | fn from(_: std::io::Error) -> GitError { 67 | GitError::Initialize {} 68 | } 69 | } 70 | 71 | pub fn initialize_git(first_commit_message: &str, path: &str) -> Result<(), GitError> { 72 | let git_status_result = Command::new("git") 73 | .arg("status") 74 | .current_dir(path) 75 | .output()?; 76 | if git_status_result.status.success() { 77 | return Err(GitError::AlreadyExist {}); 78 | } 79 | let create_dir_result = Command::new("git").arg("init").current_dir(path).output()?; 80 | let initial_commit_result = Command::new("git") 81 | .args(&["commit", "-m", first_commit_message, "--allow-empty"]) 82 | .current_dir(path) 83 | .output()?; 84 | match ( 85 | create_dir_result.status.success(), 86 | initial_commit_result.status.success(), 87 | ) { 88 | (true, true) => Ok(()), 89 | _ => Err(GitError::Initialize {}), 90 | } 91 | } 92 | 93 | #[derive(Debug, Default)] 94 | pub struct DefaultExecutor {} 95 | 96 | impl DefaultExecutor { 97 | pub fn new() -> DefaultExecutor { 98 | Self::default() 99 | } 100 | } 101 | 102 | #[derive(Debug, Fail)] 103 | pub enum ExecutorError { 104 | #[fail(display = "fail create directory")] 105 | CreateDirectroyError, 106 | #[fail(display = "fail initialize git repository")] 107 | GitInitializeError, 108 | } 109 | impl Executor for DefaultExecutor { 110 | fn execute(&self, commands: Vec) -> Result<(), ExecutorError> { 111 | let error = commands.into_iter().find_map(|command| { 112 | let result = match command { 113 | CommandType::CreateDirectory { path } => { 114 | create_directory(&path).map_err(|_| ExecutorError::CreateDirectroyError {}) 115 | } 116 | CommandType::InitializeGit { 117 | first_commit_message, 118 | path, 119 | } => initialize_git(&first_commit_message, &path) 120 | .map_err(|_| ExecutorError::GitInitializeError {}), 121 | }; 122 | if result.is_err() { 123 | Some(result) 124 | } else { 125 | None 126 | } 127 | }); 128 | match error { 129 | None => Ok(()), 130 | Some(e) => match e { 131 | Err(e) => Err(e), 132 | _ => Ok(()), 133 | }, 134 | } 135 | } 136 | } 137 | 138 | #[derive(Deserialize, Debug)] 139 | pub struct Config { 140 | user_name: Option, 141 | ghq_root: Option, 142 | mkrepo_service: String, 143 | mkrepo_username: Option, 144 | } 145 | 146 | #[derive(Debug, Fail)] 147 | pub enum FailLoadGitConfigError { 148 | #[fail(display = "fail load default git config")] 149 | LoadError, 150 | #[fail(display = "fail git config --list --null stdout parse")] 151 | ParseError, 152 | #[fail(display = "fail git command execute error")] 153 | FailGitCommandExecuteError, 154 | #[fail(display = "Not found default service setting")] 155 | NotFoundDefaultServiceSetting, 156 | } 157 | 158 | impl std::convert::From for FailLoadGitConfigError { 159 | fn from(_: git2::Error) -> Self { 160 | Self::LoadError {} 161 | } 162 | } 163 | 164 | pub fn fetch_value(config: &ConfigEntries, key_name: &str) -> Option { 165 | let mut matches = config.filter_map(|e| { 166 | if let Ok(entry) = e.as_ref() { 167 | match (&entry.name(), &entry.value()) { 168 | (Some(n), Some(v)) => { 169 | if n == &key_name { 170 | Some(String::from(*v)) 171 | } else { 172 | None 173 | } 174 | } 175 | _ => None, 176 | } 177 | } else { 178 | None 179 | } 180 | }); 181 | matches.next() 182 | } 183 | pub fn load_git_config(config: GitConfig) -> Result { 184 | if let Some(service) = fetch_value(&config.entries(None)?, "mkrepo.service") { 185 | Ok(Config { 186 | user_name: fetch_value(&config.entries(None)?, "user.name"), 187 | mkrepo_service: service, 188 | mkrepo_username: fetch_value(&config.entries(None)?, "mkrepo.username"), 189 | ghq_root: fetch_value(&config.entries(None)?, "ghq.root") 190 | .map(|root| PathBuf::from(tilde(&root).as_ref())), 191 | }) 192 | } else { 193 | Err(FailLoadGitConfigError::NotFoundDefaultServiceSetting) 194 | } 195 | } 196 | 197 | pub fn build_commands<'a>( 198 | config: Config, 199 | author: Option<&'a str>, 200 | service_name: Option<&'a str>, 201 | repository_name: &'a str, 202 | first_commit_message: Option<&'a str>, 203 | ) -> Result, Error> { 204 | let parent_path = config.ghq_root.as_ref().expect("ghq.root is not defined."); 205 | let service = match service_name { 206 | Some(n) => n, 207 | None => config.mkrepo_service.as_ref(), 208 | }; 209 | let repository_author = author 210 | .or_else(|| config.mkrepo_username.as_ref().map(Deref::deref)) 211 | .or_else(|| config.user_name.as_ref().map(Deref::deref)) 212 | .unwrap_or_else(|| { 213 | unimplemented!("`--author`, `mkrepo.username`, or `user.name` required") 214 | }); 215 | let repository_path = parent_path 216 | .join(service) 217 | .join(repository_author) 218 | .join(repository_name); 219 | 220 | Ok(vec![ 221 | CommandType::CreateDirectory { 222 | path: normalize_seps(repository_path.to_str().unwrap()), 223 | }, 224 | CommandType::InitializeGit { 225 | path: normalize_seps(repository_path.to_str().unwrap()), 226 | first_commit_message: String::from(match first_commit_message { 227 | Some(x) => x, 228 | None => "Initial commit", 229 | }), 230 | }, 231 | ]) 232 | } 233 | 234 | fn normalize_seps(path: &str) -> String { 235 | path.replace(path::is_separator, &path::MAIN_SEPARATOR.to_string()) 236 | } 237 | #[cfg(test)] 238 | mod tests { 239 | use super::*; 240 | use std::fs::File; 241 | use tempfile::TempDir; 242 | 243 | #[test] 244 | pub fn build_commands_return_to_create_directory_and_initialize_git() { 245 | let c = Config { 246 | user_name: Some("himanoa".to_owned()), 247 | ghq_root: Some(normalize_seps("/home/user/src").into()), 248 | mkrepo_service: "github.com".to_owned(), 249 | mkrepo_username: None, 250 | }; 251 | assert_eq!( 252 | build_commands(c, None, None, "mkrepo", Some("Initial commit")).unwrap(), 253 | vec![ 254 | CommandType::CreateDirectory { 255 | path: normalize_seps("/home/user/src/github.com/himanoa/mkrepo") 256 | }, 257 | CommandType::InitializeGit { 258 | first_commit_message: String::from("Initial commit"), 259 | path: normalize_seps("/home/user/src/github.com/himanoa/mkrepo") 260 | } 261 | ] 262 | ); 263 | } 264 | 265 | #[test] 266 | pub fn build_commands_return_to_create_directory_and_initialize_git_when_first_commit_message_is_none( 267 | ) { 268 | let c = Config { 269 | user_name: Some("himanoa".to_owned()), 270 | ghq_root: Some("/home/user/src".into()), 271 | mkrepo_service: "github.com".to_owned(), 272 | mkrepo_username: None, 273 | }; 274 | assert_eq!( 275 | build_commands(c, None, None, "mkrepo", None).unwrap(), 276 | vec![ 277 | CommandType::CreateDirectory { 278 | path: normalize_seps("/home/user/src/github.com/himanoa/mkrepo") 279 | }, 280 | CommandType::InitializeGit { 281 | first_commit_message: String::from("Initial commit"), 282 | path: normalize_seps("/home/user/src/github.com/himanoa/mkrepo") 283 | } 284 | ] 285 | ); 286 | } 287 | 288 | #[test] 289 | pub fn build_commands_return_to_create_directory_and_initialize_git_when_author_is_exist() { 290 | let c = Config { 291 | user_name: Some("himanoa".to_owned()), 292 | ghq_root: Some(normalize_seps("/home/user/src").into()), 293 | mkrepo_service: "github.com".to_owned(), 294 | mkrepo_username: None, 295 | }; 296 | assert_eq!( 297 | build_commands(c, Some("h1manoa"), None, "mkrepo", None).unwrap(), 298 | vec![ 299 | CommandType::CreateDirectory { 300 | path: normalize_seps("/home/user/src/github.com/h1manoa/mkrepo") 301 | }, 302 | CommandType::InitializeGit { 303 | first_commit_message: String::from("Initial commit"), 304 | path: normalize_seps("/home/user/src/github.com/h1manoa/mkrepo") 305 | } 306 | ] 307 | ); 308 | } 309 | #[test] 310 | pub fn build_commands_return_to_create_directory_and_initialize_git_when_service_is_exist() 311 | { 312 | let c = Config { 313 | user_name: Some("himanoa".to_owned()), 314 | ghq_root: Some(normalize_seps("/home/user/src").into()), 315 | mkrepo_service: "github.com".to_owned(), 316 | mkrepo_username: None, 317 | }; 318 | assert_eq!( 319 | build_commands(c, None, Some("bitbucket.com"), "mkrepo", None).unwrap(), 320 | vec![ 321 | CommandType::CreateDirectory { 322 | path: normalize_seps("/home/user/src/bitbucket.com/himanoa/mkrepo") 323 | }, 324 | CommandType::InitializeGit { 325 | first_commit_message: String::from("Initial commit"), 326 | path: normalize_seps("/home/user/src/bitbucket.com/himanoa/mkrepo") 327 | } 328 | ] 329 | ); 330 | } 331 | #[test] 332 | pub fn fetch_value_return_to_value() { 333 | let td = TempDir::new().unwrap(); 334 | let path = td.path().join("foo"); 335 | File::create(&path).unwrap(); 336 | let mut c = GitConfig::open(&path).unwrap(); 337 | assert!(c.get_str("a.foo").is_err()); 338 | c.set_str("a.foo", "foobar1").unwrap(); 339 | c.set_str("a.bar", "foobar2").unwrap(); 340 | assert_eq!( 341 | fetch_value(&c.entries(None).unwrap(), "a.foo"), 342 | Some(String::from("foobar1")) 343 | ); 344 | assert_eq!( 345 | fetch_value(&c.entries(None).unwrap(), "a.bar"), 346 | Some(String::from("foobar2")) 347 | ); 348 | } 349 | } 350 | } 351 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use clap::{App, Arg}; 2 | use git2::Config as GitConfig; 3 | use mkrepo::makerepo::{ 4 | build_commands, load_git_config, DefaultExecutor, DryRunExecutor, Executor, 5 | }; 6 | use std::process::exit; 7 | 8 | fn main() { 9 | let matchers = App::new("Make project directory for ghq style.") 10 | .version(env!("CARGO_PKG_VERSION")) 11 | .arg( 12 | Arg::with_name("repository") 13 | .help("Repository name") 14 | .required(true) 15 | .index(1), 16 | ) 17 | .arg( 18 | Arg::with_name("author") 19 | .help("repository author name") 20 | .required(false) 21 | .short("a") 22 | .takes_value(true) 23 | .long("author"), 24 | ) 25 | .arg( 26 | Arg::with_name("service") 27 | .help("service name") 28 | .required(false) 29 | .short("s") 30 | .takes_value(true) 31 | .long("service"), 32 | ) 33 | .arg( 34 | Arg::with_name("first_commit_message") 35 | .help("first_commit_message name") 36 | .required(false) 37 | .takes_value(true) 38 | .short("m"), 39 | ) 40 | .arg( 41 | Arg::with_name("dry_run") 42 | .help("dru run") 43 | .required(false) 44 | .short("d"), 45 | ) 46 | .get_matches(); 47 | let config = match load_git_config(GitConfig::open_default().unwrap()) { 48 | Ok(g) => g, 49 | Err(e) => { 50 | eprintln!("{}", e); 51 | panic!() 52 | } 53 | }; 54 | 55 | match build_commands( 56 | config, 57 | matchers.value_of("author"), 58 | matchers.value_of("service"), 59 | matchers.value_of("repository").unwrap(), 60 | matchers.value_of("first_commit_message"), 61 | ) { 62 | Ok(commands) => { 63 | if matchers.is_present("dry_run") { 64 | let executor = DryRunExecutor::new(); 65 | match executor.execute(commands) { 66 | Ok(()) => (), 67 | Err(e) => { 68 | eprintln!("{}", e); 69 | exit(1) 70 | } 71 | }; 72 | } else { 73 | let executor = DefaultExecutor::new(); 74 | match executor.execute(commands) { 75 | Ok(()) => (), 76 | Err(e) => { 77 | eprintln!("{}", e); 78 | exit(1) 79 | } 80 | }; 81 | } 82 | } 83 | Err(e) => { 84 | eprintln!("{}", e); 85 | panic!() 86 | } 87 | } 88 | } 89 | --------------------------------------------------------------------------------