From 1c0f6cfdcc1b25c3d52020fc2ab5f8917e3e66dd Mon Sep 17 00:00:00 2001
From: Shoyu Vanilla
Date: Fri, 13 Dec 2024 04:25:02 +0900
Subject: [PATCH 1/5] test(tree): new incomplete test for `cargo tree --depth
workspace`
---
tests/testsuite/tree.rs | 58 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 58 insertions(+)
diff --git a/tests/testsuite/tree.rs b/tests/testsuite/tree.rs
index 60374bb59dd..2e81f55ce0e 100644
--- a/tests/testsuite/tree.rs
+++ b/tests/testsuite/tree.rs
@@ -1846,6 +1846,64 @@ c v1.0.0
.run();
}
+#[cargo_test]
+fn depth_workspace() {
+ Package::new("somedep", "1.0.0").publish();
+ Package::new("otherdep", "1.0.0").publish();
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [workspace]
+ members = ["a", "b", "c"]
+ "#,
+ )
+ .file("a/Cargo.toml", &basic_manifest("a", "1.0.0"))
+ .file("a/src/lib.rs", "")
+ .file(
+ "b/Cargo.toml",
+ r#"
+ [package]
+ name = "b"
+ version = "0.1.0"
+
+ [dependencies]
+ c = { path = "../c" }
+ somedep = "1"
+ "#,
+ )
+ .file("b/src/lib.rs", "")
+ .file(
+ "c/Cargo.toml",
+ r#"
+ [package]
+ name = "c"
+ version = "0.1.0"
+
+ [dependencies]
+ somedep = "1"
+ otherdep = "1"
+ "#,
+ )
+ .file("c/src/lib.rs", "")
+ .build();
+
+ p.cargo("tree")
+ .with_stdout_data(str![[r#"
+a v1.0.0 ([ROOT]/foo/a)
+
+b v0.1.0 ([ROOT]/foo/b)
+├── c v0.1.0 ([ROOT]/foo/c)
+│ ├── otherdep v1.0.0
+│ └── somedep v1.0.0
+└── somedep v1.0.0
+
+c v0.1.0 ([ROOT]/foo/c) (*)
+
+"#]])
+ .run();
+}
+
#[cargo_test]
fn prune() {
let p = make_simple_proj();
From fc00223fca7bb7e927aeda2ff1810187ac0d7c4c Mon Sep 17 00:00:00 2001
From: Shoyu Vanilla
Date: Fri, 13 Dec 2024 04:26:50 +0900
Subject: [PATCH 2/5] refactor(tree): replace previous `depth: u32` opts with
new type `DisplayDepth`
refactor(tree): replace previous `depth: u32` opts with new type `DisplayDepth`
---
src/bin/cargo/commands/tree.rs | 10 ++++++--
src/cargo/ops/tree/mod.rs | 43 ++++++++++++++++++++++++++++------
2 files changed, 44 insertions(+), 9 deletions(-)
diff --git a/src/bin/cargo/commands/tree.rs b/src/bin/cargo/commands/tree.rs
index b0f35370ebc..98b21db6c73 100644
--- a/src/bin/cargo/commands/tree.rs
+++ b/src/bin/cargo/commands/tree.rs
@@ -2,7 +2,7 @@ use crate::cli;
use crate::command_prelude::*;
use anyhow::{bail, format_err};
use cargo::core::dependency::DepKind;
-use cargo::ops::tree::{self, EdgeKind};
+use cargo::ops::tree::{self, DisplayDepth, EdgeKind};
use cargo::ops::Packages;
use cargo::util::print_available_packages;
use cargo::util::CargoResult;
@@ -162,6 +162,12 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
let pkgs_to_prune = args._values_of("prune");
+ let display_depth = args
+ ._value_of("depth")
+ .map(|s| s.parse::())
+ .transpose()?
+ .unwrap_or(DisplayDepth::MaxDisplayDepth(u32::MAX));
+
let packages = args.packages_from_flags()?;
let mut invert = args
.get_many::("invert")
@@ -222,7 +228,7 @@ subtree of the package given to -p.\n\
duplicates: args.flag("duplicates"),
format: args.get_one::("format").cloned().unwrap(),
graph_features,
- max_display_depth: args.value_of_u32("depth")?.unwrap_or(u32::MAX),
+ display_depth,
no_proc_macro,
};
diff --git a/src/cargo/ops/tree/mod.rs b/src/cargo/ops/tree/mod.rs
index 0940f0ebfad..4ffb235c1d8 100644
--- a/src/cargo/ops/tree/mod.rs
+++ b/src/cargo/ops/tree/mod.rs
@@ -43,8 +43,9 @@ pub struct TreeOptions {
pub format: String,
/// Includes features in the tree as separate nodes.
pub graph_features: bool,
- /// Maximum display depth of the dependency tree.
- pub max_display_depth: u32,
+ /// Display depth of the dependency tree.
+ /// If non-negative integer, display dependencies with that amount of max depth.
+ pub display_depth: DisplayDepth,
/// Excludes proc-macro dependencies.
pub no_proc_macro: bool,
}
@@ -86,6 +87,30 @@ impl FromStr for Prefix {
}
}
+#[derive(Clone, Copy)]
+pub enum DisplayDepth {
+ MaxDisplayDepth(u32),
+}
+
+impl FromStr for DisplayDepth {
+ type Err = clap::Error;
+
+ fn from_str(s: &str) -> Result {
+ match s {
+ s => s.parse().map(Self::MaxDisplayDepth).map_err(|_| {
+ clap::Error::raw(
+ clap::error::ErrorKind::ValueValidation,
+ format!(
+ "supported values for --depth are non-negative integers, \
+ but `{}` is unknown",
+ s
+ ),
+ )
+ }),
+ }
+ }
+}
+
struct Symbols {
down: &'static str,
tee: &'static str,
@@ -250,7 +275,7 @@ fn print(
pkgs_to_prune,
opts.prefix,
opts.no_dedupe,
- opts.max_display_depth,
+ opts.display_depth,
&mut visited_deps,
&mut levels_continue,
&mut print_stack,
@@ -270,7 +295,7 @@ fn print_node<'a>(
pkgs_to_prune: &[PackageIdSpec],
prefix: Prefix,
no_dedupe: bool,
- max_display_depth: u32,
+ display_depth: DisplayDepth,
visited_deps: &mut HashSet,
levels_continue: &mut Vec,
print_stack: &mut Vec,
@@ -329,7 +354,7 @@ fn print_node<'a>(
pkgs_to_prune,
prefix,
no_dedupe,
- max_display_depth,
+ display_depth,
visited_deps,
levels_continue,
print_stack,
@@ -349,7 +374,7 @@ fn print_dependencies<'a>(
pkgs_to_prune: &[PackageIdSpec],
prefix: Prefix,
no_dedupe: bool,
- max_display_depth: u32,
+ display_depth: DisplayDepth,
visited_deps: &mut HashSet,
levels_continue: &mut Vec,
print_stack: &mut Vec,
@@ -378,6 +403,10 @@ fn print_dependencies<'a>(
}
}
+ let max_display_depth = match display_depth {
+ DisplayDepth::MaxDisplayDepth(max) => max,
+ };
+
// Current level exceeds maximum display depth. Skip.
if levels_continue.len() + 1 > max_display_depth as usize {
return;
@@ -407,7 +436,7 @@ fn print_dependencies<'a>(
pkgs_to_prune,
prefix,
no_dedupe,
- max_display_depth,
+ display_depth,
visited_deps,
levels_continue,
print_stack,
From b729060b149c43896924b910b6e55eac8a3c77b9 Mon Sep 17 00:00:00 2001
From: Shoyu Vanilla
Date: Fri, 13 Dec 2024 04:33:49 +0900
Subject: [PATCH 3/5] feat(workspace): new function `is_member_id` to check
whether given package_id belongs to ws
---
src/cargo/core/workspace.rs | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/cargo/core/workspace.rs b/src/cargo/core/workspace.rs
index a2345cf676b..a81c6b9304e 100644
--- a/src/cargo/core/workspace.rs
+++ b/src/cargo/core/workspace.rs
@@ -591,6 +591,11 @@ impl<'gctx> Workspace<'gctx> {
self.member_ids.contains(&pkg.package_id())
}
+ /// Returns true if the given package_id is a member of the workspace.
+ pub fn is_member_id(&self, package_id: PackageId) -> bool {
+ self.member_ids.contains(&package_id)
+ }
+
pub fn is_ephemeral(&self) -> bool {
self.is_ephemeral
}
From 65931bcbf614b212b742e985f217cf94ab1f02ef Mon Sep 17 00:00:00 2001
From: Shoyu Vanilla
Date: Fri, 13 Dec 2024 05:56:20 +0900
Subject: [PATCH 4/5] refactor(tree): change signatures of tree printing
functions to receive `&Workspace`
---
src/cargo/ops/tree/mod.rs | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/src/cargo/ops/tree/mod.rs b/src/cargo/ops/tree/mod.rs
index 4ffb235c1d8..60d7974c49c 100644
--- a/src/cargo/ops/tree/mod.rs
+++ b/src/cargo/ops/tree/mod.rs
@@ -6,7 +6,7 @@ use crate::core::dependency::DepKind;
use crate::core::resolver::{features::CliFeatures, ForceAllTargets, HasDevUnits};
use crate::core::{Package, PackageId, PackageIdSpec, PackageIdSpecQuery, Workspace};
use crate::ops::{self, Packages};
-use crate::util::{CargoResult, GlobalContext};
+use crate::util::CargoResult;
use crate::{drop_print, drop_println};
use anyhow::Context as _;
use graph::Graph;
@@ -228,14 +228,14 @@ pub fn build_and_print(ws: &Workspace<'_>, opts: &TreeOptions) -> CargoResult<()
try to use option `--target all` first, and then narrow your search scope accordingly.",
)?;
} else {
- print(ws.gctx(), opts, root_indexes, &pkgs_to_prune, &graph)?;
+ print(ws, opts, root_indexes, &pkgs_to_prune, &graph)?;
}
Ok(())
}
/// Prints a tree for each given root.
fn print(
- gctx: &GlobalContext,
+ ws: &Workspace<'_>,
opts: &TreeOptions,
roots: Vec,
pkgs_to_prune: &[PackageIdSpec],
@@ -244,7 +244,7 @@ fn print(
let format = Pattern::new(&opts.format)
.with_context(|| format!("tree format `{}` not valid", opts.format))?;
- let symbols = if gctx.shell().out_unicode() {
+ let symbols = if ws.gctx().shell().out_unicode() {
&UTF8_SYMBOLS
} else {
&ASCII_SYMBOLS
@@ -256,7 +256,7 @@ fn print(
for (i, root_index) in roots.into_iter().enumerate() {
if i != 0 {
- drop_println!(gctx);
+ drop_println!(ws.gctx());
}
// A stack of bools used to determine where | symbols should appear
@@ -267,7 +267,7 @@ fn print(
let mut print_stack = vec![];
print_node(
- gctx,
+ ws,
graph,
root_index,
&format,
@@ -287,7 +287,7 @@ fn print(
/// Prints a package and all of its dependencies.
fn print_node<'a>(
- gctx: &GlobalContext,
+ ws: &Workspace<'_>,
graph: &'a Graph<'_>,
node_index: usize,
format: &Pattern,
@@ -303,12 +303,12 @@ fn print_node<'a>(
let new = no_dedupe || visited_deps.insert(node_index);
match prefix {
- Prefix::Depth => drop_print!(gctx, "{}", levels_continue.len()),
+ Prefix::Depth => drop_print!(ws.gctx(), "{}", levels_continue.len()),
Prefix::Indent => {
if let Some((last_continues, rest)) = levels_continue.split_last() {
for continues in rest {
let c = if *continues { symbols.down } else { " " };
- drop_print!(gctx, "{} ", c);
+ drop_print!(ws.gctx(), "{} ", c);
}
let c = if *last_continues {
@@ -316,7 +316,7 @@ fn print_node<'a>(
} else {
symbols.ell
};
- drop_print!(gctx, "{0}{1}{1} ", c, symbols.right);
+ drop_print!(ws.gctx(), "{0}{1}{1} ", c, symbols.right);
}
}
Prefix::None => {}
@@ -332,7 +332,7 @@ fn print_node<'a>(
} else {
" (*)"
};
- drop_println!(gctx, "{}{}", format.display(graph, node_index), star);
+ drop_println!(ws.gctx(), "{}{}", format.display(graph, node_index), star);
if !new || in_cycle {
return;
@@ -346,7 +346,7 @@ fn print_node<'a>(
EdgeKind::Feature,
] {
print_dependencies(
- gctx,
+ ws,
graph,
node_index,
format,
@@ -366,7 +366,7 @@ fn print_node<'a>(
/// Prints all the dependencies of a package for the given dependency kind.
fn print_dependencies<'a>(
- gctx: &GlobalContext,
+ ws: &Workspace<'_>,
graph: &'a Graph<'_>,
node_index: usize,
format: &Pattern,
@@ -396,10 +396,10 @@ fn print_dependencies<'a>(
if let Some(name) = name {
for continues in &**levels_continue {
let c = if *continues { symbols.down } else { " " };
- drop_print!(gctx, "{} ", c);
+ drop_print!(ws.gctx(), "{} ", c);
}
- drop_println!(gctx, "{}", name);
+ drop_println!(ws.gctx(), "{}", name);
}
}
@@ -428,7 +428,7 @@ fn print_dependencies<'a>(
while let Some(dependency) = it.next() {
levels_continue.push(it.peek().is_some());
print_node(
- gctx,
+ ws,
graph,
*dependency,
format,
From f7442319e7f1ea17b0c98136424cc83bb289c190 Mon Sep 17 00:00:00 2001
From: Shoyu Vanilla
Date: Fri, 13 Dec 2024 05:57:12 +0900
Subject: [PATCH 5/5] feat(tree): implement filtering logic for `--depth
workspace` flag
---
src/cargo/ops/tree/mod.rs | 13 ++++++++++---
src/doc/man/cargo-tree.md | 3 +++
src/doc/man/generated_txt/cargo-tree.txt | 3 +++
src/doc/src/commands/cargo-tree.md | 4 +++-
src/etc/man/cargo-tree.1 | 3 +++
tests/testsuite/tree.rs | 7 ++-----
6 files changed, 24 insertions(+), 9 deletions(-)
diff --git a/src/cargo/ops/tree/mod.rs b/src/cargo/ops/tree/mod.rs
index 60d7974c49c..e0579696f61 100644
--- a/src/cargo/ops/tree/mod.rs
+++ b/src/cargo/ops/tree/mod.rs
@@ -45,6 +45,7 @@ pub struct TreeOptions {
pub graph_features: bool,
/// Display depth of the dependency tree.
/// If non-negative integer, display dependencies with that amount of max depth.
+ /// If `workspace`, display dependencies from current workspace only.
pub display_depth: DisplayDepth,
/// Excludes proc-macro dependencies.
pub no_proc_macro: bool,
@@ -90,6 +91,7 @@ impl FromStr for Prefix {
#[derive(Clone, Copy)]
pub enum DisplayDepth {
MaxDisplayDepth(u32),
+ Workspace,
}
impl FromStr for DisplayDepth {
@@ -97,11 +99,12 @@ impl FromStr for DisplayDepth {
fn from_str(s: &str) -> Result {
match s {
+ "workspace" => Ok(Self::Workspace),
s => s.parse().map(Self::MaxDisplayDepth).map_err(|_| {
clap::Error::raw(
clap::error::ErrorKind::ValueValidation,
format!(
- "supported values for --depth are non-negative integers, \
+ "supported values for --depth are non-negative integers and `workspace`, \
but `{}` is unknown",
s
),
@@ -403,8 +406,9 @@ fn print_dependencies<'a>(
}
}
- let max_display_depth = match display_depth {
- DisplayDepth::MaxDisplayDepth(max) => max,
+ let (max_display_depth, filter_non_workspace_member) = match display_depth {
+ DisplayDepth::MaxDisplayDepth(max) => (max, false),
+ DisplayDepth::Workspace => (u32::MAX, true),
};
// Current level exceeds maximum display depth. Skip.
@@ -418,6 +422,9 @@ fn print_dependencies<'a>(
// Filter out packages to prune.
match graph.node(**dep) {
Node::Package { package_id, .. } => {
+ if filter_non_workspace_member && !ws.is_member_id(*package_id) {
+ return false;
+ }
!pkgs_to_prune.iter().any(|spec| spec.matches(*package_id))
}
_ => true,
diff --git a/src/doc/man/cargo-tree.md b/src/doc/man/cargo-tree.md
index ce99b761e7d..fc3521c9939 100644
--- a/src/doc/man/cargo-tree.md
+++ b/src/doc/man/cargo-tree.md
@@ -96,6 +96,9 @@ Prune the given package from the display of the dependency tree.
{{#option "`--depth` _depth_" }}
Maximum display depth of the dependency tree. A depth of 1 displays the direct
dependencies, for example.
+
+If the given value is `workspace`, only shows the dependencies that are member
+of the current workspace, instead.
{{/option}}
{{#option "`--no-dedupe`" }}
diff --git a/src/doc/man/generated_txt/cargo-tree.txt b/src/doc/man/generated_txt/cargo-tree.txt
index 1af730aff53..0fc542f429f 100644
--- a/src/doc/man/generated_txt/cargo-tree.txt
+++ b/src/doc/man/generated_txt/cargo-tree.txt
@@ -85,6 +85,9 @@ OPTIONS
Maximum display depth of the dependency tree. A depth of 1 displays
the direct dependencies, for example.
+ If the given value is workspace, only shows the dependencies that
+ are member of the current workspace, instead.
+
--no-dedupe
Do not de-duplicate repeated dependencies. Usually, when a package
has already displayed its dependencies, further occurrences will not
diff --git a/src/doc/src/commands/cargo-tree.md b/src/doc/src/commands/cargo-tree.md
index 154939a28ef..9418eaa9d1c 100644
--- a/src/doc/src/commands/cargo-tree.md
+++ b/src/doc/src/commands/cargo-tree.md
@@ -91,7 +91,9 @@ subtree of the package given to -p
.
--depth
depth
Maximum display depth of the dependency tree. A depth of 1 displays the direct
-dependencies, for example.
+dependencies, for example.
+If the given value is workspace
, only shows the dependencies that are member
+of the current workspace, instead.
--no-dedupe
diff --git a/src/etc/man/cargo-tree.1 b/src/etc/man/cargo-tree.1
index c951460b028..25045b3f92d 100644
--- a/src/etc/man/cargo-tree.1
+++ b/src/etc/man/cargo-tree.1
@@ -93,6 +93,9 @@ Prune the given package from the display of the dependency tree.
.RS 4
Maximum display depth of the dependency tree. A depth of 1 displays the direct
dependencies, for example.
+.sp
+If the given value is \fBworkspace\fR, only shows the dependencies that are member
+of the current workspace, instead.
.RE
.sp
\fB\-\-no\-dedupe\fR
diff --git a/tests/testsuite/tree.rs b/tests/testsuite/tree.rs
index 2e81f55ce0e..762cc4d9652 100644
--- a/tests/testsuite/tree.rs
+++ b/tests/testsuite/tree.rs
@@ -1888,15 +1888,12 @@ fn depth_workspace() {
.file("c/src/lib.rs", "")
.build();
- p.cargo("tree")
+ p.cargo("tree --depth workspace")
.with_stdout_data(str![[r#"
a v1.0.0 ([ROOT]/foo/a)
b v0.1.0 ([ROOT]/foo/b)
-├── c v0.1.0 ([ROOT]/foo/c)
-│ ├── otherdep v1.0.0
-│ └── somedep v1.0.0
-└── somedep v1.0.0
+└── c v0.1.0 ([ROOT]/foo/c)
c v0.1.0 ([ROOT]/foo/c) (*)