Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ zepter
- lint
- propagate-features: Check that features are passed down.
- never-enables: A feature should never enable another other.
- duplicate-deps: Check that dependencies are not defined in both normal an dev sections.
- never-implies *(unstable)*: A feature should never transitively imply another one.
- only-enables *(unstable)*: A features should exclusively enable another one.
- why-enables *(unstable)*: Find out why a specific feature is enables.
Expand Down
59 changes: 58 additions & 1 deletion src/cmd/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use core::{
fmt::{Display, Formatter},
};
use std::{
collections::{BTreeMap, BTreeSet, HashMap},
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
fs::canonicalize,
path::PathBuf,
};
Expand Down Expand Up @@ -48,6 +48,8 @@ pub enum SubCommand {
WhyEnabled(WhyEnabledCmd),
/// Check the crates for sane no-std feature configuration.
NoStd(NoStdCmd),
/// Check for duplicated dependencies in `[dependencies]` and `[dev-dependencies]`.
DuplicateDeps(DuplicateDepsCmd),
}

#[derive(Debug, clap::Parser)]
Expand Down Expand Up @@ -280,6 +282,10 @@ impl LintCmd {
Ok(())
},
SubCommand::NoStd(cmd) => cmd.run(global),
SubCommand::DuplicateDeps(cmd) => {
cmd.run(global);
Ok(())
},
}
}
}
Expand Down Expand Up @@ -795,6 +801,57 @@ impl WhyEnabledCmd {
}
}

#[derive(Debug, clap::Parser)]
pub struct DuplicateDepsCmd {
#[allow(missing_docs)]
#[clap(flatten)]
cargo_args: super::CargoArgs,
}

