The dotfiles manager.
initial commit
4 files changed, +867 -0
+583-0Cargo.lock
| @@ -0,0 +1,583 @@ | ||
| 1 | +# This file is automatically @generated by Cargo. | |
| 2 | +# It is not intended for manual editing. | |
| 3 | +version = 4 | |
| 4 | + | |
| 5 | +[[package]] | |
| 6 | +name = "anstream" | |
| 7 | +version = "0.6.21" | |
| 8 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 9 | +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" | |
| 10 | +dependencies = [ | |
| 11 | + "anstyle", | |
| 12 | + "anstyle-parse", | |
| 13 | + "anstyle-query", | |
| 14 | + "anstyle-wincon", | |
| 15 | + "colorchoice", | |
| 16 | + "is_terminal_polyfill", | |
| 17 | + "utf8parse", | |
| 18 | +] | |
| 19 | + | |
| 20 | +[[package]] | |
| 21 | +name = "anstyle" | |
| 22 | +version = "1.0.13" | |
| 23 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 24 | +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" | |
| 25 | + | |
| 26 | +[[package]] | |
| 27 | +name = "anstyle-parse" | |
| 28 | +version = "0.2.7" | |
| 29 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 30 | +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" | |
| 31 | +dependencies = [ | |
| 32 | + "utf8parse", | |
| 33 | +] | |
| 34 | + | |
| 35 | +[[package]] | |
| 36 | +name = "anstyle-query" | |
| 37 | +version = "1.1.4" | |
| 38 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 39 | +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" | |
| 40 | +dependencies = [ | |
| 41 | + "windows-sys 0.60.2", | |
| 42 | +] | |
| 43 | + | |
| 44 | +[[package]] | |
| 45 | +name = "anstyle-wincon" | |
| 46 | +version = "3.0.10" | |
| 47 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 48 | +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" | |
| 49 | +dependencies = [ | |
| 50 | + "anstyle", | |
| 51 | + "once_cell_polyfill", | |
| 52 | + "windows-sys 0.60.2", | |
| 53 | +] | |
| 54 | + | |
| 55 | +[[package]] | |
| 56 | +name = "anyhow" | |
| 57 | +version = "1.0.100" | |
| 58 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 59 | +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" | |
| 60 | + | |
| 61 | +[[package]] | |
| 62 | +name = "bitflags" | |
| 63 | +version = "2.10.0" | |
| 64 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 65 | +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" | |
| 66 | + | |
| 67 | +[[package]] | |
| 68 | +name = "cfg-if" | |
| 69 | +version = "1.0.4" | |
| 70 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 71 | +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" | |
| 72 | + | |
| 73 | +[[package]] | |
| 74 | +name = "clap" | |
| 75 | +version = "4.5.51" | |
| 76 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 77 | +checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" | |
| 78 | +dependencies = [ | |
| 79 | + "clap_builder", | |
| 80 | + "clap_derive", | |
| 81 | +] | |
| 82 | + | |
| 83 | +[[package]] | |
| 84 | +name = "clap_builder" | |
| 85 | +version = "4.5.51" | |
| 86 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 87 | +checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" | |
| 88 | +dependencies = [ | |
| 89 | + "anstream", | |
| 90 | + "anstyle", | |
| 91 | + "clap_lex", | |
| 92 | + "strsim", | |
| 93 | +] | |
| 94 | + | |
| 95 | +[[package]] | |
| 96 | +name = "clap_complete" | |
| 97 | +version = "4.5.60" | |
| 98 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 99 | +checksum = "8e602857739c5a4291dfa33b5a298aeac9006185229a700e5810a3ef7272d971" | |
| 100 | +dependencies = [ | |
| 101 | + "clap", | |
| 102 | +] | |
| 103 | + | |
| 104 | +[[package]] | |
| 105 | +name = "clap_derive" | |
| 106 | +version = "4.5.49" | |
| 107 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 108 | +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" | |
| 109 | +dependencies = [ | |
| 110 | + "heck", | |
| 111 | + "proc-macro2", | |
| 112 | + "quote", | |
| 113 | + "syn", | |
| 114 | +] | |
| 115 | + | |
| 116 | +[[package]] | |
| 117 | +name = "clap_lex" | |
| 118 | +version = "0.7.6" | |
| 119 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 120 | +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" | |
| 121 | + | |
| 122 | +[[package]] | |
| 123 | +name = "colorchoice" | |
| 124 | +version = "1.0.4" | |
| 125 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 126 | +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" | |
| 127 | + | |
| 128 | +[[package]] | |
| 129 | +name = "dirs" | |
| 130 | +version = "5.0.1" | |
| 131 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 132 | +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" | |
| 133 | +dependencies = [ | |
| 134 | + "dirs-sys", | |
| 135 | +] | |
| 136 | + | |
| 137 | +[[package]] | |
| 138 | +name = "dirs-sys" | |
| 139 | +version = "0.4.1" | |
| 140 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 141 | +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" | |
| 142 | +dependencies = [ | |
| 143 | + "libc", | |
| 144 | + "option-ext", | |
| 145 | + "redox_users", | |
| 146 | + "windows-sys 0.48.0", | |
| 147 | +] | |
| 148 | + | |
| 149 | +[[package]] | |
| 150 | +name = "dotman" | |
| 151 | +version = "0.1.0" | |
| 152 | +dependencies = [ | |
| 153 | + "anyhow", | |
| 154 | + "clap", | |
| 155 | + "clap_complete", | |
| 156 | + "dirs", | |
| 157 | + "which", | |
| 158 | +] | |
| 159 | + | |
| 160 | +[[package]] | |
| 161 | +name = "either" | |
| 162 | +version = "1.15.0" | |
| 163 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 164 | +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" | |
| 165 | + | |
| 166 | +[[package]] | |
| 167 | +name = "errno" | |
| 168 | +version = "0.3.14" | |
| 169 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 170 | +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" | |
| 171 | +dependencies = [ | |
| 172 | + "libc", | |
| 173 | + "windows-sys 0.61.2", | |
| 174 | +] | |
| 175 | + | |
| 176 | +[[package]] | |
| 177 | +name = "getrandom" | |
| 178 | +version = "0.2.16" | |
| 179 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 180 | +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" | |
| 181 | +dependencies = [ | |
| 182 | + "cfg-if", | |
| 183 | + "libc", | |
| 184 | + "wasi", | |
| 185 | +] | |
| 186 | + | |
| 187 | +[[package]] | |
| 188 | +name = "heck" | |
| 189 | +version = "0.5.0" | |
| 190 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 191 | +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" | |
| 192 | + | |
| 193 | +[[package]] | |
| 194 | +name = "home" | |
| 195 | +version = "0.5.12" | |
| 196 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 197 | +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" | |
| 198 | +dependencies = [ | |
| 199 | + "windows-sys 0.61.2", | |
| 200 | +] | |
| 201 | + | |
| 202 | +[[package]] | |
| 203 | +name = "is_terminal_polyfill" | |
| 204 | +version = "1.70.2" | |
| 205 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 206 | +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" | |
| 207 | + | |
| 208 | +[[package]] | |
| 209 | +name = "libc" | |
| 210 | +version = "0.2.177" | |
| 211 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 212 | +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" | |
| 213 | + | |
| 214 | +[[package]] | |
| 215 | +name = "libredox" | |
| 216 | +version = "0.1.10" | |
| 217 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 218 | +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" | |
| 219 | +dependencies = [ | |
| 220 | + "bitflags", | |
| 221 | + "libc", | |
| 222 | +] | |
| 223 | + | |
| 224 | +[[package]] | |
| 225 | +name = "linux-raw-sys" | |
| 226 | +version = "0.4.15" | |
| 227 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 228 | +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" | |
| 229 | + | |
| 230 | +[[package]] | |
| 231 | +name = "once_cell_polyfill" | |
| 232 | +version = "1.70.2" | |
| 233 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 234 | +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" | |
| 235 | + | |
| 236 | +[[package]] | |
| 237 | +name = "option-ext" | |
| 238 | +version = "0.2.0" | |
| 239 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 240 | +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" | |
| 241 | + | |
| 242 | +[[package]] | |
| 243 | +name = "proc-macro2" | |
| 244 | +version = "1.0.103" | |
| 245 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 246 | +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" | |
| 247 | +dependencies = [ | |
| 248 | + "unicode-ident", | |
| 249 | +] | |
| 250 | + | |
| 251 | +[[package]] | |
| 252 | +name = "quote" | |
| 253 | +version = "1.0.42" | |
| 254 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 255 | +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" | |
| 256 | +dependencies = [ | |
| 257 | + "proc-macro2", | |
| 258 | +] | |
| 259 | + | |
| 260 | +[[package]] | |
| 261 | +name = "redox_users" | |
| 262 | +version = "0.4.6" | |
| 263 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 264 | +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" | |
| 265 | +dependencies = [ | |
| 266 | + "getrandom", | |
| 267 | + "libredox", | |
| 268 | + "thiserror", | |
| 269 | +] | |
| 270 | + | |
| 271 | +[[package]] | |
| 272 | +name = "rustix" | |
| 273 | +version = "0.38.44" | |
| 274 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 275 | +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" | |
| 276 | +dependencies = [ | |
| 277 | + "bitflags", | |
| 278 | + "errno", | |
| 279 | + "libc", | |
| 280 | + "linux-raw-sys", | |
| 281 | + "windows-sys 0.59.0", | |
| 282 | +] | |
| 283 | + | |
| 284 | +[[package]] | |
| 285 | +name = "strsim" | |
| 286 | +version = "0.11.1" | |
| 287 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 288 | +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" | |
| 289 | + | |
| 290 | +[[package]] | |
| 291 | +name = "syn" | |
| 292 | +version = "2.0.109" | |
| 293 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 294 | +checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f" | |
| 295 | +dependencies = [ | |
| 296 | + "proc-macro2", | |
| 297 | + "quote", | |
| 298 | + "unicode-ident", | |
| 299 | +] | |
| 300 | + | |
| 301 | +[[package]] | |
| 302 | +name = "thiserror" | |
| 303 | +version = "1.0.69" | |
| 304 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 305 | +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" | |
| 306 | +dependencies = [ | |
| 307 | + "thiserror-impl", | |
| 308 | +] | |
| 309 | + | |
| 310 | +[[package]] | |
| 311 | +name = "thiserror-impl" | |
| 312 | +version = "1.0.69" | |
| 313 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 314 | +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" | |
| 315 | +dependencies = [ | |
| 316 | + "proc-macro2", | |
| 317 | + "quote", | |
| 318 | + "syn", | |
| 319 | +] | |
| 320 | + | |
| 321 | +[[package]] | |
| 322 | +name = "unicode-ident" | |
| 323 | +version = "1.0.22" | |
| 324 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 325 | +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" | |
| 326 | + | |
| 327 | +[[package]] | |
| 328 | +name = "utf8parse" | |
| 329 | +version = "0.2.2" | |
| 330 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 331 | +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" | |
| 332 | + | |
| 333 | +[[package]] | |
| 334 | +name = "wasi" | |
| 335 | +version = "0.11.1+wasi-snapshot-preview1" | |
| 336 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 337 | +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" | |
| 338 | + | |
| 339 | +[[package]] | |
| 340 | +name = "which" | |
| 341 | +version = "6.0.3" | |
| 342 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 343 | +checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" | |
| 344 | +dependencies = [ | |
| 345 | + "either", | |
| 346 | + "home", | |
| 347 | + "rustix", | |
| 348 | + "winsafe", | |
| 349 | +] | |
| 350 | + | |
| 351 | +[[package]] | |
| 352 | +name = "windows-link" | |
| 353 | +version = "0.2.1" | |
| 354 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 355 | +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" | |
| 356 | + | |
| 357 | +[[package]] | |
| 358 | +name = "windows-sys" | |
| 359 | +version = "0.48.0" | |
| 360 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 361 | +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" | |
| 362 | +dependencies = [ | |
| 363 | + "windows-targets 0.48.5", | |
| 364 | +] | |
| 365 | + | |
| 366 | +[[package]] | |
| 367 | +name = "windows-sys" | |
| 368 | +version = "0.59.0" | |
| 369 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 370 | +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" | |
| 371 | +dependencies = [ | |
| 372 | + "windows-targets 0.52.6", | |
| 373 | +] | |
| 374 | + | |
| 375 | +[[package]] | |
| 376 | +name = "windows-sys" | |
| 377 | +version = "0.60.2" | |
| 378 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 379 | +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" | |
| 380 | +dependencies = [ | |
| 381 | + "windows-targets 0.53.5", | |
| 382 | +] | |
| 383 | + | |
| 384 | +[[package]] | |
| 385 | +name = "windows-sys" | |
| 386 | +version = "0.61.2" | |
| 387 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 388 | +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" | |
| 389 | +dependencies = [ | |
| 390 | + "windows-link", | |
| 391 | +] | |
| 392 | + | |
| 393 | +[[package]] | |
| 394 | +name = "windows-targets" | |
| 395 | +version = "0.48.5" | |
| 396 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 397 | +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" | |
| 398 | +dependencies = [ | |
| 399 | + "windows_aarch64_gnullvm 0.48.5", | |
| 400 | + "windows_aarch64_msvc 0.48.5", | |
| 401 | + "windows_i686_gnu 0.48.5", | |
| 402 | + "windows_i686_msvc 0.48.5", | |
| 403 | + "windows_x86_64_gnu 0.48.5", | |
| 404 | + "windows_x86_64_gnullvm 0.48.5", | |
| 405 | + "windows_x86_64_msvc 0.48.5", | |
| 406 | +] | |
| 407 | + | |
| 408 | +[[package]] | |
| 409 | +name = "windows-targets" | |
| 410 | +version = "0.52.6" | |
| 411 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 412 | +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" | |
| 413 | +dependencies = [ | |
| 414 | + "windows_aarch64_gnullvm 0.52.6", | |
| 415 | + "windows_aarch64_msvc 0.52.6", | |
| 416 | + "windows_i686_gnu 0.52.6", | |
| 417 | + "windows_i686_gnullvm 0.52.6", | |
| 418 | + "windows_i686_msvc 0.52.6", | |
| 419 | + "windows_x86_64_gnu 0.52.6", | |
| 420 | + "windows_x86_64_gnullvm 0.52.6", | |
| 421 | + "windows_x86_64_msvc 0.52.6", | |
| 422 | +] | |
| 423 | + | |
| 424 | +[[package]] | |
| 425 | +name = "windows-targets" | |
| 426 | +version = "0.53.5" | |
| 427 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 428 | +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" | |
| 429 | +dependencies = [ | |
| 430 | + "windows-link", | |
| 431 | + "windows_aarch64_gnullvm 0.53.1", | |
| 432 | + "windows_aarch64_msvc 0.53.1", | |
| 433 | + "windows_i686_gnu 0.53.1", | |
| 434 | + "windows_i686_gnullvm 0.53.1", | |
| 435 | + "windows_i686_msvc 0.53.1", | |
| 436 | + "windows_x86_64_gnu 0.53.1", | |
| 437 | + "windows_x86_64_gnullvm 0.53.1", | |
| 438 | + "windows_x86_64_msvc 0.53.1", | |
| 439 | +] | |
| 440 | + | |
| 441 | +[[package]] | |
| 442 | +name = "windows_aarch64_gnullvm" | |
| 443 | +version = "0.48.5" | |
| 444 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 445 | +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" | |
| 446 | + | |
| 447 | +[[package]] | |
| 448 | +name = "windows_aarch64_gnullvm" | |
| 449 | +version = "0.52.6" | |
| 450 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 451 | +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" | |
| 452 | + | |
| 453 | +[[package]] | |
| 454 | +name = "windows_aarch64_gnullvm" | |
| 455 | +version = "0.53.1" | |
| 456 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 457 | +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" | |
| 458 | + | |
| 459 | +[[package]] | |
| 460 | +name = "windows_aarch64_msvc" | |
| 461 | +version = "0.48.5" | |
| 462 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 463 | +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" | |
| 464 | + | |
| 465 | +[[package]] | |
| 466 | +name = "windows_aarch64_msvc" | |
| 467 | +version = "0.52.6" | |
| 468 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 469 | +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" | |
| 470 | + | |
| 471 | +[[package]] | |
| 472 | +name = "windows_aarch64_msvc" | |
| 473 | +version = "0.53.1" | |
| 474 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 475 | +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" | |
| 476 | + | |
| 477 | +[[package]] | |
| 478 | +name = "windows_i686_gnu" | |
| 479 | +version = "0.48.5" | |
| 480 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 481 | +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" | |
| 482 | + | |
| 483 | +[[package]] | |
| 484 | +name = "windows_i686_gnu" | |
| 485 | +version = "0.52.6" | |
| 486 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 487 | +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" | |
| 488 | + | |
| 489 | +[[package]] | |
| 490 | +name = "windows_i686_gnu" | |
| 491 | +version = "0.53.1" | |
| 492 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 493 | +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" | |
| 494 | + | |
| 495 | +[[package]] | |
| 496 | +name = "windows_i686_gnullvm" | |
| 497 | +version = "0.52.6" | |
| 498 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 499 | +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" | |
| 500 | + | |
| 501 | +[[package]] | |
| 502 | +name = "windows_i686_gnullvm" | |
| 503 | +version = "0.53.1" | |
| 504 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 505 | +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" | |
| 506 | + | |
| 507 | +[[package]] | |
| 508 | +name = "windows_i686_msvc" | |
| 509 | +version = "0.48.5" | |
| 510 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 511 | +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" | |
| 512 | + | |
| 513 | +[[package]] | |
| 514 | +name = "windows_i686_msvc" | |
| 515 | +version = "0.52.6" | |
| 516 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 517 | +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" | |
| 518 | + | |
| 519 | +[[package]] | |
| 520 | +name = "windows_i686_msvc" | |
| 521 | +version = "0.53.1" | |
| 522 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 523 | +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" | |
| 524 | + | |
| 525 | +[[package]] | |
| 526 | +name = "windows_x86_64_gnu" | |
| 527 | +version = "0.48.5" | |
| 528 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 529 | +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" | |
| 530 | + | |
| 531 | +[[package]] | |
| 532 | +name = "windows_x86_64_gnu" | |
| 533 | +version = "0.52.6" | |
| 534 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 535 | +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" | |
| 536 | + | |
| 537 | +[[package]] | |
| 538 | +name = "windows_x86_64_gnu" | |
| 539 | +version = "0.53.1" | |
| 540 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 541 | +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" | |
| 542 | + | |
| 543 | +[[package]] | |
| 544 | +name = "windows_x86_64_gnullvm" | |
| 545 | +version = "0.48.5" | |
| 546 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 547 | +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" | |
| 548 | + | |
| 549 | +[[package]] | |
| 550 | +name = "windows_x86_64_gnullvm" | |
| 551 | +version = "0.52.6" | |
| 552 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 553 | +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" | |
| 554 | + | |
| 555 | +[[package]] | |
| 556 | +name = "windows_x86_64_gnullvm" | |
| 557 | +version = "0.53.1" | |
| 558 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 559 | +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" | |
| 560 | + | |
| 561 | +[[package]] | |
| 562 | +name = "windows_x86_64_msvc" | |
| 563 | +version = "0.48.5" | |
| 564 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 565 | +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" | |
| 566 | + | |
| 567 | +[[package]] | |
| 568 | +name = "windows_x86_64_msvc" | |
| 569 | +version = "0.52.6" | |
| 570 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 571 | +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" | |
| 572 | + | |
| 573 | +[[package]] | |
| 574 | +name = "windows_x86_64_msvc" | |
| 575 | +version = "0.53.1" | |
| 576 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 577 | +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" | |
| 578 | + | |
| 579 | +[[package]] | |
| 580 | +name = "winsafe" | |
| 581 | +version = "0.0.19" | |
| 582 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 583 | +checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" |
+11-0Cargo.toml
| @@ -0,0 +1,11 @@ | ||
| 1 | +[package] | |
| 2 | +name = "dotman" | |
| 3 | +version = "0.1.0" | |
| 4 | +edition = "2021" | |
| 5 | + | |
| 6 | +[dependencies] | |
| 7 | +anyhow = "1.0" | |
| 8 | +clap = { version = "4.5", features = ["derive"] } | |
| 9 | +clap_complete = "4.5" | |
| 10 | +dirs = "5" | |
| 11 | +which = "6" |
+27-0README.md
| @@ -0,0 +1,27 @@ | ||
| 1 | +dotman | |
| 2 | +===== | |
| 3 | + | |
| 4 | +Small Rust CLI to manage dotfile-like repos under `/usr/local/share/dotman`, and link Neovim config. | |
| 5 | + | |
| 6 | +Commands | |
| 7 | +- `dotman install <repo-url>`: Clones the repo into `/usr/local/share/dotman/<name>` where `<name>` is derived from the URL (e.g., `https://github.com/hygo-nvim` -> `hygo-nvim`). Requires write access to `/usr/local/share/dotman` (use sudo if needed). | |
| 8 | +- `dotman link <name> <target>`: Deletes `~/.config/<target>` (if present) and creates a symlink to `/usr/local/share/dotman/<name>`. This is universal; e.g., `dotman link hygo-nvim nvim`, `dotman link my-fish fish`. | |
| 9 | +- `dotman update`: Runs `git pull --ff-only` for every git repo inside `/usr/local/share/dotman`. | |
| 10 | +- `dotman completions <SHELL>`: Prints shell completion script to stdout. Supported shells: bash, zsh, fish, powershell, elvish. | |
| 11 | + | |
| 12 | +Usage examples | |
| 13 | +- Install: `dotman install https://github.com/hygo-nvim` | |
| 14 | +- Link Neovim: `dotman link hygo-nvim nvim` | |
| 15 | +- Link Fish: `dotman link my-fish fish` | |
| 16 | +- Update all: `dotman update` | |
| 17 | + | |
| 18 | +Completions | |
| 19 | +- Bash: `dotman completions bash > /etc/bash_completion.d/dotman` (may require sudo) | |
| 20 | +- Zsh: `dotman completions zsh > "${fpath[1]}/_dotman"` | |
| 21 | +- Fish: `dotman completions fish > ~/.config/fish/completions/dotman.fish` | |
| 22 | +- Powershell: `dotman completions powershell | Out-String | Set-Content $PROFILE.CurrentUserAllHosts` | |
| 23 | +- Elvish: `dotman completions elvish > ~/.elvish/lib/dotman.elv` | |
| 24 | + | |
| 25 | +Notes | |
| 26 | +- Ensure `git` is installed and in PATH. | |
| 27 | +- Installing and updating may require `sudo` due to the `/usr/local/share/dotman` location. |
+246-0src/main.rs
| @@ -0,0 +1,246 @@ | ||
| 1 | +use anyhow::{bail, Context, Result}; | |
| 2 | +use clap::{Args, Parser, Subcommand, ValueEnum}; | |
| 3 | +use clap_complete::{generate, shells}; | |
| 4 | +use std::fs; | |
| 5 | +use std::io; | |
| 6 | +use std::path::Path; | |
| 7 | +use std::process::Command; | |
| 8 | + | |
| 9 | +const DOTMAN_DIR: &str = "/usr/local/share/dotman"; | |
| 10 | + | |
| 11 | +#[derive(Parser)] | |
| 12 | +#[command(name = "dotman", about = "Manage dotfile repos and links", version)] | |
| 13 | +#[command(arg_required_else_help = true)] | |
| 14 | +struct Cli { | |
| 15 | + #[command(subcommand)] | |
| 16 | + command: Commands, | |
| 17 | +} | |
| 18 | + | |
| 19 | +#[derive(Subcommand)] | |
| 20 | +enum Commands { | |
| 21 | + /// Clone a git repository into the dotman store | |
| 22 | + Install(InstallArgs), | |
| 23 | + /// Replace ~/.config/<target> with a symlink to a stored repo | |
| 24 | + Link(LinkArgs), | |
| 25 | + /// Pull latest changes for all stored repos | |
| 26 | + Update, | |
| 27 | + /// Generate shell completions to stdout (bash|zsh|fish|powershell|elvish) | |
| 28 | + Completions { shell: Shell }, | |
| 29 | +} | |
| 30 | + | |
| 31 | +#[derive(Args)] | |
| 32 | +struct InstallArgs { | |
| 33 | + /// Git repository URL, e.g. https://github.com/hygo-nvim | |
| 34 | + repo: String, | |
| 35 | +} | |
| 36 | + | |
| 37 | +#[derive(Args)] | |
| 38 | +struct LinkArgs { | |
| 39 | + /// Repository name stored under dotman (e.g. hygo-nvim) | |
| 40 | + name: String, | |
| 41 | + /// Target directory name under ~/.config (e.g. nvim, alacritty, fish) | |
| 42 | + target: String, | |
| 43 | +} | |
| 44 | + | |
| 45 | +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] | |
| 46 | +enum Shell { | |
| 47 | + Bash, | |
| 48 | + Zsh, | |
| 49 | + Fish, | |
| 50 | + PowerShell, | |
| 51 | + Elvish, | |
| 52 | +} | |
| 53 | + | |
| 54 | +fn main() -> Result<()> { | |
| 55 | + let cli = Cli::parse(); | |
| 56 | + | |
| 57 | + match cli.command { | |
| 58 | + Commands::Install(args) => cmd_install(&args.repo), | |
| 59 | + Commands::Link(args) => cmd_link(&args.name, &args.target), | |
| 60 | + Commands::Update => cmd_update(), | |
| 61 | + Commands::Completions { shell } => cmd_completions(shell), | |
| 62 | + } | |
| 63 | +} | |
| 64 | + | |
| 65 | +fn ensure_dotman_dir() -> Result<()> { | |
| 66 | + let path = Path::new(DOTMAN_DIR); | |
| 67 | + if !path.exists() { | |
| 68 | + fs::create_dir_all(path) | |
| 69 | + .with_context(|| format!("Failed creating {} (need sudo?)", DOTMAN_DIR))?; | |
| 70 | + } | |
| 71 | + Ok(()) | |
| 72 | +} | |
| 73 | + | |
| 74 | +fn derive_repo_name(repo_url: &str) -> String { | |
| 75 | + let trimmed = repo_url.trim_end_matches('/') | |
| 76 | + .trim_end_matches(".git"); | |
| 77 | + trimmed | |
| 78 | + .rsplit('/') | |
| 79 | + .next() | |
| 80 | + .unwrap_or(trimmed) | |
| 81 | + .to_string() | |
| 82 | +} | |
| 83 | + | |
| 84 | +fn cmd_install(repo: &str) -> Result<()> { | |
| 85 | + ensure_dotman_dir()?; | |
| 86 | + | |
| 87 | + // Determine repo name | |
| 88 | + let name = derive_repo_name(repo); | |
| 89 | + if name.is_empty() { | |
| 90 | + bail!("Could not infer repository name from URL: {}", repo); | |
| 91 | + } | |
| 92 | + | |
| 93 | + let dest = Path::new(DOTMAN_DIR).join(&name); | |
| 94 | + if dest.exists() { | |
| 95 | + println!("Repo already exists: {}", dest.display()); | |
| 96 | + return Ok(()); | |
| 97 | + } | |
| 98 | + | |
| 99 | + // Ensure git is available | |
| 100 | + if which::which("git").is_err() { | |
| 101 | + bail!("git is not installed or not found in PATH"); | |
| 102 | + } | |
| 103 | + | |
| 104 | + println!("Cloning {} -> {}", repo, dest.display()); | |
| 105 | + let status = Command::new("git") | |
| 106 | + .args(["clone", repo, dest.to_string_lossy().as_ref()]) | |
| 107 | + .status() | |
| 108 | + .with_context(|| "Failed to spawn git clone")?; | |
| 109 | + | |
| 110 | + if !status.success() { | |
| 111 | + bail!("git clone failed with status: {}", status); | |
| 112 | + } | |
| 113 | + | |
| 114 | + println!("Installed {}", name); | |
| 115 | + Ok(()) | |
| 116 | +} | |
| 117 | + | |
| 118 | +fn cmd_link(name: &str, target_name: &str) -> Result<()> { | |
| 119 | + let source = Path::new(DOTMAN_DIR).join(name); | |
| 120 | + if !source.exists() { | |
| 121 | + bail!("Source repo not found: {}", source.display()); | |
| 122 | + } | |
| 123 | + | |
| 124 | + // Target: ~/.config/<target_name> | |
| 125 | + let home = dirs::home_dir().context("Unable to determine home directory")?; | |
| 126 | + let config_dir = home.join(".config"); | |
| 127 | + let target = config_dir.join(target_name); | |
| 128 | + | |
| 129 | + if !config_dir.exists() { | |
| 130 | + fs::create_dir_all(&config_dir) | |
| 131 | + .with_context(|| format!("Failed creating {}", config_dir.display()))?; | |
| 132 | + } | |
| 133 | + | |
| 134 | + if target.exists() || symlink_exists(&target) { | |
| 135 | + remove_path(&target) | |
| 136 | + .with_context(|| format!("Failed removing existing {}", target.display()))?; | |
| 137 | + } | |
| 138 | + | |
| 139 | + // Create symlink | |
| 140 | + #[cfg(unix)] | |
| 141 | + { | |
| 142 | + std::os::unix::fs::symlink(&source, &target) | |
| 143 | + .with_context(|| format!( | |
| 144 | + "Failed creating symlink {} -> {}", | |
| 145 | + target.display(), | |
| 146 | + source.display() | |
| 147 | + ))?; | |
| 148 | + } | |
| 149 | + #[cfg(windows)] | |
| 150 | + { | |
| 151 | + if source.is_dir() { | |
| 152 | + std::os::windows::fs::symlink_dir(&source, &target) | |
| 153 | + .with_context(|| format!( | |
| 154 | + "Failed creating symlink {} -> {}", | |
| 155 | + target.display(), | |
| 156 | + source.display() | |
| 157 | + ))?; | |
| 158 | + } else { | |
| 159 | + std::os::windows::fs::symlink_file(&source, &target) | |
| 160 | + .with_context(|| format!( | |
| 161 | + "Failed creating symlink {} -> {}", | |
| 162 | + target.display(), | |
| 163 | + source.display() | |
| 164 | + ))?; | |
| 165 | + } | |
| 166 | + } | |
| 167 | + | |
| 168 | + println!( | |
| 169 | + "Linked {} -> {}", | |
| 170 | + source.display(), | |
| 171 | + target.display() | |
| 172 | + ); | |
| 173 | + Ok(()) | |
| 174 | +} | |
| 175 | + | |
| 176 | +fn cmd_update() -> Result<()> { | |
| 177 | + ensure_dotman_dir()?; | |
| 178 | + if which::which("git").is_err() { | |
| 179 | + bail!("git is not installed or not found in PATH"); | |
| 180 | + } | |
| 181 | + | |
| 182 | + let root = Path::new(DOTMAN_DIR); | |
| 183 | + let mut updated = 0usize; | |
| 184 | + let mut skipped = 0usize; | |
| 185 | + | |
| 186 | + for entry in fs::read_dir(root).with_context(|| format!("Reading {}", DOTMAN_DIR))? { | |
| 187 | + let entry = entry?; | |
| 188 | + let path = entry.path(); | |
| 189 | + if !path.is_dir() { | |
| 190 | + continue; | |
| 191 | + } | |
| 192 | + if !path.join(".git").exists() { | |
| 193 | + skipped += 1; | |
| 194 | + continue; | |
| 195 | + } | |
| 196 | + | |
| 197 | + println!("Updating {}", path.display()); | |
| 198 | + let status = Command::new("git") | |
| 199 | + .args(["-C", path.to_string_lossy().as_ref(), "pull", "--ff-only"]) | |
| 200 | + .status() | |
| 201 | + .with_context(|| format!("Running git pull in {}", path.display()))?; | |
| 202 | + if status.success() { | |
| 203 | + updated += 1; | |
| 204 | + } else { | |
| 205 | + eprintln!("git pull failed in {} with status {}", path.display(), status); | |
| 206 | + } | |
| 207 | + } | |
| 208 | + | |
| 209 | + println!("Updated {} repositories (skipped {}).", updated, skipped); | |
| 210 | + Ok(()) | |
| 211 | +} | |
| 212 | + | |
| 213 | +fn cmd_completions(shell: Shell) -> Result<()> { | |
| 214 | + use clap::CommandFactory; | |
| 215 | + let mut cmd = Cli::command(); | |
| 216 | + let name = cmd.get_name().to_string(); | |
| 217 | + match shell { | |
| 218 | + Shell::Bash => generate(shells::Bash, &mut cmd, name, &mut io::stdout()), | |
| 219 | + Shell::Zsh => generate(shells::Zsh, &mut cmd, name, &mut io::stdout()), | |
| 220 | + Shell::Fish => generate(shells::Fish, &mut cmd, name, &mut io::stdout()), | |
| 221 | + Shell::PowerShell => generate(shells::PowerShell, &mut cmd, name, &mut io::stdout()), | |
| 222 | + Shell::Elvish => generate(shells::Elvish, &mut cmd, name, &mut io::stdout()), | |
| 223 | + } | |
| 224 | + Ok(()) | |
| 225 | +} | |
| 226 | + | |
| 227 | +fn symlink_exists(path: &Path) -> bool { | |
| 228 | + match fs::symlink_metadata(path) { | |
| 229 | + Ok(md) => md.file_type().is_symlink(), | |
| 230 | + Err(_) => false, | |
| 231 | + } | |
| 232 | +} | |
| 233 | + | |
| 234 | +fn remove_path(path: &Path) -> Result<()> { | |
| 235 | + match fs::symlink_metadata(path) { | |
| 236 | + Ok(md) if md.file_type().is_symlink() => { | |
| 237 | + fs::remove_file(path).with_context(|| format!("Removing symlink {}", path.display())) | |
| 238 | + } | |
| 239 | + Ok(md) if md.is_dir() => { | |
| 240 | + fs::remove_dir_all(path).with_context(|| format!("Removing directory {}", path.display())) | |
| 241 | + } | |
| 242 | + Ok(_md) => fs::remove_file(path).with_context(|| format!("Removing file {}", path.display())), | |
| 243 | + Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(()), | |
| 244 | + Err(e) => Err(e).with_context(|| format!("Accessing {}", path.display())), | |
| 245 | + } | |
| 246 | +} |