diff --git a/Cargo.lock b/Cargo.lock index 0bc2768..f879b96 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,47 +4,48 @@ version = 3 [[package]] name = "anstream" -version = "0.6.4" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.4" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] name = "anstyle-parse" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" dependencies = [ "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.1" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", "windows-sys", @@ -52,15 +53,15 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "clap" -version = "4.4.8" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", "clap_derive", @@ -68,9 +69,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.8" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstream", "anstyle", @@ -80,9 +81,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.7" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ "heck", "proc-macro2", @@ -92,27 +93,27 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] name = "either" -version = "1.9.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" [[package]] name = "errno" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ "libc", "windows-sys", @@ -120,9 +121,9 @@ dependencies = [ [[package]] name = "fs4" -version = "0.7.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29f9df8a11882c4e3335eb2d18a0137c505d9ca927470b0cac9c6f0ae07d28f7" +checksum = "21dabded2e32cd57ded879041205c60a4a4c4bab47bd0fd2fa8b01f30849f02b" dependencies = [ "rustix", "windows-sys", @@ -130,34 +131,40 @@ dependencies = [ [[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "home" -version = "0.5.5" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ "windows-sys", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + [[package]] name = "libc" -version = "0.2.150" +version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" [[package]] name = "linux-raw-sys" -version = "0.4.11" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "magoo" -version = "0.1.4" +version = "0.2.0" dependencies = [ "clap", "fs4", @@ -167,12 +174,6 @@ dependencies = [ "which", ] -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - [[package]] name = "pathdiff" version = "0.2.1" @@ -181,27 +182,27 @@ checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] [[package]] name = "rustix" -version = "0.38.25" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ "bitflags", "errno", @@ -212,15 +213,15 @@ dependencies = [ [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.39" +version = "2.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" dependencies = [ "proc-macro2", "quote", @@ -229,27 +230,27 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" dependencies = [ "proc-macro2", "quote", @@ -270,66 +271,44 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "which" -version = "5.0.0" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bf3ea8596f3a0dd5980b46430f2058dfe2c36a27ccfbb1845d6fbfcd9ba6e14" +checksum = "8211e4f58a2b2805adfbefbc07bab82958fc91e3836339b1ab7ae32465dce0d7" dependencies = [ "either", "home", - "once_cell", "rustix", - "windows-sys", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "winsafe", ] -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys", ] -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - [[package]] name = "windows-sys" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", + "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", @@ -338,42 +317,54 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "winsafe" +version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" diff --git a/Cargo.toml b/Cargo.toml index 19d7a3b..28fea48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "magoo" -version = "0.1.4" +version = "0.2.0" edition = "2021" description = "A wrapper for git submodule that simplifies the workflows" repository = "https://github.com/Pistonite/magoo" @@ -17,12 +17,12 @@ exclude = [ ] [dependencies] -clap = { version = "4.4.8", features = ["derive"], optional = true } -fs4 = "0.7.0" +clap = { version = "4.5.4", features = ["derive"], optional = true } +fs4 = "0.8.2" pathdiff = "0.2.1" -termcolor = "1.4.0" -thiserror = "1.0.50" -which = "5.0.0" +termcolor = "1.4.1" +thiserror = "1.0.59" +which = "6.0.1" [features] default = ["cli"] diff --git a/README.md b/README.md index 06d1a76..46fdbab 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,8 @@ The arguments for adding a submodule is very similar to [`git submodule add`](ht It's recommended to always specify the `BRANCH`. Git by default will use the `HEAD` branch, which is usually not what you want. +The submodule will not be cloned recursively when adding. If you need, run `magoo install` after the `add` to clone the recursive submodules. + ### Initialize/pull the submodules ```bash magoo install @@ -80,6 +82,8 @@ magoo install You should run `magoo install` every time you pull the changes from others, in case they were updated. It also deletes submodules that are deleted by others (by running `status --fix`, see below). +By default, submodules are installed recursively, you can use `--no-recursive` to only install the ones specified by the top-level repo. + ### Show submodule status ```bash magoo status [--long] [--fix] diff --git a/README.txtpp.md b/README.txtpp.md index 50a7e34..fbfffae 100644 --- a/README.txtpp.md +++ b/README.txtpp.md @@ -98,6 +98,8 @@ MAGOO needs to know the following to add a submodule.: It's recommended to always specify the `BRANCH`. Git by default will use the `HEAD` branch, which is usually not what you want. +The submodule will not be cloned recursively when adding. If you need, run `magoo install` after the `add` to clone the recursive submodules. + ### Initialize/pull the submodules ```bash magoo install @@ -108,6 +110,8 @@ MAGOO will ensure the submodules are cloned/updated to the commit stored in the You should run `magoo install` every time you pull the changes from others, in case they were updated. It also deletes submodules that are deleted by others (by running `status --fix`, see below). +By default, submodules are installed recursively, you can use `--no-recursive` to only install the ones specified by the top-level repo. + ### Show submodule status ```bash magoo status [--long] [--fix] diff --git a/Taskfile.yml b/Taskfile.yml index 34b1098..f28c1d0 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -14,3 +14,7 @@ tasks: - cargo fmt --all - txtpp README.md + test: + desc: Run tests + cmds: + - cargo test diff --git a/src/git.rs b/src/git.rs index 317ee90..43530db 100644 --- a/src/git.rs +++ b/src/git.rs @@ -181,7 +181,7 @@ impl GitContext { if print::is_verbose() { if let Some(stderr) = child.stderr.take() { let reader = BufReader::new(stderr); - for line in reader.lines().flatten() { + for line in reader.lines().map_while(Result::ok) { println_verbose!("{line}"); } } @@ -388,10 +388,14 @@ impl GitContext { } /// Runs `git submodule sync [-- ]`. Path should be from top level - pub fn submodule_sync(&self, path: Option<&str>) -> Result<(), GitError> { + pub fn submodule_sync(&self, path: Option<&str>, recursive: bool) -> Result<(), GitError> { let top_level_dir = self.top_level_dir()?.to_cmd_arg(); let mut args = vec!["-C", &top_level_dir, "submodule", "sync"]; + if recursive { + args.push("--recursive"); + } + if let Some(path) = path { args.push("--"); args.push(path); @@ -448,6 +452,7 @@ impl GitContext { path: Option<&str>, force: bool, remote: bool, + recursive: bool, ) -> Result<(), GitError> { let top_level_dir = self.top_level_dir()?.to_cmd_arg(); let mut args = vec!["-C", &top_level_dir, "submodule", "update"]; @@ -460,6 +465,11 @@ impl GitContext { args.push("--remote"); } + if recursive { + args.push("--init"); + args.push("--recursive"); + } + if let Some(path) = path { args.push("--"); args.push(path); @@ -531,6 +541,7 @@ impl Guard { .read(true) .write(true) .create(true) + .truncate(true) .open(path) .map_err(|e| GitError::LockFailed(path.to_cmd_arg(), e))?; file.lock_exclusive() diff --git a/src/lib.rs b/src/lib.rs index 2dbb670..7f7ac86 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,6 +30,7 @@ //! quiet: false, //! color: None, //! }, +//! delete: false, //! }; //! //! // don't need this if you don't need output to stdout @@ -57,6 +58,7 @@ //! quiet: false, //! color: None, //! }, +//! delete: false, //! }), //! dir: "my/repo".to_string(), //! }); @@ -184,6 +186,10 @@ pub struct StatusCommand { #[cfg_attr(feature = "cli", clap(long, short))] pub fix: bool, + /// Prefers deleting the submodule instead of installing it when fixing + #[cfg_attr(feature = "cli", clap(long, requires("fix")))] + pub delete: bool, + /// Print options #[cfg_attr(feature = "cli", clap(flatten))] pub options: PrintOptions, @@ -212,7 +218,7 @@ impl StatusCommand { } if self.fix { for submodule in flat_status.iter_mut() { - submodule.fix(&context)?; + submodule.fix(&context, self.delete)?; } return Ok(status); } @@ -274,6 +280,12 @@ pub struct InstallCommand { #[cfg_attr(feature = "cli", clap(long, short))] pub force: bool, + /// Don't install submodules recursively, only top-level + /// + /// By default, submodules are installed recursively with `git submodule update --recursive`. + #[cfg_attr(feature = "cli", clap(long))] + pub no_recursive: bool, + /// Print options #[cfg_attr(feature = "cli", clap(flatten))] pub options: PrintOptions, @@ -292,7 +304,7 @@ impl InstallCommand { let mut status = Status::read_from(&context)?; for submodule in status.flattened_mut() { - submodule.fix(&context)?; + submodule.fix(&context, false)?; } match &self.url { @@ -310,8 +322,8 @@ impl InstallCommand { None => { println_verbose!("Installing submodules"); context.submodule_init(None)?; - context.submodule_sync(None)?; - context.submodule_update(None, self.force, false)?; + context.submodule_sync(None, !self.no_recursive)?; + context.submodule_update(None, self.force, false, !self.no_recursive)?; } } @@ -400,9 +412,8 @@ impl UpdateCommand { println_hint!(" run `magoo status` to investigate. Some issues might be fixable with `magoo status --fix`."); println_hint!(" alternatively, use the `--bypass` flag to ignore and continue anyway."); return Err(GitError::NeedFix(false)); - } else { - println_warn!("Bypassing warnings from unhealthy submodule `{name}`"); } + println_warn!("Bypassing warnings from unhealthy submodule `{name}`"); } let path = match submodule.path() { @@ -425,14 +436,14 @@ impl UpdateCommand { context.submodule_set_url(path, url)?; } - context.submodule_sync(Some(path))?; - context.submodule_update(Some(path), self.force, true)?; + context.submodule_sync(Some(path), false)?; + context.submodule_update(Some(path), self.force, true, false)?; } None => { println_verbose!("Updating submodules"); context.submodule_init(None)?; - context.submodule_sync(None)?; - context.submodule_update(None, self.force, true)?; + context.submodule_sync(None, false)?; + context.submodule_update(None, self.force, true, false)?; } } diff --git a/src/submodule.rs b/src/submodule.rs index 65b4ffa..eab909f 100644 --- a/src/submodule.rs +++ b/src/submodule.rs @@ -329,7 +329,7 @@ impl Submodule { /// 1. The submodule is healthy and initialized. /// 2. The submodule is healthy but not initialized. /// 3. The submodule is deleted. - pub fn fix(&mut self, context: &GitContext) -> Result<(), GitError> { + pub fn fix(&mut self, context: &GitContext, prefer_delete: bool) -> Result<(), GitError> { // the submodule can be in any shape or form // here are some notations: // - `G`: submodule data in .gitmodules is [`Some`] @@ -371,11 +371,16 @@ impl Submodule { } } - self.fix_issue(self.find_issue(), context)?; + self.fix_issue(self.find_issue(), context, prefer_delete)?; Ok(()) } - fn fix_issue(&mut self, issue: PartsIssue, context: &GitContext) -> Result<(), GitError> { + fn fix_issue( + &mut self, + issue: PartsIssue, + context: &GitContext, + prefer_delete: bool, + ) -> Result<(), GitError> { match issue { PartsIssue::None => { // submodule is healthy @@ -387,7 +392,31 @@ impl Submodule { self.force_remove_module_dir(context)?; } PartsIssue::MissingIndex => { - // index is missing, delete it + // index is missing + // try installing it from the info in submodule + if !prefer_delete { + if let Some(gitmodule) = &self.in_gitmodules { + // url and path are required + if let (Some(url), Some(path)) = (&gitmodule.url, &gitmodule.path) { + println_verbose!("Fix: adding submodule from .gitmodules"); + let result = context.submodule_add( + url.as_ref(), + Some(path.as_ref()), + gitmodule.branch.as_deref(), + Some(gitmodule.name.as_ref()), + None, + false, + ); + if let Err(e) = result { + println_error!("Failed to add submodule as part of --fix: {e}"); + println_hint!("To delete it instead, add the `--delete` flag"); + return Err(e); + } + return Ok(()); + } + } + } + // if we can't add from .gitmodules, delete it println_verbose!("Fix: deleting submodule missing in index"); self.force_delete(context)?; } @@ -397,6 +426,12 @@ impl Submodule { println_verbose!("Fix: deleting submodule missing in .gitmodules"); self.force_delete(context)?; } + PartsIssue::MissingIndexAndGitModules => { + // submodule is not in .gitmodules + // delete it + println_verbose!("Fix: deleting submodule missing in index and .gitmodules"); + self.force_delete(context)?; + } }; Ok(()) } @@ -426,10 +461,14 @@ impl Submodule { PartsIssue::Residue } (Some(_), None, Some(_), Some(_)) => PartsIssue::Residue, - (_, _, _, None) => { - // index is missing + (Some(_), _, _, None) => { + // index is missing, but is in .gitmodules PartsIssue::MissingIndex } + (None, _, _, None) => { + // submodule is not in .gitmodules or index + PartsIssue::MissingIndexAndGitModules + } (None, _, _, _) => { // submodule is not in .gitmodules PartsIssue::MissingInGitModules @@ -626,6 +665,7 @@ enum PartsIssue { Residue, MissingIndex, MissingInGitModules, + MissingIndexAndGitModules, } impl PartsIssue { pub fn describe(&self) -> &'static str { @@ -634,6 +674,7 @@ impl PartsIssue { PartsIssue::Residue => "has residue from removal", PartsIssue::MissingIndex => "missing in index", PartsIssue::MissingInGitModules => "not in .gitmodules", + PartsIssue::MissingIndexAndGitModules => "missing in index and .gitmodules", } } }