impl DuplicateDepsCmd {
pub fn run(&self, _global: &GlobalArgs) {
// To easily compare dependencies, we normalize them by removing the kind.
fn normalize_dep(dep: &cargo_metadata::Dependency) -> cargo_metadata::Dependency {
let mut dep = dep.clone();
dep.kind = cargo_metadata::DependencyKind::Unknown;
dep
}

let meta = self.cargo_args.load_metadata().expect("Loads metadata");

let mut issues = vec![];

for pkg in &meta.workspace_packages() {
let deps: HashSet<_> = pkg
.dependencies
.iter()
.filter(|d| d.kind == cargo_metadata::DependencyKind::Normal)
.map(normalize_dep)
.collect();

let dev_deps: HashSet<_> = pkg
.dependencies
.iter()
.filter(|d| d.kind == cargo_metadata::DependencyKind::Development)
.map(normalize_dep)
.collect();

for dep in deps.intersection(&dev_deps) {
issues.push(format!(
"Package `{}` has duplicated `{}` in both [dependencies] and [dev-dependencies]",
pkg.name, dep.name
));
}
}

if !issues.is_empty() {
for issue in issues {
println!("{issue}");
}
std::process::exit(1);
}
}
}
// Complexity is `O(x ^ 4) with x=pkgs.len()`.
pub fn build_feature_dag(meta: &Metadata, pkgs: &[Package]) -> Dag<CrateAndFeature> {
let mut dag = Dag::new();
Expand Down
37 changes: 37 additions & 0 deletions tests/ui/lint/duplicate-deps/dep_kinds_multiple.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
crates:
- name: A
deps:
- name: BD
kind: dev
- name: BD
kind: build
features:
F0: null
- name: B
deps:
- name: ND
- name: ND
kind: dev
features:
F0: null
- name: C
deps:
- name: NB
- name: NB
kind: build
features:
F0: null
- name: BD
features:
F0: null
- name: ND
features:
F0: null
- name: NB
features:
F0: null
cases:
- cmd: lint duplicate-deps
stdout: |
Package `B` has duplicated `ND` in both [dependencies] and [dev-dependencies]
code: 1
2 changes: 1 addition & 1 deletion tests/ui/root-args/help.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ cases:
- cmd: --help
stdout: "Analyze, Fix and Format features in your Rust workspace.\n\nUsage: zepter [OPTIONS] [COMMAND]\n\nCommands:\n trace Trace the dependency path from one crate to another\n lint Lint your feature usage by analyzing crate metadata\n format Format the features in your manifest files\n run \n debug Arguments for how to load cargo metadata from a workspace\n help Print this message or the help of the given subcommand(s)\n\nOptions:\n -q, --quiet\n Only print errors. Supersedes `--log`\n\n --log <LEVEL>\n Log level to use\n \n [default: info]\n\n --color\n Use ANSI terminal colors\n\n --exit-code-zero\n Try to exit with code zero if the intended check failed.\n \n Will still return 1 in case of an actual error (eg. failed to find some file) or a panic\n (aka software bug).\n\n --fix-hint <FIX_HINT>\n Dont print any hints on how to fix the error.\n \n This is mostly used internally when dispatching, workflows since they come with their\n hints.\n \n [default: on]\n\n Possible values:\n - on: Prints some hint that is (hopefully) helpful\n - off: Prints no hint at all\n\n -h, --help\n Print help (see a summary with '-h')\n\n -V, --version\n Print version\n"
- cmd: lint --help
stdout: "Lint your feature usage by analyzing crate metadata\n\nUsage: zepter lint [OPTIONS] <COMMAND>\n\nCommands:\n propagate-feature Check whether features are properly propagated\n never-enables A specific feature never enables a specific other feature\n never-implies A specific feature never implies a specific other feature\n only-enables A specific feature is only implied by a specific set of other features\n why-enabled Arguments for how to load cargo metadata from a workspace\n no-std Check the crates for sane no-std feature configuration\n help Print this message or the help of the given subcommand(s)\n\nOptions:\n -q, --quiet\n Only print errors. Supersedes `--log`\n\n --log <LEVEL>\n Log level to use\n \n [default: info]\n\n --color\n Use ANSI terminal colors\n\n --exit-code-zero\n Try to exit with code zero if the intended check failed.\n \n Will still return 1 in case of an actual error (eg. failed to find some file) or a panic\n (aka software bug).\n\n --fix-hint <FIX_HINT>\n Dont print any hints on how to fix the error.\n \n This is mostly used internally when dispatching, workflows since they come with their\n hints.\n \n [default: on]\n\n Possible values:\n - on: Prints some hint that is (hopefully) helpful\n - off: Prints no hint at all\n\n -h, --help\n Print help (see a summary with '-h')\n"
stdout: "Lint your feature usage by analyzing crate metadata\n\nUsage: zepter lint [OPTIONS] <COMMAND>\n\nCommands:\n propagate-feature Check whether features are properly propagated\n never-enables A specific feature never enables a specific other feature\n never-implies A specific feature never implies a specific other feature\n only-enables A specific feature is only implied by a specific set of other features\n why-enabled Arguments for how to load cargo metadata from a workspace\n no-std Check the crates for sane no-std feature configuration\n duplicate-deps Check for duplicated dependencies in `[dependencies]` and `[dev-dependencies]`\n help Print this message or the help of the given subcommand(s)\n\nOptions:\n -q, --quiet\n Only print errors. Supersedes `--log`\n\n --log <LEVEL>\n Log level to use\n \n [default: info]\n\n --color\n Use ANSI terminal colors\n\n --exit-code-zero\n Try to exit with code zero if the intended check failed.\n \n Will still return 1 in case of an actual error (eg. failed to find some file) or a panic\n (aka software bug).\n\n --fix-hint <FIX_HINT>\n Dont print any hints on how to fix the error.\n \n This is mostly used internally when dispatching, workflows since they come with their\n hints.\n \n [default: on]\n\n Possible values:\n - on: Prints some hint that is (hopefully) helpful\n - off: Prints no hint at all\n\n -h, --help\n Print help (see a summary with '-h')\n"
- cmd: lint propagate-feature --help
stdout: "Check whether features are properly propagated\n\nUsage: zepter lint propagate-feature [OPTIONS] --features <FEATURES>\n\nOptions:\n --manifest-path <MANIFEST_PATH>\n Cargo manifest path or directory.\n \n For directories it appends a `Cargo.toml`.\n\n --workspace\n Whether to only consider workspace crates\n\n --offline\n Whether to use offline mode\n\n --locked\n Whether to use all the locked dependencies from the `Cargo.lock`.\n \n Otherwise it may update some dependencies. For CI usage its a good idea to use it.\n\n --all-features\n \n\n --features <FEATURES>\n Comma separated list of features to check.\n \n Listing the same feature multiple times has the same effect as listing it once.\n\n -p, --packages [<PACKAGES>...]\n The packages to check. If empty, all packages are checked\n\n -q, --quiet\n Only print errors. Supersedes `--log`\n\n --feature-enables-dep <FEATURE:CRATE>\n The auto-fixer will enables the feature of the dependencies as non-optional.\n \n This can be used in case that a dependency should not be enabled like `dep?/feature` but\n like `dep/feature` instead. In this case you would pass `--feature-enables-dep\n feature:dep`. The option can be passed multiple times, or multiple key-value pairs can be\n passed at once by separating them with a comma like: `--feature-enables-dep\n feature:dep,feature2:dep2`. (TODO: Duplicate entries are undefined).\n\n --log <LEVEL>\n Log level to use\n \n [default: info]\n\n --color\n Use ANSI terminal colors\n\n --left-side-feature-missing <MUTE_SETTING>\n Overwrite the behaviour when the left side dependency is missing the feature.\n \n This can be used to ignore missing features, treat them as warning or error. A \"missing\n feature\" here means that if `A` has a dependency `B` which has a feature `F`, and the\n propagation is checked then normally it would error if `A` is not forwarding `F` to `B`.\n Now this option modifies the behaviour if `A` does not have the feature in the first place.\n The default behaviour is to require `A` to also have `F`.\n \n [default: fix]\n\n Possible values:\n - ignore: Ignore this behaviour\n - report: Only report but do not fix\n - fix: Fix if `--fix` is passed\n\n --exit-code-zero\n Try to exit with code zero if the intended check failed.\n \n Will still return 1 in case of an actual error (eg. failed to find some file) or a panic\n (aka software bug).\n\n --ignore-missing-propagate <CRATE/FEATURE:DEP/DEP_FEATURE>\n Ignore single missing links in the feature propagation chain.\n\n --fix-hint <FIX_HINT>\n Dont print any hints on how to fix the error.\n \n This is mostly used internally when dispatching, workflows since they come with their\n hints.\n \n [default: on]\n\n Possible values:\n - on: Prints some hint that is (hopefully) helpful\n - off: Prints no hint at all\n\n --left-side-outside-workspace <MUTE_SETTING>\n How to handle the case that the LHS is outside the workspace.\n \n [default: fix]\n\n Possible values:\n - ignore: Ignore this behaviour\n - report: Only report but do not fix\n - fix: Fix if `--fix` is passed\n\n --dep-kinds <KIND/MUTE_SETTING>\n How to handle dev-dependencies.\n \n [default: normal:check,dev:check,build:check]\n\n --show-version\n Show crate versions in the output\n\n --show-path\n Show crate manifest paths in the output\n\n --fix\n Try to automatically fix the problems\n\n --modify-paths <MODIFY_PATHS>\n \n\n --fix-dependency <FIX_DEPENDENCY>\n Fix only issues with this package as dependency\n\n --fix-package <FIX_PACKAGE>\n Fix only issues with this package as feature source\n\n -h, --help\n Print help (see a summary with '-h')\n"
Loading