diff --git a/.vscode/settings.json b/.vscode/settings.json index 20dd886b979..19c28fab755 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,6 +12,7 @@ "aarch", "algos", "binutils", + "bools", "chmod", "choco", "clippy", diff --git a/Cargo.lock b/Cargo.lock index d3df924c5e1..9d7e1ec8f2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,18 +17,6 @@ version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486" -[[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - [[package]] name = "async-trait" version = "0.1.50" @@ -57,47 +45,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -[[package]] -name = "blake2b_simd" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" -dependencies = [ - "arrayref", - "arrayvec", - "constant_time_eq", -] - -[[package]] -name = "bstr" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90682c8d613ad3373e66de8c6411e0ae2ab2571e879d2efbf73558cc66f21279" -dependencies = [ - "lazy_static", - "memchr", - "regex-automata", - "serde", -] - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - [[package]] name = "bytes" version = "1.0.1" @@ -187,44 +140,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "crossbeam-utils" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" -dependencies = [ - "cfg-if 1.0.0", - "lazy_static", -] - -[[package]] -name = "csv" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" -dependencies = [ - "bstr", - "csv-core", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "csv-core" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" -dependencies = [ - "memchr", -] - [[package]] name = "directories" version = "2.0.2" @@ -235,17 +150,6 @@ dependencies = [ "dirs-sys", ] -[[package]] -name = "dirs" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" -dependencies = [ - "libc", - "redox_users 0.3.5", - "winapi", -] - [[package]] name = "dirs-next" version = "2.0.0" @@ -263,7 +167,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" dependencies = [ "libc", - "redox_users 0.4.0", + "redox_users", "winapi", ] @@ -274,7 +178,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", - "redox_users 0.4.0", + "redox_users", "winapi", ] @@ -284,12 +188,6 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" -[[package]] -name = "encode_unicode" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" - [[package]] name = "futures" version = "0.3.16" @@ -384,17 +282,6 @@ dependencies = [ "slab", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.3" @@ -403,7 +290,7 @@ checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if 1.0.0", "libc", - "wasi 0.10.2+wasi-snapshot-preview1", + "wasi", ] [[package]] @@ -440,6 +327,15 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "indoc" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a75aeaaef0ce18b58056d306c27b07436fbb34b8816c53094b76dd81803136" +dependencies = [ + "unindent", +] + [[package]] name = "is-root" version = "0.1.2" @@ -459,12 +355,6 @@ dependencies = [ "either", ] -[[package]] -name = "itoa" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" - [[package]] name = "lazy_static" version = "1.4.0" @@ -573,7 +463,6 @@ checksum = "6acbef58a60fe69ab50510a55bc8cdd4d6cf2283d27ad338f54cb52747a9cf2d" name = "pacaptr" version = "0.12.1" dependencies = [ - "anyhow", "async-trait", "bytes", "clap", @@ -581,12 +470,12 @@ dependencies = [ "confy", "dirs-next", "futures", + "indoc", "is-root", "itertools", "macro_rules_attribute", "once_cell", "pacaptr-macros", - "prettytable-rs", "regex", "serde", "tap", @@ -603,11 +492,24 @@ dependencies = [ name = "pacaptr-macros" version = "0.1.0" dependencies = [ + "anyhow", "itertools", "litrs", + "once_cell", "proc-macro2", "quote", + "regex", "syn", + "tabled", +] + +[[package]] +name = "papergrid" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117aab6154bbd707e4cca766c7df1d3d247f3bf3052a76709583713c356d6baf" +dependencies = [ + "unicode-width", ] [[package]] @@ -628,20 +530,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "prettytable-rs" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fd04b170004fa2daccf418a7f8253aaf033c27760b5f225889024cf66d7ac2e" -dependencies = [ - "atty", - "csv", - "encode_unicode", - "lazy_static", - "term", - "unicode-width", -] - [[package]] name = "proc-macro-error" version = "1.0.4" @@ -696,12 +584,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "redox_syscall" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - [[package]] name = "redox_syscall" version = "0.2.9" @@ -711,25 +593,14 @@ dependencies = [ "bitflags", ] -[[package]] -name = "redox_users" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" -dependencies = [ - "getrandom 0.1.16", - "redox_syscall 0.1.57", - "rust-argon2", -] - [[package]] name = "redox_users" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ - "getrandom 0.2.3", - "redox_syscall 0.2.9", + "getrandom", + "redox_syscall", ] [[package]] @@ -743,36 +614,12 @@ dependencies = [ "regex-syntax", ] -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" - [[package]] name = "regex-syntax" version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" -[[package]] -name = "rust-argon2" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" -dependencies = [ - "base64", - "blake2b_simd", - "constant_time_eq", - "crossbeam-utils", -] - -[[package]] -name = "ryu" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" - [[package]] name = "serde" version = "1.0.126" @@ -826,22 +673,32 @@ dependencies = [ ] [[package]] -name = "tap" -version = "1.0.1" +name = "tabled" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +checksum = "78e44c818a29312cb5f5b9b38aa72b37ad31b687dd32c5c50e737cc9f0385f20" +dependencies = [ + "papergrid", + "tabled_derive", +] [[package]] -name = "term" -version = "0.5.2" +name = "tabled_derive" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" +checksum = "295be2fd92b0c382818e4c5271594cd5232651ef3826c4e9963f204113eccec0" dependencies = [ - "byteorder", - "dirs", - "winapi", + "proc-macro2", + "quote", + "syn", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "termcolor" version = "1.1.2" @@ -969,6 +826,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +[[package]] +name = "unindent" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7" + [[package]] name = "users" version = "0.10.0" @@ -991,12 +854,6 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index 1864c014e84..e9c6366b021 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,30 +21,30 @@ version = "0.12.1" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[build-dependencies] -anyhow = "1.0.42" -itertools = "0.10.1" -prettytable-rs = "0.8.0" -regex = "1.5.4" +# [build-dependencies] [dev-dependencies] xshell = "0.1.14" -pacaptr-macros = { path="crates/pacaptr-macros" } [dependencies] async-trait = "0.1.50" bytes = "1.0.1" # clap = "3.0.0-beta.2" -clap = { git="https://github.com/clap-rs/clap" } +clap = { git = "https://github.com/clap-rs/clap" } colored = "2.0.0" confy = "0.4.0" dirs-next = "2.0.0" futures = "0.3.16" +indoc = "1.0.3" is-root = "0.1.2" itertools = "0.10.1" macro_rules_attribute = "0.0.2" once_cell = "1.8.0" -regex = { version = "1.5.4", default-features = false, features = ["std", "perf"] } +pacaptr-macros = { path = "crates/pacaptr-macros" } +regex = { version = "1.5.4", default-features = false, features = [ + "std", + "perf", +] } serde = { version = "1.0.126", features = ["derive"] } tap = "1.0.1" thiserror = "1.0.26" @@ -66,8 +66,16 @@ copyright = "2020, Rami3L" maintainer = "Rami3L " # license-file = ["LICENSE", "4"] assets = [ - ["target/release/pacaptr", "usr/bin/", "755"], - ["README.md", "usr/share/doc/pacaptr/README", "644"], + [ + "target/release/pacaptr", + "usr/bin/", + "755", + ], + [ + "README.md", + "usr/share/doc/pacaptr/README", + "644", + ], ] depends = "$auto" extended-description = """\ diff --git a/README.md b/README.md index 71e0825d1d4..78d1e3dbd40 100644 --- a/README.md +++ b/README.md @@ -313,4 +313,4 @@ After some discussions in [pacapt/#126], I decided to rewrite the project in Rus [rmtree]: https://github.com/beeftornado/homebrew-rmtree [gsudo]: https://github.com/gerardog/gsudo [rs-dev]: https://github.com/rami3l/pacaptr/tree/rs-dev -[compatibility table]: ./docs/compatibility_table.md +[compatibility table]: https://docs.rs/pacaptr diff --git a/build.rs b/build.rs deleted file mode 100644 index 1c62cbd6fe1..00000000000 --- a/build.rs +++ /dev/null @@ -1,86 +0,0 @@ -use std::{collections::BTreeMap, ffi::OsString, fs, io::Write, iter, path::Path}; - -use anyhow::{Context, Result}; -use itertools::Itertools; -use prettytable::{Cell, Row, Table}; -use regex::Regex; - -const PM_IMPL_DIR: &str = "src/pm/"; -const COMPAT_TABLE_PATH: &str = "docs/compatibility_table.md"; -const METHODS: &[&str] = &[ - "q", "qc", "qe", "qi", "qk", "ql", "qm", "qo", "qp", "qs", "qu", "r", "rn", "rns", "rs", "rss", - "s", "sc", "scc", "sccc", "sg", "si", "sii", "sl", "ss", "su", "suy", "sw", "sy", "u", -]; - -/// Checks the implementation status of `pacman` commands in a specific file -/// (eg. `homebrew.rs`). -fn check_methods(file: &Path) -> Result> { - let bytes = fs::read(file)?; - let contents = String::from_utf8(bytes)?; - - METHODS - .iter() - .map(|&method| { - // A function definition (rg. `rs`) is written as follows: - // `(async) fn rs(..) {..}` - let found = Regex::new(&format!(r#"fn\s+{}\s*\("#, method))?.is_match(&contents); - Ok((method.to_owned(), found)) - }) - .try_collect() -} - -fn main() -> Result<()> { - // Tell Cargo that if the given file changes, to rerun this build script. - println!("cargo:rerun-if-changed={}", PM_IMPL_DIR); - - let paths: Vec = fs::read_dir(PM_IMPL_DIR) - .context("Failed while reading PM_IMPL_DIR")? - .map(|entry| entry.context("Error while reading path")) - .try_collect()?; - - let excluded_names = ["mod.rs", "unknown.rs"]; - let impls: BTreeMap> = paths - .iter() - .filter(|entry| !excluded_names.iter().any(|&ex| ex == entry.file_name())) - .map(|entry| check_methods(&entry.path()).map(|impl_| (entry.file_name(), impl_))) - .try_collect()?; - - let make_row = |name: &str, data: &[&str]| { - let row = iter::once(&name) - .chain(data) - .map(|&s| Cell::new(s)) - .collect(); - Row::new(row) - }; - - // First row: `row!["", "q", "qc", "qe", ..]` - let head = Ok(make_row("", METHODS)); - let tail = impls.iter().map(|(file, items)| { - let data = METHODS - .iter() - .map(|&method| { - items - .get(method) - .expect("Implementation details not registered") - .then(|| "*") - .unwrap_or("") - }) - .collect_vec(); - - file.to_str() - .context("Failed to convert `file: OsString` to `&str`") - .map(|file| make_row(file, &data)) - }); - let mut table: Table = iter::once(head).chain(tail).try_collect()?; - table.set_format(*prettytable::format::consts::FORMAT_CLEAN); - - let mut file = - fs::File::create(COMPAT_TABLE_PATH).context("Failed while creating compatibility table")?; - file.write_all("```txt\n".as_bytes())?; - table - .print(&mut file) - .context("Failed while writing compatibility table")?; - file.write_all("```\n".as_bytes())?; - - Ok(()) -} diff --git a/crates/pacaptr-macros/Cargo.toml b/crates/pacaptr-macros/Cargo.toml index d88d2d9bf9f..b84ab75a37c 100644 --- a/crates/pacaptr-macros/Cargo.toml +++ b/crates/pacaptr-macros/Cargo.toml @@ -9,8 +9,12 @@ edition = "2018" proc-macro = true [dependencies] +anyhow = "1.0.42" +itertools = "0.10.1" litrs = "0.2.3" +once_cell = "1.8.0" proc-macro2 = "1.0.28" quote = "1.0.9" +regex = "1.5.4" syn = "1.0.74" -itertools = "0.10.1" +tabled = "0.2.1" diff --git a/crates/pacaptr-macros/src/compat_table.rs b/crates/pacaptr-macros/src/compat_table.rs new file mode 100644 index 00000000000..504360e5d86 --- /dev/null +++ b/crates/pacaptr-macros/src/compat_table.rs @@ -0,0 +1,110 @@ +use std::{collections::BTreeMap, ffi::OsString, fmt::Debug, fs, iter, path::Path, str::FromStr}; + +use anyhow::Context; +use itertools::Itertools; +use once_cell::sync::Lazy; +use proc_macro2::{Span, TokenStream}; +use regex::Regex; +use syn::{Error, Result}; +use tabled::{style::Style as TableStyle, Table, Tabled}; + +const PM_IMPL_DIR: &str = "src/pm/"; +const METHODS: &[&str] = &[ + "q", "qc", "qe", "qi", "qk", "ql", "qm", "qo", "qp", "qs", "qu", "r", "rn", "rns", "rs", "rss", + "s", "sc", "scc", "sccc", "sg", "si", "sii", "sl", "ss", "su", "suy", "sw", "sy", "u", +]; + +/// Checks the implementation status of `pacman` commands in a specific file +/// (eg. `homebrew.rs`). +fn check_methods(file: &Path) -> anyhow::Result> { + let bytes = fs::read(file)?; + let contents = String::from_utf8(bytes)?; + + METHODS + .iter() + .map(|&method| { + // A function definition (rg. `rs`) is written as follows: + // `(async) fn rs(..) {..}` + let found = Regex::new(&format!(r#"fn\s+{}\s*\("#, method))?.is_match(&contents); + Ok((method.to_owned(), found)) + }) + .try_collect() +} + +struct CompatRow { + fields: Vec, +} + +impl Tabled for CompatRow { + fn fields(&self) -> Vec { + self.fields.clone() + } + + fn headers() -> Vec { + static HEADERS: Lazy> = Lazy::new(|| { + // `["Module", "q", "qc", "qe", ..]` + iter::once(&"Module") + .chain(METHODS.iter()) + .map(|&s| s.to_owned()) + .collect() + }); + HEADERS.clone() + } +} + +fn make_table() -> anyhow::Result { + let paths: Vec = fs::read_dir(PM_IMPL_DIR) + .context("Failed while reading PM_IMPL_DIR")? + .map(|entry| entry.context("Error while reading path")) + .try_collect()?; + + let excluded_names = ["mod.rs", "unknown.rs"]; + let impls: BTreeMap> = paths + .iter() + .filter(|entry| !excluded_names.iter().any(|&ex| ex == entry.file_name())) + .map(|entry| check_methods(&entry.path()).map(|impl_| (entry.file_name(), impl_))) + .try_collect()?; + + let make_row = |name: &str, data: &[&str]| { + let fields = iter::once(&name) + .chain(data) + .map(|&s| s.to_owned()) + .collect_vec(); + CompatRow { fields } + }; + + let data: Vec<_> = impls + .iter() + .map(|(file, items)| { + let data = METHODS + .iter() + .map(|&method| { + items + .get(method) + .expect("Implementation details not registered") + .then(|| "*") + .unwrap_or("") + }) + .collect_vec(); + + file.to_str() + .context("Failed to convert `file: OsString` to `&str`") + .map(|file| make_row(file, &data)) + }) + .try_collect()?; + + let table = Table::new(&data).with(TableStyle::noborder()); + Ok(format!("```\n{}```\n", table)) +} + +pub(crate) fn compat_table_impl() -> Result { + fn throw(e: &dyn Debug) -> Error { + let msg = format!("{:?}", e); + Error::new(Span::call_site(), msg) + } + + let table = make_table().map_err(|e| throw(&e as _))?; + let comments = format!(r##"r#"{}"#"##, table); + let res = TokenStream::from_str(&comments)?; + Ok(res) +} diff --git a/crates/pacaptr-macros/src/lib.rs b/crates/pacaptr-macros/src/lib.rs index bfa5adb2a88..3655b071f0e 100644 --- a/crates/pacaptr-macros/src/lib.rs +++ b/crates/pacaptr-macros/src/lib.rs @@ -1,13 +1,14 @@ +mod compat_table; mod test_dsl; -use std::convert::TryFrom; +use std::{convert::TryFrom, iter::FromIterator}; use itertools::Itertools; use litrs::StringLit; use proc_macro2::TokenStream; use quote::quote; -use crate::test_dsl::test_dsl_impl; +use crate::{compat_table::compat_table_impl, test_dsl::test_dsl_impl}; /// A DSL (Domain-Specific Language) embedded in Rust, in order to simplify the /// form of smoke tests. @@ -65,3 +66,12 @@ pub fn test_dsl(input: proc_macro::TokenStream) -> proc_macro::TokenStream { proc_macro::TokenStream::from(res) } + +#[proc_macro] +pub fn compat_table(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let comments = match compat_table_impl() { + Err(e) => return e.to_compile_error().into(), + Ok(r) => proc_macro::TokenStream::from(r), + }; + proc_macro::TokenStream::from_iter(vec![comments, input]) +} diff --git a/docs/compatibility_table.md b/docs/compatibility_table.md deleted file mode 100644 index aea8f72fba3..00000000000 --- a/docs/compatibility_table.md +++ /dev/null @@ -1,15 +0,0 @@ -```txt - q qc qe qi qk ql qm qo qp qs qu r rn rns rs rss s sc scc sccc sg si sii sl ss su suy sw sy u - apk.rs * * * * * * * * * * * * * * * * * * * * * * - apt.rs * * * * * * * * * * * * * * * * * * * * * * - brew.rs * * * * * * * * * * * * * * * * * * - choco.rs * * * * * * * * * * - conda.rs * * * * * * * * * - dnf.rs * * * * * * * * * * * * * * * * * * * * * * * * * - emerge.rs * * * * * * * * * * * * * * * * - pip.rs * * * * * * * * * - port.rs * * * * * * * * * * * * * * * * * - scoop.rs * * * * * * * * * * * * * * - tlmgr.rs * * * * * * * * * * * * - zypper.rs * * * * * * * * * * * * * * * * * * * * * * * -``` diff --git a/src/dispatch/cmd.rs b/src/dispatch/cmd.rs index fee7455ff26..c81495cac7d 100644 --- a/src/dispatch/cmd.rs +++ b/src/dispatch/cmd.rs @@ -24,6 +24,7 @@ use crate::{ global_setting = AppSettings::ColoredHelp, setting = AppSettings::SubcommandRequiredElseHelp, )] +#[allow(clippy::struct_excessive_bools)] pub struct Pacaptr { #[clap(subcommand)] ops: Operations, @@ -198,6 +199,7 @@ impl Pacaptr { /// Generates current [`Config`] by merging current command line arguments /// and options obtained with [`clap`] with the dotfile [`Config`], which /// has a lower precedence. + #[must_use] pub fn merge_cfg(&self, dotfile: Config) -> Config { Config { dry_run: self.dry_run || dotfile.dry_run, @@ -210,6 +212,10 @@ impl Pacaptr { /// Executes the job according to the flags received and the package manager /// detected. + /// + /// # Errors + /// See [`Error`](crate::error::Error) for a list of possible errors. + #[allow(trivial_numeric_casts)] pub async fn dispatch_from(&self, mut cfg: Config) -> Result { // Collect options as a `String`, eg. `-S -y -u => "Suy"`. // ! HACK: In `Pm` we ensure the Pacman methods are all named with flags in @@ -295,6 +301,10 @@ impl Pacaptr { /// Runs [`dispatch_from`](Pacaptr::dispatch_from) with automatically /// detected [`Config`]. + /// + /// # Errors + /// See [`Error`](crate::error::Error) for a list of possible errors. + #[allow(trivial_numeric_casts)] pub async fn dispatch(&self) -> Result { let dotfile = task::block_in_place(Config::load); let cfg = self.merge_cfg(dotfile?); @@ -353,11 +363,12 @@ pub(super) mod tests { static MOCK_CFG: Lazy = Lazy::new(|| Config { default_pm: Some("mockpm".into()), - ..Default::default() + ..Config::default() }); #[test] #[should_panic(expected = "should run: suy")] + #[allow(clippy::semicolon_if_nothing_returned)] async fn simple_syu() { let opt = dbg!(Pacaptr::parse_from(&["pacaptr", "-Syu"])); let subcmd = &opt.ops; @@ -370,6 +381,7 @@ pub(super) mod tests { #[test] #[should_panic(expected = "should run: suy")] + #[allow(clippy::semicolon_if_nothing_returned)] async fn long_syu() { let opt = dbg!(Pacaptr::parse_from(&[ "pacaptr", @@ -387,6 +399,7 @@ pub(super) mod tests { #[test] #[should_panic(expected = r#"should run: sw ["curl", "wget"]"#)] + #[allow(clippy::semicolon_if_nothing_returned)] async fn simple_sw() { let opt = dbg!(Pacaptr::parse_from(&["pacaptr", "-Sw", "curl", "wget"])); let subcmd = &opt.ops; @@ -399,6 +412,7 @@ pub(super) mod tests { #[test] #[should_panic(expected = r#"should run: s ["docker"]"#)] + #[allow(clippy::semicolon_if_nothing_returned)] async fn other_flags() { let opt = dbg!(Pacaptr::parse_from(&[ "pacaptr", "-S", "--dryrun", "--yes", "docker" @@ -415,6 +429,7 @@ pub(super) mod tests { #[test] #[should_panic(expected = r#"should run: s ["docker", "--proxy=localhost:1234"]"#)] + #[allow(clippy::semicolon_if_nothing_returned)] async fn extra_flags() { let opt = dbg!(Pacaptr::parse_from(&[ "pacaptr", @@ -436,6 +451,7 @@ pub(super) mod tests { #[test] #[should_panic(expected = r#"should run: si ["docker", "--proxy=localhost:1234"]"#)] + #[allow(clippy::semicolon_if_nothing_returned)] async fn using() { let opt = dbg!(Pacaptr::parse_from(&[ "pacaptr", diff --git a/src/dispatch/config.rs b/src/dispatch/config.rs index 0f390666979..bc3a40c3d9a 100644 --- a/src/dispatch/config.rs +++ b/src/dispatch/config.rs @@ -11,6 +11,7 @@ const CONFIG_ENV_VAR: &str = "PACAPTR_CONFIG"; /// Configurations that may vary when running the package manager. #[derive(Clone, Default, Debug, Serialize, Deserialize)] +#[allow(clippy::struct_excessive_bools)] pub struct Config { #[serde(default)] pub dry_run: bool, @@ -31,8 +32,9 @@ pub struct Config { impl Config { /// The default config file path is `$HOME/.config/pacaptr/pacaptr.toml`. /// - /// This method will almost always success, and will only fail if `$HOME` is - /// not found. + /// # Errors + /// Returns an [`Error::ConfigError`] when `$HOME` is not found. + #[allow(trivial_numeric_casts)] pub fn default_path() -> Result { let crate_name = clap::crate_name!(); dirs_next::home_dir() @@ -48,6 +50,10 @@ impl Config { /// Gets the custom config file path specified by the `PACAPTR_CONFIG` /// environment variable. + /// + /// # Errors + /// Returns an [`Error::ConfigError`] when the config path is not found in + /// the environmental variable. pub fn custom_path() -> Result { env::var(CONFIG_ENV_VAR) .map_err(|e| Error::ConfigError { @@ -63,6 +69,9 @@ impl Config { /// the config file in the default path. /// - If the config file is not present anyway, a default one will be loaded /// with [`Default::default`], and no files will be written. + /// + /// # Errors + /// Returns an [`Error::ConfigError`] when the config file loading fails. pub fn load() -> Result { let path = Config::custom_path().or_else(|_| Config::default_path())?; path.exists() @@ -71,6 +80,6 @@ impl Config { .map_err(|_e| Error::ConfigError { msg: format!("Failed to read config at `{:?}`", &path), }) - .map(|cfg| cfg.unwrap_or_default()) + .map(Option::unwrap_or_default) } } diff --git a/src/dispatch/mod.rs b/src/dispatch/mod.rs index 1f6cbe137dd..c7d0787d90f 100644 --- a/src/dispatch/mod.rs +++ b/src/dispatch/mod.rs @@ -16,9 +16,13 @@ mod cmd; pub mod config; pub use self::{cmd::Pacaptr, config::Config}; -use crate::{exec::is_exe, pm::*}; +use crate::{ + exec::is_exe, + pm::{Apk, Apt, Brew, Choco, Conda, Dnf, Emerge, Pip, Pm, Port, Scoop, Tlmgr, Unknown, Zypper}, +}; /// Detects the name of the package manager to be used in auto dispatch. +#[must_use] pub fn detect_pm_str<'s>() -> &'s str { let pairs: &[(&str, &str)] = match () { _ if cfg!(target_os = "windows") => &[("scoop", ""), ("choco", "")], diff --git a/src/error.rs b/src/error.rs index ec8eb52ecad..a685636265e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -3,6 +3,8 @@ use thiserror::Error; use tokio::{io, task::JoinError}; +/// A specialized [`Result`](std::result::Result) type used by +/// [`pacaptr`](crate). pub type Result = std::result::Result; /// Error type for the [`pacaptr`](crate) library. @@ -10,10 +12,12 @@ pub type Result = std::result::Result; pub enum Error { /// Error while parsing CLI arguments. #[error("Failed to parse arguments: {msg}")] + #[allow(missing_docs)] ArgParseError { msg: String }, /// Error when handling a [`Config`](crate::dispatch::Config). #[error("Failed to handle config: {msg}")] + #[allow(missing_docs)] ConfigError { msg: String }, /// An [`Cmd`](crate::exec::Cmd) fails to finish. @@ -27,6 +31,7 @@ pub enum Error { /// Error when trying to get the `stdout`/`stderr`/... handler out of a /// running an [`Cmd`](crate::exec::Cmd). #[error("Subprocess didn't have a handle to {handle}")] + #[allow(missing_docs)] CmdNoHandleError { handle: String }, /// An [`Cmd`](crate::exec::Cmd) fails to finish. @@ -43,6 +48,7 @@ pub enum Error { /// A [`Pm`](crate::pm::Pm) operation is not implemented. #[error("Operation `{op}` is unimplemented for `{pm}`")] + #[allow(missing_docs)] OperationUnimplementedError { op: String, pm: String }, /// Miscellaneous other error. diff --git a/src/exec.rs b/src/exec.rs index 9450a345b19..88d11efa22e 100644 --- a/src/exec.rs +++ b/src/exec.rs @@ -5,8 +5,9 @@ use std::{ sync::atomic::{AtomicBool, Ordering}, }; -use bytes::Bytes; +use bytes::{Bytes, BytesMut}; use futures::prelude::*; +use indoc::indoc; pub use is_root::is_root; use itertools::{chain, Itertools}; use once_cell::sync::Lazy; @@ -17,6 +18,7 @@ use tokio::{ process::Command as Exec, task::JoinHandle, }; +#[allow(clippy::wildcard_imports)] use tokio_util::{ codec::{BytesCodec, FramedRead}, compat::*, @@ -26,7 +28,7 @@ use which::which; use crate::{ error::{Error, Result}, - print::*, + print::{print_cmd, print_question, PROMPT_CANCELED, PROMPT_PENDING, PROMPT_RUN}, }; /// Different ways in which a command shall be dealt with. @@ -59,6 +61,7 @@ pub enum Mode { Prompt, } +/// The status code type returned by a [`Cmd`], pub type StatusCode = i32; /// Output of running a [`Cmd`]. @@ -70,7 +73,7 @@ pub struct Output { /// The status code returned by the [`Cmd`]. /// - /// Here we use [`Some(n)`] for exit code, [`None`] for signals. + /// Here we use [`Some`] for exit code, [`None`] for signals. pub code: Option, } @@ -97,9 +100,9 @@ pub struct Cmd { impl Cmd { pub fn new(cmd: &[impl AsRef]) -> Self { - Self { + Cmd { cmd: cmd.iter().map(AsRef::as_ref).map_into().collect(), - ..Default::default() + ..Cmd::default() } } @@ -115,6 +118,7 @@ impl Cmd { self.tap_mut(|s| s.flags = flags.iter().map(AsRef::as_ref).map_into().collect()) } + #[must_use] pub fn sudo(self, sudo: bool) -> Self { self.tap_mut(|s| s.sudo = sudo) } @@ -123,11 +127,13 @@ impl Cmd { /// /// If a **normal admin** needs to run it with `sudo`, and we are not /// `root`, then this is the case. + #[must_use] pub fn should_sudo(&self) -> bool { self.sudo && !is_root() } /// Converts a [`Cmd`] object into an [`Exec`]. + #[must_use] pub fn build(self) -> Exec { // ! Special fix for `zypper`: `zypper install -y curl` is accepted, // ! but not `zypper install curl -y`. @@ -169,6 +175,7 @@ where let mut buf = Vec::::new(); let buf_sink = (&mut buf).into_sink(); + #[allow(clippy::option_if_let_else)] let sink = if let Some(out) = out { let out_sink = out.compat_write().into_sink(); buf_sink.fanout(out_sink).left_sink() @@ -180,16 +187,31 @@ where Ok(buf) } +macro_rules! docs_errors_exec { + () => { + indoc! {" + # Errors + This function might return one of the following errors: + + - [`Error::CmdJoinError`] + - [`Error::CmdNoHandleError`] + - [`Error::CmdSpawnError`] + - [`Error::CmdWaitError`] + "} + }; +} + impl Cmd { /// Executes a [`Cmd`] and returns its output. /// /// The exact behavior depends on the [`Mode`] passed in (see the definition /// of [`Mode`] for more info). + #[doc = docs_errors_exec!()] pub async fn exec(self, mode: Mode) -> Result { match mode { Mode::PrintCmd => { print_cmd(&self, PROMPT_CANCELED); - Ok(Default::default()) + Ok(Output::default()) } Mode::Mute => self.exec_checkall(true).await, Mode::CheckAll => { @@ -204,14 +226,21 @@ impl Cmd { } } - /// Inner implementation of [`Cmd::exec_checkerr`] and - /// [`Cmd::exec_checkall`]. - /// - /// `merge == false` goes to [`Cmd::exec_checkerr`], and - /// [`Cmd::exec_checkall`] otherwise. + /// Inner implementation of [`Cmd::exec_checkerr`] (if `merge` is `false`) + /// and [`Cmd::exec_checkall`] (otherwise). + #[doc = docs_errors_exec!()] async fn exec_check_output(self, mute: bool, merge: bool) -> Result { use tokio_stream::StreamExt; - use Error::*; + use Error::{CmdJoinError, CmdNoHandleError, CmdSpawnError, CmdWaitError}; + + fn make_reader( + src: Option, + name: &str, + ) -> Result>> { + src.map(into_bytes).ok_or_else(|| CmdNoHandleError { + handle: name.into(), + }) + } let mut child = self .build() @@ -224,15 +253,6 @@ impl Cmd { .spawn() .map_err(CmdSpawnError)?; - fn make_reader( - src: Option, - name: &str, - ) -> Result>> { - src.map(into_bytes).ok_or_else(|| CmdNoHandleError { - handle: name.into(), - }) - } - let stderr_reader = make_reader(child.stderr.take(), "stderr")?; let mut reader = if merge { let stdout_reader = make_reader(child.stdout.take(), "stdout")?; @@ -264,6 +284,7 @@ impl Cmd { /// /// If `mute` is `false`, then normal `stdout/stderr` output will be printed /// to `stdout` too. + #[doc = docs_errors_exec!()] pub async fn exec_checkall(self, mute: bool) -> Result { self.exec_check_output(mute, true).await } @@ -272,6 +293,7 @@ impl Cmd { /// /// If `mute` is `false`, then its `stderr` output will be printed to /// `stderr` too. + #[doc = docs_errors_exec!()] pub async fn exec_checkerr(self, mute: bool) -> Result { self.exec_check_output(mute, false).await } @@ -284,6 +306,7 @@ impl Cmd { /// This function behaves just like [`exec_checkerr`](Cmd::exec_checkerr), /// but in addition, the user will be prompted if (s)he wishes to /// continue with the command execution. + #[doc = docs_errors_exec!()] pub async fn exec_prompt(self, mute: bool) -> Result { static ALL_YES: Lazy = Lazy::new(|| AtomicBool::new(false)); @@ -315,7 +338,7 @@ impl Cmd { } }; if !proceed { - return Ok(Default::default()); + return Ok(Output::default()); } print_cmd(&self, PROMPT_RUN); self.exec_checkerr(mute).await @@ -335,6 +358,8 @@ impl std::fmt::Display for Cmd { /// /// If `case_sensitive` is `false`, then `expected` should be all lower case /// patterns. +#[must_use] +#[allow(clippy::missing_panics_doc)] pub fn prompt(question: &str, options: &str, expected: &[&str], case_sensitive: bool) -> String { use std::io::{self, Write}; @@ -361,10 +386,21 @@ pub fn prompt(question: &str, options: &str, expected: &[&str], case_sensitive: .unwrap() // It's impossible to find nothing out of an infinite loop. } +macro_rules! docs_errors_grep { + () => { + indoc! {" + # Errors + Returns an [`Error::OtherError`] when any of the + regex patterns is ill-formed. + "} + }; +} + /// Finds all lines in the given `text` that matches all the `patterns`. /// /// We suppose that all patterns are legal regular expressions. /// An error message will be returned if this is not the case. +#[doc = docs_errors_grep!()] pub fn grep<'t>(text: &'t str, patterns: &[&str]) -> Result> { patterns .iter() @@ -381,6 +417,7 @@ pub fn grep<'t>(text: &'t str, patterns: &[&str]) -> Result> { } /// Prints the result of [`grep`] line by line. +#[doc = docs_errors_grep!()] pub fn grep_print(text: &str, patterns: &[&str]) -> Result<()> { grep(text, patterns).map(|lns| lns.iter().for_each(|ln| println!("{}", ln))) } @@ -388,13 +425,14 @@ pub fn grep_print(text: &str, patterns: &[&str]) -> Result<()> { /// Checks if an executable exists by name (consult `$PATH`) or by path. /// /// To check by one parameter only, pass `""` to the other one. +#[must_use] pub fn is_exe(name: &str, path: &str) -> bool { (!path.is_empty() && which(path).is_ok()) || (!name.is_empty() && which(name).is_ok()) } /// Turns an [`AsyncRead`] into a [`Stream`]. /// -/// _Shamelessly copied from [StackOverflow](https://stackoverflow.com/a/59327560)._ +/// _Shamelessly copied from [`StackOverflow`](https://stackoverflow.com/a/59327560)._ pub fn into_bytes(reader: impl AsyncRead) -> impl Stream> { - FramedRead::new(reader, BytesCodec::new()).map_ok(|bytes| bytes.freeze()) + FramedRead::new(reader, BytesCodec::new()).map_ok(BytesMut::freeze) } diff --git a/src/lib.rs b/src/lib.rs index dd4e5a63a8c..e54f873ee91 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,26 @@ -#![warn(broken_intra_doc_links)] #![forbid(unsafe_code)] +#![warn( + clippy::pedantic, + missing_copy_implementations, + missing_debug_implementations, + missing_docs, + rustdoc::broken_intra_doc_links, + trivial_numeric_casts, + unused_allocation +)] + +//! `pacaptr` is a `pacman`-like syntax wrapper for many package managers. +//! +//! # Compatibility Table +//! +//! Currently, `pacaptr` supports the following operations: +#![doc = pacaptr_macros::compat_table!()] +//! Note: Some flags are "translated" so are not shown in this table, eg. `-p` +//! in `-Sp`. pub mod dispatch; pub mod error; pub mod exec; + pub mod pm; pub mod print; diff --git a/src/pm/apk.rs b/src/pm/apk.rs index 5c16621c8bd..8caec6c94f2 100644 --- a/src/pm/apk.rs +++ b/src/pm/apk.rs @@ -10,19 +10,20 @@ use crate::{ print::{self, PROMPT_RUN}, }; +#[derive(Debug)] pub struct Apk { pub cfg: Config, } static STRAT_PROMPT: Lazy = Lazy::new(|| Strategy { prompt: PromptStrategy::CustomPrompt, - ..Default::default() + ..Strategy::default() }); static STRAT_INSTALL: Lazy = Lazy::new(|| Strategy { prompt: PromptStrategy::CustomPrompt, no_cache: NoCacheStrategy::with_flags(&["--no-cache"]), - ..Default::default() + ..Strategy::default() }); #[async_trait] @@ -75,7 +76,7 @@ impl Pm for Apk { print::print_cmd(&cmd, PROMPT_RUN); } let out_bytes = self - .check_output(cmd, PmMode::Mute, &Default::default()) + .check_output(cmd, PmMode::Mute, &Strategy::default()) .await? .contents; exec::grep_print(&String::from_utf8(out_bytes)?, kws) @@ -93,7 +94,7 @@ impl Pm for Apk { Cmd::with_sudo(&["apk", "del"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -103,7 +104,7 @@ impl Pm for Apk { Cmd::with_sudo(&["apk", "del", "--purge"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -114,7 +115,7 @@ impl Pm for Apk { Cmd::with_sudo(&["apk", "del", "--purge", "-r"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -129,7 +130,7 @@ impl Pm for Apk { Cmd::with_sudo(&["apk", "add"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_INSTALL)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_INSTALL)) .await } @@ -138,7 +139,7 @@ impl Pm for Apk { async fn sc(&self, _kws: &[&str], flags: &[&str]) -> Result<()> { Cmd::with_sudo(&["apk", "cache", "-v", "clean"]) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -146,7 +147,7 @@ impl Pm for Apk { async fn scc(&self, _kws: &[&str], flags: &[&str]) -> Result<()> { Cmd::with_sudo(&["rm", "-vrf", "/var/cache/apk/*"]) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -186,7 +187,7 @@ impl Pm for Apk { }) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_INSTALL)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_INSTALL)) .await } @@ -200,7 +201,7 @@ impl Pm for Apk { }) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_INSTALL)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_INSTALL)) .await } @@ -210,7 +211,7 @@ impl Pm for Apk { Cmd::new(&["apk", "fetch"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -230,7 +231,7 @@ impl Pm for Apk { Cmd::with_sudo(&["apk", "add", "--allow-untrusted"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_INSTALL)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_INSTALL)) .await } } diff --git a/src/pm/apt.rs b/src/pm/apt.rs index 6c16223ea53..9a390800c00 100644 --- a/src/pm/apt.rs +++ b/src/pm/apt.rs @@ -2,22 +2,23 @@ use async_trait::async_trait; use once_cell::sync::Lazy; use tap::prelude::*; -use super::{NoCacheStrategy, Pm, PmHelper, PromptStrategy, Strategy}; +use super::{NoCacheStrategy, Pm, PmHelper, PmMode, PromptStrategy, Strategy}; use crate::{dispatch::config::Config, error::Result, exec::Cmd}; +#[derive(Debug)] pub struct Apt { pub cfg: Config, } static STRAT_PROMPT: Lazy = Lazy::new(|| Strategy { prompt: PromptStrategy::native_no_confirm(&["--yes"]), - ..Default::default() + ..Strategy::default() }); static STRAT_INSTALL: Lazy = Lazy::new(|| Strategy { prompt: PromptStrategy::native_no_confirm(&["--yes"]), no_cache: NoCacheStrategy::Scc, - ..Default::default() + ..Strategy::default() }); #[async_trait] @@ -82,7 +83,7 @@ impl Pm for Apt { Cmd::with_sudo(&["apt", "remove"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -92,7 +93,7 @@ impl Pm for Apt { Cmd::with_sudo(&["apt", "purge"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -103,7 +104,7 @@ impl Pm for Apt { Cmd::with_sudo(&["apt", "autoremove", "--purge"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -113,7 +114,7 @@ impl Pm for Apt { Cmd::with_sudo(&["apt", "autoremove"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -126,7 +127,7 @@ impl Pm for Apt { }) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_INSTALL)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_INSTALL)) .await } @@ -136,7 +137,7 @@ impl Pm for Apt { Cmd::with_sudo(&["apt", "clean"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -145,7 +146,7 @@ impl Pm for Apt { Cmd::with_sudo(&["apt", "autoclean"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -187,11 +188,11 @@ impl Pm for Apt { if kws.is_empty() { Cmd::with_sudo(&["apt", "upgrade"]) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await?; Cmd::with_sudo(&["apt", "dist-upgrade"]) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_INSTALL)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_INSTALL)) .await } else { self.s(kws, flags).await @@ -211,7 +212,7 @@ impl Pm for Apt { Cmd::with_sudo(&["apt", "install", "--download-only"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_INSTALL)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_INSTALL)) .await } diff --git a/src/pm/brew.rs b/src/pm/brew.rs index 4a0b982219c..82d102b2365 100644 --- a/src/pm/brew.rs +++ b/src/pm/brew.rs @@ -10,19 +10,20 @@ use crate::{ print::{self, PROMPT_INFO, PROMPT_RUN}, }; +#[derive(Debug)] pub struct Brew { pub cfg: Config, } static STRAT_PROMPT: Lazy = Lazy::new(|| Strategy { prompt: PromptStrategy::CustomPrompt, - ..Default::default() + ..Strategy::default() }); static STRAT_INSTALL: Lazy = Lazy::new(|| Strategy { prompt: PromptStrategy::CustomPrompt, no_cache: NoCacheStrategy::Scc, - ..Default::default() + ..Strategy::default() }); impl Brew { @@ -32,7 +33,7 @@ impl Brew { print::print_cmd(&cmd, PROMPT_RUN); } let out_bytes = self - .check_output(cmd, PmMode::Mute, &Default::default()) + .check_output(cmd, PmMode::Mute, &Strategy::default()) .await? .contents; @@ -108,7 +109,7 @@ impl Pm for Brew { Cmd::new(&["brew", "uninstall"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -117,12 +118,12 @@ impl Pm for Brew { async fn rss(&self, kws: &[&str], flags: &[&str]) -> Result<()> { let strat = Strategy { dry_run: DryRunStrategy::with_flags(&["--dry-run"]), - ..Default::default() + ..Strategy::default() }; let err_msg = Cmd::new(&["brew", "rmtree"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.check_output(cmd, Default::default(), &strat)) + .pipe(|cmd| self.check_output(cmd, PmMode::default(), &strat)) .await? .contents .pipe(String::from_utf8)?; @@ -151,7 +152,7 @@ impl Pm for Brew { }) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_INSTALL)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_INSTALL)) .await } @@ -161,12 +162,12 @@ impl Pm for Brew { let strat = Strategy { dry_run: DryRunStrategy::with_flags(&["--dry-run"]), prompt: PromptStrategy::CustomPrompt, - ..Default::default() + ..Strategy::default() }; Cmd::new(&["brew", "cleanup"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &strat)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &strat)) .await } @@ -175,12 +176,12 @@ impl Pm for Brew { let strat = Strategy { dry_run: DryRunStrategy::with_flags(&["--dry-run"]), prompt: PromptStrategy::CustomPrompt, - ..Default::default() + ..Strategy::default() }; Cmd::new(&["brew", "cleanup", "-s"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &strat)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &strat)) .await } @@ -209,7 +210,7 @@ impl Pm for Brew { Cmd::new(&["brew", "upgrade"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_INSTALL)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_INSTALL)) .await } @@ -226,7 +227,7 @@ impl Pm for Brew { Cmd::new(&["brew", "fetch"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } diff --git a/src/pm/choco.rs b/src/pm/choco.rs index 7de4a00a079..3f916f606de 100644 --- a/src/pm/choco.rs +++ b/src/pm/choco.rs @@ -2,10 +2,11 @@ use async_trait::async_trait; use once_cell::sync::Lazy; use tap::prelude::*; -use super::{DryRunStrategy, Pm, PmHelper, PromptStrategy, Strategy}; +use super::{DryRunStrategy, Pm, PmHelper, PmMode, PromptStrategy, Strategy}; use crate::exec::Cmd; use crate::{dispatch::config::Config, error::Result}; +#[derive(Debug)] pub struct Choco { pub cfg: Config, } @@ -13,17 +14,17 @@ pub struct Choco { static STRAT_PROMPT: Lazy = Lazy::new(|| Strategy { prompt: PromptStrategy::native_no_confirm(&["--yes"]), dry_run: DryRunStrategy::with_flags(&["--what-if"]), - ..Default::default() + ..Strategy::default() }); static STRAT_CHECK_DRY: Lazy = Lazy::new(|| Strategy { dry_run: DryRunStrategy::with_flags(&["--what-if"]), - ..Default::default() + ..Strategy::default() }); impl Choco { async fn check_dry(&self, cmd: Cmd) -> Result<()> { - self.run_with(cmd, Default::default(), &STRAT_CHECK_DRY) + self.run_with(cmd, PmMode::default(), &STRAT_CHECK_DRY) .await } } @@ -65,7 +66,7 @@ impl Pm for Choco { Cmd::new(&["choco", "uninstall"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -75,7 +76,7 @@ impl Pm for Choco { Cmd::new(&["choco", "uninstall", "--removedependencies"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -88,7 +89,7 @@ impl Pm for Choco { }) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -114,7 +115,7 @@ impl Pm for Choco { }) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } diff --git a/src/pm/conda.rs b/src/pm/conda.rs index e1f4eb5c576..eca91f9ca95 100644 --- a/src/pm/conda.rs +++ b/src/pm/conda.rs @@ -11,13 +11,14 @@ use crate::{ print::{self, PROMPT_RUN}, }; +#[derive(Debug)] pub struct Conda { pub cfg: Config, } static STRAT_PROMPT: Lazy = Lazy::new(|| Strategy { prompt: PromptStrategy::native_no_confirm(&["-y"]), - ..Default::default() + ..Strategy::default() }); #[async_trait] @@ -50,7 +51,7 @@ impl Pm for Conda { print::print_cmd(&cmd, PROMPT_RUN); } let out_bytes = self - .check_output(cmd, PmMode::Mute, &Default::default()) + .check_output(cmd, PmMode::Mute, &Strategy::default()) .await? .contents; exec::grep_print(&String::from_utf8(out_bytes)?, kws)?; @@ -62,7 +63,7 @@ impl Pm for Conda { Cmd::new(&["conda", "remove"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -71,7 +72,7 @@ impl Pm for Conda { Cmd::new(&["conda", "install"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -80,7 +81,7 @@ impl Pm for Conda { async fn sc(&self, _kws: &[&str], flags: &[&str]) -> Result<()> { Cmd::new(&["conda", "clean", "--all"]) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -107,7 +108,7 @@ impl Pm for Conda { Cmd::new(&["conda", "update", "--all"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } diff --git a/src/pm/dnf.rs b/src/pm/dnf.rs index de1e3c267e5..1a85465c1f3 100644 --- a/src/pm/dnf.rs +++ b/src/pm/dnf.rs @@ -11,24 +11,25 @@ use crate::{ print::{self, PROMPT_RUN}, }; +#[derive(Debug)] pub struct Dnf { pub cfg: Config, } static STRAT_PROMPT: Lazy = Lazy::new(|| Strategy { prompt: PromptStrategy::native_no_confirm(&["-y"]), - ..Default::default() + ..Strategy::default() }); static STRAT_PROMPT_CUSTOM: Lazy = Lazy::new(|| Strategy { prompt: PromptStrategy::CustomPrompt, - ..Default::default() + ..Strategy::default() }); static STRAT_INSTALL: Lazy = Lazy::new(|| Strategy { prompt: PromptStrategy::native_no_confirm(&["-y"]), no_cache: NoCacheStrategy::Sccc, - ..Default::default() + ..Strategy::default() }); #[async_trait] @@ -117,7 +118,7 @@ impl Pm for Dnf { print::print_cmd(&cmd, PROMPT_RUN); } let out = self - .check_output(cmd, PmMode::Mute, &Default::default()) + .check_output(cmd, PmMode::Mute, &Strategy::default()) .await? .contents .pipe(String::from_utf8)?; @@ -135,7 +136,7 @@ impl Pm for Dnf { Cmd::with_sudo(&["dnf", "remove"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -144,7 +145,7 @@ impl Pm for Dnf { Cmd::with_sudo(&["dnf", "install"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_INSTALL)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_INSTALL)) .await } @@ -153,7 +154,7 @@ impl Pm for Dnf { async fn sc(&self, _kws: &[&str], flags: &[&str]) -> Result<()> { Cmd::new(&["dnf", "clean", "expire-cache"]) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT_CUSTOM)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT_CUSTOM)) .await } @@ -161,7 +162,7 @@ impl Pm for Dnf { async fn scc(&self, _kws: &[&str], flags: &[&str]) -> Result<()> { Cmd::new(&["dnf", "clean", "packages"]) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT_CUSTOM)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT_CUSTOM)) .await } @@ -170,7 +171,7 @@ impl Pm for Dnf { async fn sccc(&self, _kws: &[&str], flags: &[&str]) -> Result<()> { Cmd::new(&["dnf", "clean", "all"]) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT_CUSTOM)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT_CUSTOM)) .await } @@ -225,7 +226,7 @@ impl Pm for Dnf { Cmd::with_sudo(&["dnf", "upgrade"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_INSTALL)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_INSTALL)) .await } @@ -241,7 +242,7 @@ impl Pm for Dnf { Cmd::with_sudo(&["dnf", "install", "--downloadonly"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_INSTALL)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_INSTALL)) .await } diff --git a/src/pm/emerge.rs b/src/pm/emerge.rs index c7ca685b3b1..3faf04359f1 100644 --- a/src/pm/emerge.rs +++ b/src/pm/emerge.rs @@ -3,27 +3,28 @@ use itertools::Itertools; use once_cell::sync::Lazy; use tap::prelude::*; -use super::{NoCacheStrategy, Pm, PmHelper, PromptStrategy, Strategy}; +use super::{NoCacheStrategy, Pm, PmHelper, PmMode, PromptStrategy, Strategy}; use crate::{dispatch::config::Config, error::Result, exec::Cmd}; +#[derive(Debug)] pub struct Emerge { pub cfg: Config, } static STRAT_ASK: Lazy = Lazy::new(|| Strategy { prompt: PromptStrategy::native_confirm(&["--ask"]), - ..Default::default() + ..Strategy::default() }); static STRAT_INTERACTIVE: Lazy = Lazy::new(|| Strategy { prompt: PromptStrategy::native_confirm(&["--interactive"]), - ..Default::default() + ..Strategy::default() }); static STRAT_INSTALL: Lazy = Lazy::new(|| Strategy { prompt: PromptStrategy::native_confirm(&["--ask"]), no_cache: NoCacheStrategy::Scc, - ..Default::default() + ..Strategy::default() }); #[async_trait] @@ -77,7 +78,7 @@ impl Pm for Emerge { Cmd::with_sudo(&["emerge", "--unmerge"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_ASK)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_ASK)) .await } @@ -87,7 +88,7 @@ impl Pm for Emerge { Cmd::with_sudo(&["emerge", "--depclean"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_ASK)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_ASK)) .await } @@ -96,7 +97,7 @@ impl Pm for Emerge { Cmd::with_sudo(&["emerge"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_INSTALL)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_INSTALL)) .await } @@ -106,7 +107,7 @@ impl Pm for Emerge { Cmd::with_sudo(&["eclean-dist"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_INTERACTIVE)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_INTERACTIVE)) .await } @@ -133,7 +134,7 @@ impl Pm for Emerge { Cmd::with_sudo(&["emerge", "-uDN"]) .kws(if kws.is_empty() { &["@world"] } else { kws }) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_INSTALL)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_INSTALL)) .await } diff --git a/src/pm/mod.rs b/src/pm/mod.rs index 8da5cb6878e..7e8c41abc91 100644 --- a/src/pm/mod.rs +++ b/src/pm/mod.rs @@ -3,6 +3,8 @@ //! //! [`pacman`]: https://wiki.archlinux.org/index.php/Pacman +#![allow(clippy::module_name_repetitions)] + pub mod apk; pub mod apt; pub mod brew; @@ -33,8 +35,9 @@ use crate::{ exec::{Cmd, Mode, Output, StatusCode}, }; -/// The list of `pacman` methods supported by `pacaptr`. +/// The list of [`pacman`](https://wiki.archlinux.org/index.php/Pacman) methods supported by [`pacaptr`](crate). #[macro_export] +#[doc(hidden)] macro_rules! methods { ($caller:tt) => { tt_call::tt_return! { @@ -244,14 +247,12 @@ pub trait PmHelper: Pm { /// Executes a command in the context of the [`Pm`] implementation. Returns /// the [`Output`] of this command. async fn check_output(&self, mut cmd: Cmd, mode: PmMode, strat: &Strategy) -> Result { - let cfg = self.cfg(); - async fn run(cfg: &Config, cmd: &Cmd, mode: PmMode, strat: &Strategy) -> Result { let mut curr_cmd = cmd.clone(); let no_confirm = cfg.no_confirm; if cfg.no_cache { if let NoCacheStrategy::WithFlags(v) = &strat.no_cache { - curr_cmd.flags.extend(v.to_owned()); + curr_cmd.flags.extend(v.clone()); } } match &strat.prompt { @@ -260,24 +261,26 @@ pub trait PmHelper: Pm { PromptStrategy::CustomPrompt => curr_cmd.exec(Mode::Prompt).await, PromptStrategy::NativeNoConfirm(v) => { if no_confirm { - curr_cmd.flags.extend(v.to_owned()); + curr_cmd.flags.extend(v.clone()); } curr_cmd.exec(mode.into()).await } PromptStrategy::NativeConfirm(v) => { if !no_confirm { - curr_cmd.flags.extend(v.to_owned()); + curr_cmd.flags.extend(v.clone()); } curr_cmd.exec(mode.into()).await } } } + let cfg = self.cfg(); + // `--dry-run` should apply to both the main command and the cleanup. let res = match &strat.dry_run { DryRunStrategy::PrintCmd if cfg.dry_run => cmd.clone().exec(Mode::PrintCmd).await?, DryRunStrategy::WithFlags(v) if cfg.dry_run => { - cmd.flags.extend(v.to_owned()); + cmd.flags.extend(v.clone()); // -- A dry run with extra flags does not need `sudo`. -- cmd = cmd.sudo(false); run(cfg, &cmd, mode, strat).await? @@ -311,7 +314,7 @@ pub trait PmHelper: Pm { /// Executes a command in the context of the [`Pm`] implementation with /// default settings. async fn run(&self, cmd: Cmd) -> Result<()> { - self.run_with(cmd, Default::default(), &Default::default()) + self.run_with(cmd, PmMode::default(), &Strategy::default()) .await } } @@ -371,6 +374,7 @@ pub enum DryRunStrategy { } impl DryRunStrategy { + #[must_use] pub fn with_flags(flags: &[&str]) -> Self { Self::WithFlags(flags.iter().map(|&s| s.to_owned()).collect()) } @@ -398,10 +402,12 @@ pub enum PromptStrategy { } impl PromptStrategy { + #[must_use] pub fn native_no_confirm(no_confirm: &[&str]) -> Self { Self::NativeNoConfirm(no_confirm.iter().map(|&s| s.to_owned()).collect()) } + #[must_use] pub fn native_confirm(confirm: &[&str]) -> Self { Self::NativeConfirm(confirm.iter().map(|&s| s.to_owned()).collect()) } @@ -431,6 +437,7 @@ pub enum NoCacheStrategy { } impl NoCacheStrategy { + #[must_use] pub fn with_flags(flags: &[&str]) -> Self { Self::WithFlags(flags.iter().map(|&s| s.to_owned()).collect()) } diff --git a/src/pm/pip.rs b/src/pm/pip.rs index 6f92c729411..8036809559c 100644 --- a/src/pm/pip.rs +++ b/src/pm/pip.rs @@ -5,11 +5,12 @@ use tap::prelude::*; use super::{Pm, PmHelper, PmMode, PromptStrategy, Strategy}; use crate::{ dispatch::config::Config, - error::Result, + error::{Error, Result}, exec::{self, Cmd}, print::{self, PROMPT_RUN}, }; +#[derive(Debug)] pub struct Pip { pub cmd: String, pub cfg: Config, @@ -17,12 +18,12 @@ pub struct Pip { static STRAT_PROMPT: Lazy = Lazy::new(|| Strategy { prompt: PromptStrategy::CustomPrompt, - ..Default::default() + ..Strategy::default() }); static STRAT_UNINSTALL: Lazy = Lazy::new(|| Strategy { prompt: PromptStrategy::native_no_confirm(&["-y"]), - ..Default::default() + ..Strategy::default() }); #[async_trait] @@ -62,7 +63,7 @@ impl Pm for Pip { print::print_cmd(&cmd, PROMPT_RUN); } let out_bytes = self - .check_output(cmd, PmMode::Mute, &Default::default()) + .check_output(cmd, PmMode::Mute, &Strategy::default()) .await? .contents; exec::grep_print(&String::from_utf8(out_bytes)?, kws)?; @@ -83,7 +84,7 @@ impl Pm for Pip { Cmd::new(&[&self.cmd, "uninstall"] as _) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_UNINSTALL)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_UNINSTALL)) .await } @@ -92,7 +93,7 @@ impl Pm for Pip { Cmd::new(&[&self.cmd, "install"] as _) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -105,18 +106,17 @@ impl Pm for Pip { /// Su updates outdated packages. async fn su(&self, kws: &[&str], flags: &[&str]) -> Result<()> { - if !kws.is_empty() { - Cmd::new(&[&self.cmd, "install", "--upgrade"] as _) - .kws(kws) - .flags(flags) - .pipe(|cmd| self.run(cmd)) - .await - } else { - Err(crate::error::Error::OperationUnimplementedError { + if kws.is_empty() { + return Err(Error::OperationUnimplementedError { op: "su".into(), pm: self.name().into(), - }) + }); } + Cmd::new(&[&self.cmd, "install", "--upgrade"] as _) + .kws(kws) + .flags(flags) + .pipe(|cmd| self.run(cmd)) + .await } /// Sw retrieves all packages from the server, but does not install/upgrade diff --git a/src/pm/port.rs b/src/pm/port.rs index 780e3b6a69f..0e66cafcc06 100644 --- a/src/pm/port.rs +++ b/src/pm/port.rs @@ -2,22 +2,23 @@ use async_trait::async_trait; use once_cell::sync::Lazy; use tap::prelude::*; -use super::{NoCacheStrategy, Pm, PmHelper, PromptStrategy, Strategy}; +use super::{NoCacheStrategy, Pm, PmHelper, PmMode, PromptStrategy, Strategy}; use crate::{dispatch::config::Config, error::Result, exec::Cmd}; +#[derive(Debug)] pub struct Port { pub cfg: Config, } static STRAT_PROMPT: Lazy = Lazy::new(|| Strategy { prompt: PromptStrategy::CustomPrompt, - ..Default::default() + ..Strategy::default() }); static STRAT_INSTALL: Lazy = Lazy::new(|| Strategy { prompt: PromptStrategy::CustomPrompt, no_cache: NoCacheStrategy::Scc, - ..Default::default() + ..Strategy::default() }); #[async_trait] @@ -80,7 +81,7 @@ impl Pm for Port { Cmd::with_sudo(&["port", "uninstall"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -90,7 +91,7 @@ impl Pm for Port { Cmd::with_sudo(&["port", "uninstall", "--follow-dependencies"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -99,7 +100,7 @@ impl Pm for Port { Cmd::with_sudo(&["port", "install"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_INSTALL)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_INSTALL)) .await } @@ -113,7 +114,7 @@ impl Pm for Port { }) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -126,7 +127,7 @@ impl Pm for Port { }) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -152,7 +153,7 @@ impl Pm for Port { }) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_INSTALL)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_INSTALL)) .await } diff --git a/src/pm/scoop.rs b/src/pm/scoop.rs index 4216537676f..cde06edc0ef 100644 --- a/src/pm/scoop.rs +++ b/src/pm/scoop.rs @@ -10,19 +10,20 @@ use crate::{ print::{self, PROMPT_RUN}, }; +#[derive(Debug)] pub struct Scoop { pub cfg: Config, } static STRAT_PROMPT: Lazy = Lazy::new(|| Strategy { prompt: PromptStrategy::CustomPrompt, - ..Default::default() + ..Strategy::default() }); static STRAT_INSTALL: Lazy = Lazy::new(|| Strategy { prompt: PromptStrategy::CustomPrompt, no_cache: NoCacheStrategy::Scc, - ..Default::default() + ..Strategy::default() }); impl Scoop { @@ -32,7 +33,7 @@ impl Scoop { print::print_cmd(&cmd, PROMPT_RUN); } let out_bytes = self - .check_output(cmd, PmMode::Mute, &Default::default()) + .check_output(cmd, PmMode::Mute, &Strategy::default()) .await? .contents; @@ -91,7 +92,7 @@ impl Pm for Scoop { Cmd::new(&["powershell", "scoop", "uninstall"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -101,7 +102,7 @@ impl Pm for Scoop { Cmd::new(&["powershell", "scoop", "uninstall", "--purge"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -110,7 +111,7 @@ impl Pm for Scoop { Cmd::new(&["powershell", "scoop", "install"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_INSTALL)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_INSTALL)) .await } @@ -120,7 +121,7 @@ impl Pm for Scoop { Cmd::new(&["powershell", "scoop", "cache", "rm"]) .kws(if kws.is_empty() { &["*"] } else { kws }) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -163,7 +164,7 @@ impl Pm for Scoop { Cmd::new(&["powershell", "scoop", "update"]) .kws(if kws.is_empty() { &["*"] } else { kws }) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_INSTALL)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_INSTALL)) .await } diff --git a/src/pm/tlmgr.rs b/src/pm/tlmgr.rs index a18f6636000..fda4ad748be 100644 --- a/src/pm/tlmgr.rs +++ b/src/pm/tlmgr.rs @@ -2,16 +2,17 @@ use async_trait::async_trait; use once_cell::sync::Lazy; use tap::prelude::*; -use super::{DryRunStrategy, Pm, PmHelper, Strategy}; +use super::{DryRunStrategy, Pm, PmHelper, PmMode, Strategy}; use crate::{dispatch::config::Config, error::Result, exec::Cmd}; +#[derive(Debug)] pub struct Tlmgr { pub cfg: Config, } static STRAT_CHECK_DRY: Lazy = Lazy::new(|| Strategy { dry_run: DryRunStrategy::with_flags(&["--dry-run"]), - ..Default::default() + ..Strategy::default() }); #[async_trait] @@ -59,7 +60,7 @@ impl Pm for Tlmgr { Cmd::new(&["tlmgr", "remove"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_CHECK_DRY)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_CHECK_DRY)) .await } @@ -68,7 +69,7 @@ impl Pm for Tlmgr { Cmd::new(&["tlmgr", "install"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_CHECK_DRY)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_CHECK_DRY)) .await } @@ -103,7 +104,7 @@ impl Pm for Tlmgr { }) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_CHECK_DRY)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_CHECK_DRY)) .await } @@ -119,7 +120,7 @@ impl Pm for Tlmgr { Cmd::new(&["tlmgr", "install", "--file"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_CHECK_DRY)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_CHECK_DRY)) .await } } diff --git a/src/pm/unknown.rs b/src/pm/unknown.rs index 698912c3cae..c15ac57b11e 100644 --- a/src/pm/unknown.rs +++ b/src/pm/unknown.rs @@ -1,16 +1,19 @@ use super::Pm; use crate::dispatch::config::Config; +#[derive(Debug)] pub struct Unknown { pub name: String, pub cfg: Config, } impl Unknown { + #[must_use] + /// Creates a new [`Unknown`] package manager with the given name. pub fn new(name: &str) -> Self { Unknown { name: format!("unknown package manager: {}", name), - cfg: Default::default(), + cfg: Config::default(), } } } diff --git a/src/pm/zypper.rs b/src/pm/zypper.rs index ef45b704ca3..b6700f3b60d 100644 --- a/src/pm/zypper.rs +++ b/src/pm/zypper.rs @@ -9,19 +9,20 @@ use crate::{ exec::{self, Cmd}, }; +#[derive(Debug)] pub struct Zypper { pub cfg: Config, } static STRAT_CHECK_DRY: Lazy = Lazy::new(|| Strategy { dry_run: DryRunStrategy::with_flags(&["--dry-run"]), - ..Default::default() + ..Strategy::default() }); static STRAT_PROMPT: Lazy = Lazy::new(|| Strategy { prompt: PromptStrategy::native_no_confirm(&["-y"]), dry_run: DryRunStrategy::with_flags(&["--dry-run"]), - ..Default::default() + ..Strategy::default() }); static STRAT_INSTALL: Lazy = Lazy::new(|| Strategy { @@ -32,7 +33,7 @@ static STRAT_INSTALL: Lazy = Lazy::new(|| Strategy { impl Zypper { async fn check_dry(&self, cmd: Cmd) -> Result<()> { - self.run_with(cmd, Default::default(), &STRAT_CHECK_DRY) + self.run_with(cmd, PmMode::default(), &STRAT_CHECK_DRY) .await } } @@ -85,7 +86,7 @@ impl Pm for Zypper { async fn qm(&self, kws: &[&str], flags: &[&str]) -> Result<()> { let cmd = Cmd::new(&["zypper", "search", "-si"]).kws(kws).flags(flags); let out_bytes = self - .check_output(cmd, PmMode::Mute, &Default::default()) + .check_output(cmd, PmMode::Mute, &Strategy::default()) .await? .contents; let out = String::from_utf8(out_bytes)?; @@ -130,7 +131,7 @@ impl Pm for Zypper { Cmd::with_sudo(&["zypper", "remove"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -140,7 +141,7 @@ impl Pm for Zypper { Cmd::with_sudo(&["zypper", "remove", "--clean-deps"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_PROMPT)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_PROMPT)) .await } @@ -149,7 +150,7 @@ impl Pm for Zypper { Cmd::with_sudo(&["zypper", "install"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_INSTALL)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_INSTALL)) .await } @@ -158,11 +159,11 @@ impl Pm for Zypper { async fn sc(&self, _kws: &[&str], flags: &[&str]) -> Result<()> { let strat = Strategy { prompt: PromptStrategy::CustomPrompt, - ..Default::default() + ..Strategy::default() }; Cmd::with_sudo(&["zypper", "clean"]) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &strat)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &strat)) .await } @@ -221,7 +222,7 @@ impl Pm for Zypper { async fn su(&self, _kws: &[&str], flags: &[&str]) -> Result<()> { Cmd::with_sudo(&["zypper", "--no-refresh", "dist-upgrade"]) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_INSTALL)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_INSTALL)) .await } @@ -230,7 +231,7 @@ impl Pm for Zypper { async fn suy(&self, _kws: &[&str], flags: &[&str]) -> Result<()> { Cmd::with_sudo(&["zypper", "dist-upgrade"]) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_INSTALL)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_INSTALL)) .await } @@ -240,7 +241,7 @@ impl Pm for Zypper { Cmd::with_sudo(&["zypper", "install", "--download-only"]) .kws(kws) .flags(flags) - .pipe(|cmd| self.run_with(cmd, Default::default(), &STRAT_INSTALL)) + .pipe(|cmd| self.run_with(cmd, PmMode::default(), &STRAT_INSTALL)) .await } diff --git a/src/print.rs b/src/print.rs index 388ee7fc85d..17316d78ae5 100644 --- a/src/print.rs +++ b/src/print.rs @@ -1,5 +1,7 @@ //! Output messages and prompts. +#![allow(missing_docs, clippy::module_name_repetitions)] + use colored::Colorize; use crate::exec::Cmd; @@ -10,6 +12,7 @@ pub static PROMPT_RUN: &str = "Running"; pub static PROMPT_INFO: &str = "Info"; pub static PROMPT_ERROR: &str = "Error"; +/// The right indentation to be applied on prompt prefixes. pub static PROMPT_INDENT: usize = 9; macro_rules! prompt_format { @@ -43,7 +46,7 @@ pub fn print_cmd(cmd: &Cmd, prompt: &str) { prompt.green().bold(), cmd, indent = PROMPT_INDENT - ) + ); } /// Prints out a message after the given prompt. diff --git a/tests/common.rs b/tests/common.rs index e0fb73d9341..1d70267f3d9 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -9,6 +9,7 @@ enum Input<'i> { args: &'i [&'i str], flags: &'i [&'i str], }, + #[allow(dead_code)] Exec { cmd: &'i [&'i str], kws: &'i [&'i str], @@ -45,6 +46,7 @@ impl<'t> Test<'t> { self } + #[allow(dead_code)] pub fn exec(mut self, cmd: &'t [&str], kws: &'t [&str]) -> Self { // Guard against consecutive inputs without calling `self.output()`. if self.pending_input.is_some() {