Auto merge of #9520 - weihanglo:tree-prune, r=ehuss

Add `--prune` option for cargo-tree

Part of #8105

Prune the given package from the display of the dependency tree. Also providing a nice suggestion if the package is not within the resolved dependency graph.
This commit is contained in:
bors 2021-06-09 00:28:53 +00:00
commit aa8b09297b
7 changed files with 153 additions and 19 deletions

View File

@ -56,6 +56,11 @@ pub fn cli() -> App {
)
.short("i"),
)
.arg(multi_opt(
"prune",
"SPEC",
"Prune the given package from the display of the dependency tree",
))
.arg(opt("depth", "Maximum display depth of the dependency tree").value_name("DEPTH"))
// Deprecated, use --prefix=none instead.
.arg(Arg::with_name("no-indent").long("no-indent").hidden(true))
@ -152,6 +157,8 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
let (edge_kinds, no_proc_macro) = parse_edge_kinds(config, args)?;
let graph_features = edge_kinds.contains(&EdgeKind::Feature);
let pkgs_to_prune = args._values_of("prune");
let packages = args.packages_from_flags()?;
let mut invert = args
.values_of("invert")
@ -197,6 +204,7 @@ subtree of the package given to -p.\n\
target,
edge_kinds,
invert,
pkgs_to_prune,
prefix,
no_dedupe,
duplicates: args.is_present("duplicates"),

View File

@ -27,6 +27,8 @@ pub struct TreeOptions {
/// The dependency kinds to display.
pub edge_kinds: HashSet<EdgeKind>,
pub invert: Vec<String>,
/// The packages to prune from the display of the dependency tree.
pub pkgs_to_prune: Vec<String>,
/// The style of prefix for each line.
pub prefix: Prefix,
/// If `true`, duplicates will be repeated.
@ -199,7 +201,19 @@ pub fn build_and_print(ws: &Workspace<'_>, opts: &TreeOptions) -> CargoResult<()
graph.invert();
}
print(ws.config(), opts, root_indexes, &graph)?;
// Packages to prune.
let pkgs_to_prune = opts
.pkgs_to_prune
.iter()
.map(|p| PackageIdSpec::parse(p))
.map(|r| {
// Provide a error message if pkgid is not within the resolved
// dependencies graph.
r.and_then(|spec| spec.query(ws_resolve.targeted_resolve.iter()).and(Ok(spec)))
})
.collect::<CargoResult<Vec<PackageIdSpec>>>()?;
print(ws.config(), opts, root_indexes, &pkgs_to_prune, &graph)?;
Ok(())
}
@ -208,6 +222,7 @@ fn print(
config: &Config,
opts: &TreeOptions,
roots: Vec<usize>,
pkgs_to_prune: &[PackageIdSpec],
graph: &Graph<'_>,
) -> CargoResult<()> {
let format = Pattern::new(&opts.format)
@ -240,6 +255,7 @@ fn print(
root_index,
&format,
symbols,
pkgs_to_prune,
opts.prefix,
opts.no_dedupe,
opts.max_display_depth,
@ -260,6 +276,7 @@ fn print_node<'a>(
node_index: usize,
format: &Pattern,
symbols: &Symbols,
pkgs_to_prune: &[PackageIdSpec],
prefix: Prefix,
no_dedupe: bool,
max_display_depth: u32,
@ -319,6 +336,7 @@ fn print_node<'a>(
node_index,
format,
symbols,
pkgs_to_prune,
prefix,
no_dedupe,
max_display_depth,
@ -339,6 +357,7 @@ fn print_dependencies<'a>(
node_index: usize,
format: &Pattern,
symbols: &Symbols,
pkgs_to_prune: &[PackageIdSpec],
prefix: Prefix,
no_dedupe: bool,
max_display_depth: u32,
@ -371,6 +390,11 @@ fn print_dependencies<'a>(
}
}
// Current level exceeds maximum display depth. Skip.
if levels_continue.len() + 1 > max_display_depth as usize {
return;
}
let mut it = deps
.iter()
.filter(|dep| {
@ -386,26 +410,34 @@ fn print_dependencies<'a>(
true
}
})
.filter(|dep| {
// Filter out packages to prune.
match graph.node(**dep) {
Node::Package { package_id, .. } => {
!pkgs_to_prune.iter().any(|spec| spec.matches(*package_id))
}
_ => true,
}
})
.peekable();
while let Some(dependency) = it.next() {
if levels_continue.len() + 1 <= max_display_depth as usize {
levels_continue.push(it.peek().is_some());
print_node(
config,
graph,
*dependency,
format,
symbols,
prefix,
no_dedupe,
max_display_depth,
no_proc_macro,
visited_deps,
levels_continue,
print_stack,
);
levels_continue.pop();
}
levels_continue.push(it.peek().is_some());
print_node(
config,
graph,
*dependency,
format,
symbols,
pkgs_to_prune,
prefix,
no_dedupe,
max_display_depth,
no_proc_macro,
visited_deps,
levels_continue,
print_stack,
);
levels_continue.pop();
}
}

