diff --git a/Cargo.lock b/Cargo.lock index ca8110e..01f875d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -678,9 +678,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" [[package]] name = "object" @@ -766,18 +766,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.105" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] @@ -796,7 +796,7 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.17", "libredox", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -914,9 +914,9 @@ dependencies = [ [[package]] name = "serde-inline-default" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d48532bc0781ac622a5fea0f16502d3b4f1af0fcebe56d618120969f35d315" +checksum = "2bf03b7a5281cfd4013bc788d057b0f09fc634397d83bc8973c955bd4f32727a" dependencies = [ "proc-macro2", "quote", @@ -1095,11 +1095,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl 2.0.17", + "thiserror-impl 2.0.18", ] [[package]] @@ -1115,9 +1115,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", @@ -1135,9 +1135,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.45" +version = "0.3.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd" +checksum = "9da98b7d9b7dad93488a84b8248efc35352b0b2657397d4167e7ad67e5d535e5" dependencies = [ "deranged", "itoa", @@ -1150,15 +1150,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.25" +version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd" +checksum = "78cc610bac2dcee56805c99642447d4c5dbde4d01f752ffea0199aee1f601dc4" dependencies = [ "num-conv", "time-core", @@ -1420,6 +1420,6 @@ checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zmij" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f63c051f4fe3c1509da62131a678643c5b6fbdc9273b2b79d4378ebda003d2" +checksum = "dfcd145825aace48cff44a8844de64bf75feec3080e0aa5cdbde72961ae51a65" diff --git a/Cargo.toml b/Cargo.toml index a390fec..c7e84d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,10 +8,6 @@ repository = "https://github.com/ripytide/metapac" readme = "README.md" keywords = ["package-manager", "linux", "declarative", "cli"] categories = ["command-line-utilities"] -authors = [ - "James Forster ", - "Md Isfarul Haque , _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn add_repos( + repos: &BTreeMap, + _: bool, + _: &Self::Config, + ) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } - fn remove_repos(_: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn remove_repos(repos: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } fn version(_: &Self::Config) -> Result { - run_command_for_stdout(["apt", "--version"], Perms::Same, false) + run_command_for_stdout(["apt", "--version"], Perms::Same, StdErr::Show) } } diff --git a/src/backends/arch.rs b/src/backends/arch.rs index 2c81a72..c82a929 100644 --- a/src/backends/arch.rs +++ b/src/backends/arch.rs @@ -98,13 +98,13 @@ impl Backend for Arch { "--quiet", ], Perms::Same, - false, + StdErr::Show, )?; let installed = run_command_for_stdout( [config.package_manager.as_command(), "--query", "--quiet"], Perms::Same, - false, + StdErr::Show, )?; Ok(all @@ -129,7 +129,7 @@ impl Backend for Arch { "--quiet", ], Perms::Same, - false, + StdErr::Show, )?; let mut result = BTreeMap::new(); @@ -189,7 +189,7 @@ impl Backend for Arch { "--quiet", ], Perms::Same, - false, + StdErr::Show, )?; let orphans = orphans_output.lines(); @@ -262,19 +262,31 @@ impl Backend for Arch { Ok(BTreeMap::new()) } - fn add_repos(_: &BTreeMap, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn add_repos( + repos: &BTreeMap, + _: bool, + _: &Self::Config, + ) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } - fn remove_repos(_: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn remove_repos(repos: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } fn version(config: &Self::Config) -> Result { run_command_for_stdout( [config.package_manager.as_command(), "--version"], Perms::Same, - false, + StdErr::Show, ) } } diff --git a/src/backends/brew.rs b/src/backends/brew.rs index 8f973c4..352f93b 100644 --- a/src/backends/brew.rs +++ b/src/backends/brew.rs @@ -60,13 +60,13 @@ impl Backend for Brew { let formulae = run_command_for_stdout( ["brew", "list", "-1", "--quiet", "--installed-on-request"], Perms::Same, - false, + StdErr::Show, )?; let casks = run_command_for_stdout( ["brew", "list", "-1", "--cask", "--quiet"], Perms::Same, - false, + StdErr::Show, )?; Ok(formulae @@ -141,15 +141,27 @@ impl Backend for Brew { Ok(BTreeMap::new()) } - fn add_repos(_: &BTreeMap, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn add_repos( + repos: &BTreeMap, + _: bool, + _: &Self::Config, + ) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } - fn remove_repos(_: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn remove_repos(repos: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } fn version(_: &Self::Config) -> Result { - run_command_for_stdout(["brew", "--version"], Perms::Same, false) + run_command_for_stdout(["brew", "--version"], Perms::Same, StdErr::Show) } } diff --git a/src/backends/bun.rs b/src/backends/bun.rs index 6135ce3..efbfa9b 100644 --- a/src/backends/bun.rs +++ b/src/backends/bun.rs @@ -45,13 +45,16 @@ impl Backend for Bun { return Ok(BTreeMap::new()); } - let output = - match run_command_for_stdout(["bun", "pm", "ls", "--global"], Perms::Same, true) { - Ok(output) => output, - //unfortunately when there are no global packages installed bun returns an error rather - //than saying zero packages - Err(_) => return Ok(BTreeMap::new()), - }; + let output = match run_command_for_stdout( + ["bun", "pm", "ls", "--global"], + Perms::Same, + StdErr::Hide, + ) { + Ok(output) => output, + //unfortunately when there are no global packages installed bun returns an error rather + //than saying zero packages + Err(_) => return Ok(BTreeMap::new()), + }; let lines = output.lines().collect::>(); @@ -147,15 +150,27 @@ impl Backend for Bun { Ok(BTreeMap::new()) } - fn add_repos(_: &BTreeMap, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn add_repos( + repos: &BTreeMap, + _: bool, + _: &Self::Config, + ) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } - fn remove_repos(_: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn remove_repos(repos: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } fn version(_: &Self::Config) -> Result { - run_command_for_stdout(["bun", "--version"], Perms::Same, false) + run_command_for_stdout(["bun", "--version"], Perms::Same, StdErr::Show) } } diff --git a/src/backends/cargo.rs b/src/backends/cargo.rs index 3ad738b..72ef9e3 100644 --- a/src/backends/cargo.rs +++ b/src/backends/cargo.rs @@ -181,25 +181,38 @@ impl Backend for Cargo { } fn clean_cache(_: &Self::Config) -> Result<()> { - run_command_for_stdout(["cargo-cache", "-V"], Perms::Same, false).map_or(Ok(()), |_| { - run_command(["cargo", "cache", "-a"], Perms::Same) - }) + run_command_for_stdout(["cargo-cache", "-V"], Perms::Same, StdErr::Show) + .map_or(Ok(()), |_| { + run_command(["cargo", "cache", "-a"], Perms::Same) + }) } fn get_installed_repos(_: &Self::Config) -> Result> { Ok(BTreeMap::new()) } - fn add_repos(_: &BTreeMap, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn add_repos( + repos: &BTreeMap, + _: bool, + _: &Self::Config, + ) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } - fn remove_repos(_: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn remove_repos(repos: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } fn version(_: &Self::Config) -> Result { - run_command_for_stdout(["cargo", "--version"], Perms::Same, false) + run_command_for_stdout(["cargo", "--version"], Perms::Same, StdErr::Show) } } diff --git a/src/backends/dnf.rs b/src/backends/dnf.rs index 1ee216e..c96133d 100644 --- a/src/backends/dnf.rs +++ b/src/backends/dnf.rs @@ -55,7 +55,7 @@ impl Backend for Dnf { "%{name}\n", ], Perms::Same, - false, + StdErr::Show, )?; Ok(packages @@ -140,7 +140,7 @@ impl Backend for Dnf { } fn get_installed_repos(_: &Self::Config) -> Result> { - let repos = run_command_for_stdout(["dnf", "copr", "list"], Perms::Sudo, false)?; + let repos = run_command_for_stdout(["dnf", "copr", "list"], Perms::Sudo, StdErr::Show)?; let repos = repos .lines() @@ -181,6 +181,6 @@ impl Backend for Dnf { } fn version(_: &Self::Config) -> Result { - run_command_for_stdout(["dnf", "--version"], Perms::Same, false) + run_command_for_stdout(["dnf", "--version"], Perms::Same, StdErr::Show) } } diff --git a/src/backends/flatpak.rs b/src/backends/flatpak.rs index 904b3a4..2cab39e 100644 --- a/src/backends/flatpak.rs +++ b/src/backends/flatpak.rs @@ -13,20 +13,19 @@ pub struct Flatpak; #[serde_inline_default] #[derive(Debug, Serialize, Deserialize, Default)] #[serde(deny_unknown_fields)] -pub struct FlatpakConfig { - installation: Option, -} +pub struct FlatpakConfig {} #[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct FlatpakPackageOptions { - pub installation: Option, pub remote: Option, } #[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] #[serde(deny_unknown_fields)] -pub struct FlatpakRepoOptions {} +pub struct FlatpakRepoOptions { + pub url: Option, +} impl Backend for Flatpak { type Config = FlatpakConfig; @@ -57,20 +56,19 @@ impl Backend for Flatpak { "flatpak", "list", "--app", - "--columns=application,installation", + "--columns=installation,application,origin", ], Perms::Same, - false, + StdErr::Show, )?; let apps = apps.lines().map(|line| { let parts = line.split_whitespace().collect::>(); ( - parts[0].to_string(), + format!("{}:{}", parts[0], parts[1]), Self::PackageOptions { - installation: Some(parts[1].to_string()), - remote: None, + remote: Some(parts[2].to_string()), }, ) }); @@ -81,16 +79,19 @@ impl Backend for Flatpak { fn install_packages( packages: &BTreeMap, no_confirm: bool, - config: &Self::Config, + _: &Self::Config, ) -> Result<()> { - let mut groups = BTreeMap::new(); + //group packages for faster installation and less y/n prompts + let mut groups: BTreeMap<(String, Option), Vec> = BTreeMap::new(); for (package, options) in packages { - let installation = options.installation.clone().or(config.installation.clone()); - let remote = options.remote.clone(); + let (installation, name) = package.split_once(":").ok_or(eyre!( + "invalid flatpak package name: {package:?}, should be in form \"installation:package\", such as \"system:metapac\"" + ))?; + groups - .entry((installation, remote)) - .or_insert_with(Vec::new) - .push(package.clone()); + .entry((installation.to_string(), options.remote.clone())) + .or_default() + .push(name.to_string()); } for ((installation, remote), packages) in groups { @@ -99,11 +100,10 @@ impl Backend for Flatpak { .into_iter() .chain(Some("--assumeyes").filter(|_| no_confirm)) .map(|x| x.to_string()) - .chain(match installation.as_deref() { - Some("user") => Some("--user".to_string()), - Some("system") => Some("--system".to_string()), - Some(x) => Some(format!("--installation={x}")), - None => None, + .chain(match installation.as_str() { + "user" => Some("--user".to_string()), + "system" => Some("--system".to_string()), + x => Some(format!("--installation={x}")), }) .chain(remote) .chain(packages), @@ -119,12 +119,31 @@ impl Backend for Flatpak { no_confirm: bool, _: &Self::Config, ) -> Result<()> { - if !packages.is_empty() { + //group packages for faster uninstallation and less y/n prompts + let mut groups: BTreeMap> = BTreeMap::new(); + for package in packages { + let (installation, name) = package.split_once(":").ok_or(eyre!( + "invalid flatpak package name: {package:?}, should be in form \"installation:package\", such as \"system:metapac\"" + ))?; + + groups + .entry(installation.to_string()) + .or_default() + .push(name.to_string()); + } + + for (installation, packages) in groups { run_command( ["flatpak", "uninstall"] .into_iter() .chain(Some("--assumeyes").filter(|_| no_confirm)) - .chain(packages.iter().map(String::as_str)), + .map(|x| x.to_string()) + .chain(match installation.as_str() { + "user" => Some("--user".to_string()), + "system" => Some("--system".to_string()), + x => Some(format!("--installation={x}")), + }) + .chain(packages), Perms::Same, )?; } @@ -137,13 +156,36 @@ impl Backend for Flatpak { no_confirm: bool, _: &Self::Config, ) -> Result<()> { - run_command( - ["flatpak", "update"] - .into_iter() - .chain(Some("--assumeyes").filter(|_| no_confirm)) - .chain(packages.iter().map(String::as_str)), - Perms::Same, - ) + //group packages for faster uninstallation and less y/n prompts + let mut groups: BTreeMap> = BTreeMap::new(); + for package in packages { + let (installation, name) = package.split_once(":").ok_or(eyre!( + "invalid flatpak package name: {package:?}, should be in form \"installation:package\", such as \"system:metapac\"" + ))?; + + groups + .entry(installation.to_string()) + .or_default() + .push(name.to_string()); + } + + for (installation, packages) in groups { + run_command( + ["flatpak", "update"] + .into_iter() + .chain(Some("--assumeyes").filter(|_| no_confirm)) + .map(|x| x.to_string()) + .chain(match installation.as_str() { + "user" => Some("--user".to_string()), + "system" => Some("--system".to_string()), + x => Some(format!("--installation={x}")), + }) + .chain(packages), + Perms::Same, + )?; + } + + Ok(()) } fn update_all_packages(no_confirm: bool, _: &Self::Config) -> Result<()> { @@ -162,18 +204,89 @@ impl Backend for Flatpak { } fn get_installed_repos(_: &Self::Config) -> Result> { - Ok(BTreeMap::new()) + let repos = run_command_for_stdout( + ["flatpak", "remotes", "--columns", "options,name,url"], + Perms::Sudo, + StdErr::Show, + )?; + + let repos = repos + .lines() + .map(|line| { + let parts = line.split_whitespace().collect::>(); + let installation = parts[0].split(",").collect::>()[0]; + ( + format!("{}:{}", installation, parts[1]), + FlatpakRepoOptions { + url: Some(parts[2].to_string()), + }, + ) + }) + .collect(); + + Ok(repos) } - fn add_repos(_: &BTreeMap, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn add_repos( + repos: &BTreeMap, + no_confirm: bool, + _: &Self::Config, + ) -> Result<()> { + for (repo, options) in repos { + let (installation, name) = repo.split_once(":").ok_or(eyre!( + "invalid flatpak repo name: {repo:?}, should be in form \"installation:repo\", such as \"system:flathub\"" + ))?; + + run_command( + ["flatpak", "remote-add"] + .into_iter() + .chain(Some("--assumeyes").filter(|_| no_confirm)) + .map(ToString::to_string) + .chain(match installation { + "user" => Some("--user".to_string()), + "system" => Some("--system".to_string()), + x => Some(format!("--installation={x}")), + }) + .chain([ + name.to_string(), + options + .url + .as_deref() + .ok_or(eyre!("flatpak repos must have the \"url\" option set"))? + .to_string(), + ]), + Perms::Sudo, + )? + } + + Ok(()) } - fn remove_repos(_: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn remove_repos(repos: &BTreeSet, no_confirm: bool, _: &Self::Config) -> Result<()> { + for repo in repos { + let (installation, name) = repo.split_once(":").ok_or(eyre!( + "invalid flatpak repo name: {repo:?}, should be in form \"installation:repo\", such as \"system:flathub\"" + ))?; + + run_command( + ["flatpak", "remote-delete"] + .into_iter() + .chain(Some("--assumeyes").filter(|_| no_confirm)) + .map(ToString::to_string) + .chain(match installation { + "user" => Some("--user".to_string()), + "system" => Some("--system".to_string()), + x => Some(format!("--installation={x}")), + }) + .chain([name.to_string()]), + Perms::Sudo, + )? + } + + Ok(()) } fn version(_: &Self::Config) -> Result { - run_command_for_stdout(["flatpak", "--version"], Perms::Same, false) + run_command_for_stdout(["flatpak", "--version"], Perms::Same, StdErr::Show) } } diff --git a/src/backends/mas.rs b/src/backends/mas.rs index 56f80f5..fbd67a5 100644 --- a/src/backends/mas.rs +++ b/src/backends/mas.rs @@ -45,7 +45,7 @@ impl Backend for Mas { return Ok(BTreeMap::new()); } - let output = run_command_for_stdout(["mas", "list"], Perms::Same, false)?; + let output = run_command_for_stdout(["mas", "list"], Perms::Same, StdErr::Show)?; Ok(output .lines() @@ -110,15 +110,27 @@ impl Backend for Mas { Ok(BTreeMap::new()) } - fn add_repos(_: &BTreeMap, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn add_repos( + repos: &BTreeMap, + _: bool, + _: &Self::Config, + ) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } - fn remove_repos(_: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn remove_repos(repos: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } fn version(_: &Self::Config) -> Result { - run_command_for_stdout(["mas", "version"], Perms::Same, false) + run_command_for_stdout(["mas", "version"], Perms::Same, StdErr::Show) } } diff --git a/src/backends/mise.rs b/src/backends/mise.rs index c823006..f7a09dc 100644 --- a/src/backends/mise.rs +++ b/src/backends/mise.rs @@ -43,7 +43,7 @@ impl Backend for Mise { let search = run_command_for_stdout( ["mise", "search", "--no-headers", "--quiet"], Perms::Same, - true, + StdErr::Hide, )?; Ok(search @@ -75,7 +75,7 @@ impl Backend for Mise { "--quiet", ], Perms::Same, - true, + StdErr::Hide, )?; let packages_json = match serde_json::from_str(&packages)? { @@ -154,15 +154,27 @@ impl Backend for Mise { Ok(BTreeMap::new()) } - fn add_repos(_: &BTreeMap, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn add_repos( + repos: &BTreeMap, + _: bool, + _: &Self::Config, + ) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } - fn remove_repos(_: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn remove_repos(repos: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } fn version(_: &Self::Config) -> Result { - run_command_for_stdout(["mise", "--version"], Perms::Same, false) + run_command_for_stdout(["mise", "--version"], Perms::Same, StdErr::Show) } } diff --git a/src/backends/npm.rs b/src/backends/npm.rs index b00b4cb..d4b3d97 100644 --- a/src/backends/npm.rs +++ b/src/backends/npm.rs @@ -46,8 +46,11 @@ impl Backend for Npm { return Ok(BTreeMap::new()); } - let stdout = - run_command_for_stdout(["npm", "list", "--global", "--json"], Perms::Same, false)?; + let stdout = run_command_for_stdout( + ["npm", "list", "--global", "--json"], + Perms::Same, + StdErr::Show, + )?; let value: Value = serde_json::from_str(&stdout)?; let object = value.as_object().ok_or(eyre!("json should be an object"))?; @@ -125,15 +128,27 @@ impl Backend for Npm { Ok(BTreeMap::new()) } - fn add_repos(_: &BTreeMap, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn add_repos( + repos: &BTreeMap, + _: bool, + _: &Self::Config, + ) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } - fn remove_repos(_: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn remove_repos(repos: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } fn version(_: &Self::Config) -> Result { - run_command_for_stdout(["npm", "--version"], Perms::Same, false) + run_command_for_stdout(["npm", "--version"], Perms::Same, StdErr::Show) } } diff --git a/src/backends/pipx.rs b/src/backends/pipx.rs index a52603b..36e5ac3 100644 --- a/src/backends/pipx.rs +++ b/src/backends/pipx.rs @@ -53,7 +53,7 @@ impl Backend for Pipx { let names = extract_package_names(run_command_for_stdout( ["pipx", "list", "--json"], Perms::Same, - true, + StdErr::Hide, )?)?; Ok(names @@ -112,16 +112,28 @@ impl Backend for Pipx { Ok(BTreeMap::new()) } - fn add_repos(_: &BTreeMap, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn add_repos( + repos: &BTreeMap, + _: bool, + _: &Self::Config, + ) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } - fn remove_repos(_: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn remove_repos(repos: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } fn version(_: &Self::Config) -> Result { - run_command_for_stdout(["pipx", "--version"], Perms::Same, false) + run_command_for_stdout(["pipx", "--version"], Perms::Same, StdErr::Show) } } diff --git a/src/backends/pnpm.rs b/src/backends/pnpm.rs index e576f2d..4b284cc 100644 --- a/src/backends/pnpm.rs +++ b/src/backends/pnpm.rs @@ -47,8 +47,11 @@ impl Backend for Pnpm { return Ok(BTreeMap::new()); } - let stdout = - run_command_for_stdout(["pnpm", "list", "--global", "--json"], Perms::Same, false)?; + let stdout = run_command_for_stdout( + ["pnpm", "list", "--global", "--json"], + Perms::Same, + StdErr::Show, + )?; let value: Value = serde_json::from_str(&stdout)?; let first_object = value.as_array().ok_or(eyre!("json should be an array"))?[0] @@ -128,15 +131,27 @@ impl Backend for Pnpm { Ok(BTreeMap::new()) } - fn add_repos(_: &BTreeMap, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn add_repos( + repos: &BTreeMap, + _: bool, + _: &Self::Config, + ) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } - fn remove_repos(_: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn remove_repos(repos: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } fn version(_: &Self::Config) -> Result { - run_command_for_stdout(["pnpm", "--version"], Perms::Same, false) + run_command_for_stdout(["pnpm", "--version"], Perms::Same, StdErr::Show) } } diff --git a/src/backends/scoop.rs b/src/backends/scoop.rs index 1ba542d..661fdca 100644 --- a/src/backends/scoop.rs +++ b/src/backends/scoop.rs @@ -56,7 +56,7 @@ impl Backend for Scoop { return Ok(BTreeMap::new()); } - let output = run_command_for_stdout(["scoop.cmd", "list"], Perms::Same, false)?; + let output = run_command_for_stdout(["scoop.cmd", "list"], Perms::Same, StdErr::Show)?; let lines = output.lines().collect::>(); let mut packages = BTreeMap::new(); @@ -129,16 +129,28 @@ impl Backend for Scoop { Ok(BTreeMap::new()) } - fn add_repos(_: &BTreeMap, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn add_repos( + repos: &BTreeMap, + _: bool, + _: &Self::Config, + ) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } - fn remove_repos(_: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn remove_repos(repos: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } fn version(_: &Self::Config) -> Result { - let output = run_command_for_stdout(["scoop.cmd", "--version"], Perms::Same, false)?; + let output = run_command_for_stdout(["scoop.cmd", "--version"], Perms::Same, StdErr::Show)?; Ok(output.lines().nth(1).unwrap().to_string()) } diff --git a/src/backends/snap.rs b/src/backends/snap.rs index 9dc0bcc..a83434f 100644 --- a/src/backends/snap.rs +++ b/src/backends/snap.rs @@ -84,7 +84,7 @@ impl Backend for Snap { return Ok(BTreeMap::new()); } - let output = run_command_for_stdout(["snap", "list"], Perms::Same, false)?; + let output = run_command_for_stdout(["snap", "list"], Perms::Same, StdErr::Show)?; // Skip the first line which is the header Ok(output @@ -150,16 +150,28 @@ impl Backend for Snap { Ok(BTreeMap::new()) } - fn add_repos(_: &BTreeMap, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn add_repos( + repos: &BTreeMap, + _: bool, + _: &Self::Config, + ) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } - fn remove_repos(_: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn remove_repos(repos: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } fn version(_: &Self::Config) -> Result { - run_command_for_stdout(["snap", "--version"], Perms::Same, false).map(|output| { + run_command_for_stdout(["snap", "--version"], Perms::Same, StdErr::Show).map(|output| { output .lines() .next() diff --git a/src/backends/uv.rs b/src/backends/uv.rs index 0d2f447..796adf0 100644 --- a/src/backends/uv.rs +++ b/src/backends/uv.rs @@ -55,7 +55,7 @@ impl Backend for Uv { let names = run_command_for_stdout( ["uv", "tool", "list", "--color", "never"], Perms::Same, - true, + StdErr::Hide, )? .lines() .filter(|x| !x.starts_with("-")) @@ -127,15 +127,27 @@ impl Backend for Uv { Ok(BTreeMap::new()) } - fn add_repos(_: &BTreeMap, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn add_repos( + repos: &BTreeMap, + _: bool, + _: &Self::Config, + ) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } - fn remove_repos(_: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn remove_repos(repos: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } fn version(_: &Self::Config) -> Result { - run_command_for_stdout(["uv", "--version"], Perms::Same, false) + run_command_for_stdout(["uv", "--version"], Perms::Same, StdErr::Show) } } diff --git a/src/backends/vscode.rs b/src/backends/vscode.rs index 23c7e7d..df92dd3 100644 --- a/src/backends/vscode.rs +++ b/src/backends/vscode.rs @@ -71,7 +71,7 @@ impl Backend for VsCode { let names = run_command_for_stdout( [config.variant.as_command(), "--list-extensions"], Perms::Same, - true, + StdErr::Hide, )? .lines() .map(|x| (x.to_string(), Self::PackageOptions {})) @@ -142,19 +142,31 @@ impl Backend for VsCode { Ok(BTreeMap::new()) } - fn add_repos(_: &BTreeMap, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn add_repos( + repos: &BTreeMap, + _: bool, + _: &Self::Config, + ) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } - fn remove_repos(_: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn remove_repos(repos: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } fn version(config: &Self::Config) -> Result { run_command_for_stdout( [config.variant.as_command(), "--version"], Perms::Same, - false, + StdErr::Show, ) .map(|x| x.lines().join(" ")) } diff --git a/src/backends/winget.rs b/src/backends/winget.rs index ab03834..cc3d8d2 100644 --- a/src/backends/winget.rs +++ b/src/backends/winget.rs @@ -68,7 +68,7 @@ impl Backend for WinGet { tempfile.path().to_str().unwrap(), ], Perms::Same, - false, + StdErr::Show, )?; let mut export = String::new(); @@ -147,15 +147,27 @@ impl Backend for WinGet { Ok(BTreeMap::new()) } - fn add_repos(_: &BTreeMap, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn add_repos( + repos: &BTreeMap, + _: bool, + _: &Self::Config, + ) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } - fn remove_repos(_: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn remove_repos(repos: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } fn version(_: &Self::Config) -> Result { - run_command_for_stdout(["winget", "--version"], Perms::Same, false) + run_command_for_stdout(["winget", "--version"], Perms::Same, StdErr::Show) } } diff --git a/src/backends/xbps.rs b/src/backends/xbps.rs index b37beaf..3c0e94c 100644 --- a/src/backends/xbps.rs +++ b/src/backends/xbps.rs @@ -47,8 +47,11 @@ impl Backend for Xbps { return Ok(BTreeMap::new()); } - let stdout = - run_command_for_stdout(["xbps-query", "--list-manual-pkgs"], Perms::Same, false)?; + let stdout = run_command_for_stdout( + ["xbps-query", "--list-manual-pkgs"], + Perms::Same, + StdErr::Show, + )?; // Removes the package version from output let re = Regex::new(r"-[^-]*$")?; @@ -149,15 +152,27 @@ impl Backend for Xbps { Ok(BTreeMap::new()) } - fn add_repos(_: &BTreeMap, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn add_repos( + repos: &BTreeMap, + _: bool, + _: &Self::Config, + ) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } - fn remove_repos(_: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn remove_repos(repos: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } fn version(_: &Self::Config) -> Result { - run_command_for_stdout(["xbps-query", "--version"], Perms::Same, false) + run_command_for_stdout(["xbps-query", "--version"], Perms::Same, StdErr::Show) } } diff --git a/src/backends/yarn.rs b/src/backends/yarn.rs index 9f64261..924a5c0 100644 --- a/src/backends/yarn.rs +++ b/src/backends/yarn.rs @@ -51,7 +51,7 @@ impl Backend for Yarn { //have binaries, see https://github.com/yarnpkg/yarn/issues/5725 // //instead we manually read the global `package.json` file - let dir = run_command_for_stdout(["yarn", "global", "dir"], Perms::Same, true)?; + let dir = run_command_for_stdout(["yarn", "global", "dir"], Perms::Same, StdErr::Hide)?; let dir = dir .lines() .next() @@ -142,15 +142,27 @@ impl Backend for Yarn { Ok(BTreeMap::new()) } - fn add_repos(_: &BTreeMap, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn add_repos( + repos: &BTreeMap, + _: bool, + _: &Self::Config, + ) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } - fn remove_repos(_: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn remove_repos(repos: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } fn version(_: &Self::Config) -> Result { - run_command_for_stdout(["yarn", "--version"], Perms::Same, false) + run_command_for_stdout(["yarn", "--version"], Perms::Same, StdErr::Show) } } diff --git a/src/backends/zypper.rs b/src/backends/zypper.rs index 86f06e6..5aff00c 100644 --- a/src/backends/zypper.rs +++ b/src/backends/zypper.rs @@ -51,7 +51,7 @@ impl Backend for Zypper { let stdout = run_command_for_stdout( ["zypper", "packages", "--userinstalled"], Perms::Same, - false, + StdErr::Show, )?; stdout @@ -147,15 +147,27 @@ impl Backend for Zypper { Ok(BTreeMap::new()) } - fn add_repos(_: &BTreeMap, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn add_repos( + repos: &BTreeMap, + _: bool, + _: &Self::Config, + ) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } - fn remove_repos(_: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { - Err(eyre!("unimplemented")) + fn remove_repos(repos: &BTreeSet, _: bool, _: &Self::Config) -> Result<()> { + if repos.is_empty() { + Ok(()) + } else { + Err(eyre!("unimplemented")) + } } fn version(_: &Self::Config) -> Result { - run_command_for_stdout(["zypper", "--version"], Perms::Same, false) + run_command_for_stdout(["zypper", "--version"], Perms::Same, StdErr::Show) } } diff --git a/src/cmd.rs b/src/cmd.rs index 0a41c96..2eac8c7 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -13,7 +13,13 @@ pub enum Perms { Same, } -pub fn run_command_for_stdout(args: I, perms: Perms, hide_stderr: bool) -> Result +#[derive(Debug, Clone, Copy)] +pub enum StdErr { + Show, + Hide, +} + +pub fn run_command_for_stdout(args: I, perms: Perms, stderr: StdErr) -> Result where S: Into, I: IntoIterator, @@ -39,7 +45,7 @@ where .args(remaining_args) .stdin(Stdio::inherit()) .stdout(Stdio::piped()) - .stderr(if !hide_stderr { + .stderr(if matches!(stderr, StdErr::Show) { Stdio::inherit() } else { Stdio::null() diff --git a/src/core.rs b/src/core.rs index f8ccab4..a0db150 100644 --- a/src/core.rs +++ b/src/core.rs @@ -91,7 +91,7 @@ impl CleanCommand { if self.no_confirm { log::info!("proceeding to uninstall packages without confirmation"); } else if !Confirm::new() - .with_prompt("these packages will be uninstalled, do you want to continue?") + .with_prompt("these repos/packages will be uninstalled, do you want to continue?") .default(true) .show_default(true) .interact() @@ -134,7 +134,7 @@ impl SyncCommand { log::info!("proceeding to install packages without confirmation"); } else if !missing.is_empty() && !Confirm::new() - .with_prompt("these packages will be installed, do you want to continue?") + .with_prompt("these repos/packages will be installed, do you want to continue?") .default(true) .show_default(true) .interact() diff --git a/src/prelude.rs b/src/prelude.rs index baea549..7d52502 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -28,7 +28,7 @@ pub use crate::cli::{ BackendsCommand, CleanCacheCommand, CleanCommand, MainArguments, MainSubcommand, SyncCommand, UnmanagedCommand, UpdateAllCommand, UpdateCommand, }; -pub use crate::cmd::Perms; +pub use crate::cmd::{Perms, StdErr}; pub use crate::config::Config; pub use crate::groups::Groups; pub use crate::hooks::Hooks;