From d71068cab8c34ebb897c2e8d7435b28fc69c1aad Mon Sep 17 00:00:00 2001 From: nanocryk <6422796+nanocryk@users.noreply.github.com> Date: Tue, 20 Dec 2022 19:38:55 +0100 Subject: [PATCH] Add workspace ignore list (#57) * include ignored list from workspace * used but workspace ignored should NOT give a warning * remove unused default impl * fix clippy warnings Co-authored-by: Benjamin Bouvier --- .../ignored-dep-workspace/Cargo.lock | 267 ++++++++++++++++++ .../ignored-dep-workspace/Cargo.toml | 13 + .../ignored-dep-workspace/inner/Cargo.toml | 20 ++ .../ignored-dep-workspace/inner/src/main.rs | 9 + src/main.rs | 6 +- src/search_unused.rs | 65 +++-- 6 files changed, 358 insertions(+), 22 deletions(-) create mode 100644 integration-tests/ignored-dep-workspace/Cargo.lock create mode 100644 integration-tests/ignored-dep-workspace/Cargo.toml create mode 100644 integration-tests/ignored-dep-workspace/inner/Cargo.toml create mode 100644 integration-tests/ignored-dep-workspace/inner/src/main.rs diff --git a/integration-tests/ignored-dep-workspace/Cargo.lock b/integration-tests/ignored-dep-workspace/Cargo.lock new file mode 100644 index 0000000..0591fe0 --- /dev/null +++ b/integration-tests/ignored-dep-workspace/Cargo.lock @@ -0,0 +1,267 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "futures" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" + +[[package]] +name = "futures-executor" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" + +[[package]] +name = "futures-macro" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" + +[[package]] +name = "futures-task" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" + +[[package]] +name = "futures-util" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "ignored-dep" +version = "0.1.0" +dependencies = [ + "futures", + "lazy_static", + "log-once", + "rand", + "rand_core", + "serde", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.138" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "log-once" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aba6f00890254f37df9778e2df6042249f543ab1789cbe001c50b4debe264a8c" +dependencies = [ + "log", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "serde" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e326c9ec8042f1b5da33252c8a37e9ffbd2c9bef0155215b6e6c80c790e05f91" + +[[package]] +name = "slab" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] + +[[package]] +name = "syn" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/integration-tests/ignored-dep-workspace/Cargo.toml b/integration-tests/ignored-dep-workspace/Cargo.toml new file mode 100644 index 0000000..44a16f5 --- /dev/null +++ b/integration-tests/ignored-dep-workspace/Cargo.toml @@ -0,0 +1,13 @@ +[workspace] +members = ["./inner"] + +[workspace.dependencies] +log = "0.4.14" +serde = "1" + +[workspace.metadata.cargo-machete] +ignored = [ + "lazy_static", + "serde", + "futures", # actually used but in workspace ignored, should NOT cause a warning +] \ No newline at end of file diff --git a/integration-tests/ignored-dep-workspace/inner/Cargo.toml b/integration-tests/ignored-dep-workspace/inner/Cargo.toml new file mode 100644 index 0000000..99dff34 --- /dev/null +++ b/integration-tests/ignored-dep-workspace/inner/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "ignored-dep" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +log-once = "0.3.1" +rand = "0.8.5" +rand_core = "0.6.3" +lazy_static = "1.4.0" +serde.workspace = true +futures = "0.3" + +[package.metadata.cargo-machete] +ignored = [ + "log", + "rand_core" # actually used, should cause a warning +] diff --git a/integration-tests/ignored-dep-workspace/inner/src/main.rs b/integration-tests/ignored-dep-workspace/inner/src/main.rs new file mode 100644 index 0000000..7355076 --- /dev/null +++ b/integration-tests/ignored-dep-workspace/inner/src/main.rs @@ -0,0 +1,9 @@ +#[allow(unused_imports)] +use rand_core::Error as _; + +#[allow(unused_imports)] +use futures::Future as _; + +fn main() { + log_once::warn_once!("Hello, world!"); +} diff --git a/src/main.rs b/src/main.rs index efface7..de878a5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -84,7 +84,7 @@ fn collect_paths(path: &Path, skip_target_dir: bool) -> Vec { .filter_map(|entry| match entry { Ok(entry) if entry.file_name() == "Cargo.toml" => Some(entry.into_path()), Err(err) => { - eprintln!("error when walking over subdirectories: {}", err); + eprintln!("error when walking over subdirectories: {err}"); None } _ => None, @@ -181,7 +181,7 @@ fn run_machete() -> anyhow::Result { for (analysis, path) in results { println!("{} -- {}:", analysis.package_name, path.to_string_lossy()); for dep in &analysis.unused { - println!("\t{}", dep); + println!("\t{dep}"); has_unused_dependencies = true; // any unused dependency is enough to set flag to true } @@ -214,7 +214,7 @@ fn remove_dependencies(manifest: &str, dependencies_list: &[String]) -> anyhow:: for k in dependencies_list { dependencies .remove(k) - .with_context(|| format!("Dependency {} not found", k))?; + .with_context(|| format!("Dependency {k} not found"))?; } let serialized = manifest.to_string(); diff --git a/src/search_unused.rs b/src/search_unused.rs index 1660998..c891f33 100644 --- a/src/search_unused.rs +++ b/src/search_unused.rs @@ -150,7 +150,7 @@ fn collect_paths(dir_path: &Path, analysis: &PackageAnalysis) -> Vec { let dir_entry = match result { Ok(dir_entry) => dir_entry, Err(err) => { - eprintln!("{}", err); + eprintln!("{err}"); return None; } }; @@ -168,7 +168,7 @@ fn collect_paths(dir_path: &Path, analysis: &PackageAnalysis) -> Vec { }) .collect(); - trace!("found transitive paths: {:?}", paths); + trace!("found transitive paths: {paths:?}"); paths } @@ -267,7 +267,7 @@ impl Search { fn get_full_manifest( dir_path: &Path, manifest_path: &Path, -) -> anyhow::Result> { +) -> anyhow::Result<(cargo_toml::Manifest, Vec)> { // HACK: we can't plain use `from_path_with_metadata` here, because it calls // `complete_from_path` just a bit too early (before we've had a chance to call // `inherit_workspace`). See https://gitlab.com/crates.rs/cargo_toml/-/issues/20 for details, @@ -276,12 +276,27 @@ fn get_full_manifest( let mut manifest = cargo_toml::Manifest::::from_slice_with_metadata(&cargo_toml_content)?; + let mut workspace_ignored = vec![]; + let mut dir_path = dir_path.join("../"); while dir_path.exists() { let workspace_cargo_path = dir_path.join("Cargo.toml"); - if let Ok(workspace_manifest) = cargo_toml::Manifest::from_path(&workspace_cargo_path) { - if workspace_manifest.workspace.is_some() { + if let Ok(workspace_manifest) = + cargo_toml::Manifest::::from_path_with_metadata(&workspace_cargo_path) + { + if let Some(workspace) = &workspace_manifest.workspace { manifest.inherit_workspace(&workspace_manifest, &workspace_cargo_path)?; + + // Look for `workspace.metadata.cargo-machete.ignored` in the workspace Cargo.toml. + if let Some(ignored) = workspace + .metadata + .as_ref() + .and_then(|metadata| metadata.cargo_machete.as_ref()) + .map(|machete| &machete.ignored) + { + workspace_ignored = ignored.clone(); + } + break; } } @@ -290,7 +305,7 @@ fn get_full_manifest( manifest.complete_from_path(manifest_path)?; - Ok(manifest) + Ok((manifest, workspace_ignored)) } pub(crate) fn find_unused( @@ -302,7 +317,7 @@ pub(crate) fn find_unused( trace!("trying to open {}...", manifest_path.display()); - let manifest = get_full_manifest(&dir_path, manifest_path)?; + let (manifest, workspace_ignored) = get_full_manifest(&dir_path, manifest_path)?; let package_name = match manifest.package { Some(ref package) => package.name.clone(), @@ -352,11 +367,12 @@ pub(crate) fn find_unused( .manifest .package .as_ref() - .unwrap() - .metadata - .as_ref() + .and_then(|package| package.metadata.as_ref()) .and_then(|meta| meta.cargo_machete.as_ref()) - .map(|meta| meta.ignored.iter().collect::>()); + .map(|meta| meta.ignored.iter().collect::>()) + .unwrap_or_default(); + + let workspace_ignored: HashSet<_> = workspace_ignored.into_iter().collect(); enum SingleDepResult { /// Dependency is unused and not marked as ignored. @@ -386,18 +402,16 @@ pub(crate) fn find_unused( } if !found_once { - if let Some(ref ignored) = ignored { - if ignored.contains(&name) { - return None; - } + if ignored.contains(&name) || workspace_ignored.contains(&name) { + return None; } + Some(SingleDepResult::Unused(name)) } else { - if let Some(ref ignored) = ignored { - if ignored.contains(&name) { - return Some(SingleDepResult::IgnoredButUsed(name)); - } + if ignored.contains(&name) { + return Some(SingleDepResult::IgnoredButUsed(name)); } + None } }) @@ -679,3 +693,16 @@ fn test_ignore_deps_works() { assert_eq!(analysis.ignored_used, &["rand_core".to_string()]); }); } + +#[test] +fn test_ignore_deps_workspace_works() { + // ensure that ignored deps listed in Cargo.toml workspace.metadata.cargo-machete.ignore are + // correctly ignored. + check_analysis( + "./integration-tests/ignored-dep-workspace/inner/Cargo.toml", + |analysis| { + assert_eq!(analysis.unused, &["rand".to_string()]); + assert_eq!(analysis.ignored_used, &["rand_core".to_string()]); + }, + ); +}