View File

@ -71,6 +71,10 @@ flag can be used to display the package's reverse dependencies only with the
subtree of the package given to `-p`.
{{/option}}
{{#option "`--prune` _spec_" }}
Prune the given package from the display of the dependency tree.
{{/option}}
{{#option "`--depth` _depth_" }}
Maximum display depth of the dependency tree. A depth of 1 displays the direct
dependencies, for example.

View File

@ -59,6 +59,9 @@ OPTIONS
package's reverse dependencies only with the subtree of the package
given to -p.
--prune spec
Prune the given package from the display of the dependency tree.
--depth depth
Maximum display depth of the dependency tree. A depth of 1 displays
the direct dependencies, for example.

View File

@ -71,6 +71,10 @@ flag can be used to display the package's reverse dependencies only with the
subtree of the package given to <code>-p</code>.</dd>
<dt class="option-term" id="option-cargo-tree---prune"><a class="option-anchor" href="#option-cargo-tree---prune"></a><code>--prune</code> <em>spec</em></dt>
<dd class="option-desc">Prune the given package from the display of the dependency tree.</dd>
<dt class="option-term" id="option-cargo-tree---depth"><a class="option-anchor" href="#option-cargo-tree---depth"></a><code>--depth</code> <em>depth</em></dt>
<dd class="option-desc">Maximum display depth of the dependency tree. A depth of 1 displays the direct
dependencies, for example.</dd>

View File

@ -69,6 +69,11 @@ flag can be used to display the package's reverse dependencies only with the
subtree of the package given to \fB\-p\fR\&.
.RE
.sp
\fB\-\-prune\fR \fIspec\fR
.RS 4
Prune the given package from the display of the dependency tree.
.RE
.sp
\fB\-\-depth\fR \fIdepth\fR
.RS 4
Maximum display depth of the dependency tree. A depth of 1 displays the direct

View File

@ -1720,3 +1720,81 @@ c v1.0.0
)
.run();
}
#[cargo_test]
fn prune() {
let p = make_simple_proj();
p.cargo("tree --prune c")
.with_stdout(
"\
foo v0.1.0 ([..]/foo)
a v1.0.0
b v1.0.0
[build-dependencies]
bdep v1.0.0
b v1.0.0 (*)
[dev-dependencies]
devdep v1.0.0
b v1.0.0 (*)
",
)
.run();
// multiple prune
p.cargo("tree --prune c --prune bdep")
.with_stdout(
"\
foo v0.1.0 ([..]/foo)
a v1.0.0
b v1.0.0
[build-dependencies]
[dev-dependencies]
devdep v1.0.0
b v1.0.0 (*)
",
)
.run();
// with edge-kinds
p.cargo("tree --prune c -e normal")
.with_stdout(
"\
foo v0.1.0 ([..]/foo)
a v1.0.0
b v1.0.0
",
)
.run();
// pruning self does not works
p.cargo("tree --prune foo")
.with_stdout(
"\
foo v0.1.0 ([..]/foo)
a v1.0.0
b v1.0.0
c v1.0.0
c v1.0.0
[build-dependencies]
bdep v1.0.0
b v1.0.0 (*)
[dev-dependencies]
devdep v1.0.0
b v1.0.0 (*)
",
)
.run();
// dep not exist
p.cargo("tree --prune no-dep")
.with_stderr(
"\
[ERROR] package ID specification `no-dep` did not match any packages
<tab>Did you mean `bdep`?
",
)
.with_status(101)
.run();
}