Skip to content

Commit 73b3092

Browse files
authored
feat(tree): Add --depth public behind -Zunstable-options (#15243)
### What does this PR try to resolve? I was investigating some issues around public dependency lints and wanted to see the structure of the public dependencies and had the idea to add this with us having added `--depth workspace`. See rust-lang/rust#119428 (comment) for some example output (comparing `cargo tree` with `cargo tree --depth public`) ### How should we test and review this PR? ### Additional information
2 parents 1c5ec2b + 3952e2d commit 73b3092

File tree

4 files changed

+343
-13
lines changed

4 files changed

+343
-13
lines changed

src/cargo/ops/tree/graph.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ impl Node {
7878
pub struct Edge {
7979
kind: EdgeKind,
8080
node: NodeId,
81+
public: bool,
8182
}
8283

8384
impl Edge {
@@ -88,6 +89,10 @@ impl Edge {
8889
pub fn node(&self) -> NodeId {
8990
self.node
9091
}
92+
93+
pub fn public(&self) -> bool {
94+
self.public
95+
}
9196
}
9297

9398
/// The kind of edge, for separating dependencies into different sections.
@@ -105,7 +110,7 @@ pub enum EdgeKind {
105110
///
106111
/// The value is a `Vec` because each edge kind can have multiple outgoing
107112
/// edges. For example, package "foo" can have multiple normal dependencies.
108-
#[derive(Clone)]
113+
#[derive(Clone, Debug)]
109114
struct Edges(HashMap<EdgeKind, Vec<Edge>>);
110115

111116
impl Edges {
@@ -135,6 +140,7 @@ impl Edges {
135140
}
136141

137142
/// A graph of dependencies.
143+
#[derive(Debug)]
138144
pub struct Graph<'a> {
139145
nodes: Vec<Node>,
140146
/// The indexes of `edges` correspond to the `nodes`. That is, `edges[0]`
@@ -268,6 +274,7 @@ impl<'a> Graph<'a> {
268274
let new_edge = Edge {
269275
kind: edge.kind(),
270276
node: new_to_index,
277+
public: edge.public(),
271278
};
272279
new_graph.edges_mut(new_from).add_edge(new_edge);
273280
}
@@ -290,6 +297,7 @@ impl<'a> Graph<'a> {
290297
let new_edge = Edge {
291298
kind: edge.kind(),
292299
node: NodeId::new(from_idx, self.nodes[from_idx].name()),
300+
public: edge.public(),
293301
};
294302
new_edges[edge.node().index].add_edge(new_edge);
295303
}
@@ -514,6 +522,7 @@ fn add_pkg(
514522
let new_edge = Edge {
515523
kind: EdgeKind::Dep(dep.kind()),
516524
node: dep_index,
525+
public: dep.is_public(),
517526
};
518527
if opts.graph_features {
519528
// Add the dependency node with feature nodes in-between.
@@ -577,12 +586,14 @@ fn add_feature(
577586
let from_edge = Edge {
578587
kind: to.kind(),
579588
node: node_index,
589+
public: to.public(),
580590
};
581591
graph.edges_mut(from).add_edge(from_edge);
582592
}
583593
let to_edge = Edge {
584594
kind: EdgeKind::Feature,
585595
node: to.node(),
596+
public: true,
586597
};
587598
graph.edges_mut(node_index).add_edge(to_edge);
588599
(missing, node_index)
@@ -620,6 +631,7 @@ fn add_cli_features(
620631
let feature_edge = Edge {
621632
kind: EdgeKind::Feature,
622633
node: package_index,
634+
public: true,
623635
};
624636
let index = add_feature(graph, feature, None, feature_edge).1;
625637
graph.cli_features.insert(index);
@@ -654,13 +666,15 @@ fn add_cli_features(
654666
let feature_edge = Edge {
655667
kind: EdgeKind::Feature,
656668
node: package_index,
669+
public: true,
657670
};
658671
let index = add_feature(graph, dep_name, None, feature_edge).1;
659672
graph.cli_features.insert(index);
660673
}
661674
let dep_edge = Edge {
662675
kind: EdgeKind::Feature,
663676
node: dep_index,
677+
public: true,
664678
};
665679
let index = add_feature(graph, dep_feature, None, dep_edge).1;
666680
graph.cli_features.insert(index);
@@ -721,6 +735,7 @@ fn add_feature_rec(
721735
let feature_edge = Edge {
722736
kind: EdgeKind::Feature,
723737
node: package_index,
738+
public: true,
724739
};
725740
let (missing, feat_index) = add_feature(graph, *dep_name, Some(from), feature_edge);
726741
// Don't recursive if the edge already exists to deal with cycles.
@@ -771,12 +786,14 @@ fn add_feature_rec(
771786
let feature_edge = Edge {
772787
kind: EdgeKind::Feature,
773788
node: package_index,
789+
public: true,
774790
};
775791
add_feature(graph, *dep_name, Some(from), feature_edge);
776792
}
777793
let dep_edge = Edge {
778794
kind: EdgeKind::Feature,
779795
node: dep_index,
796+
public: true,
780797
};
781798
let (missing, feat_index) =
782799
add_feature(graph, *dep_feature, Some(from), dep_edge);

src/cargo/ops/tree/mod.rs

+32-12
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ impl FromStr for Prefix {
9191
#[derive(Clone, Copy)]
9292
pub enum DisplayDepth {
9393
MaxDisplayDepth(u32),
94+
Public,
9495
Workspace,
9596
}
9697

@@ -100,6 +101,7 @@ impl FromStr for DisplayDepth {
100101
fn from_str(s: &str) -> Result<Self, Self::Err> {
101102
match s {
102103
"workspace" => Ok(Self::Workspace),
104+
"public" => Ok(Self::Public),
103105
s => s.parse().map(Self::MaxDisplayDepth).map_err(|_| {
104106
clap::Error::raw(
105107
clap::error::ErrorKind::ValueValidation,
@@ -282,7 +284,7 @@ fn print(
282284
&mut visited_deps,
283285
&mut levels_continue,
284286
&mut print_stack,
285-
);
287+
)?;
286288
}
287289

288290
Ok(())
@@ -302,7 +304,7 @@ fn print_node<'a>(
302304
visited_deps: &mut HashSet<NodeId>,
303305
levels_continue: &mut Vec<(anstyle::Style, bool)>,
304306
print_stack: &mut Vec<NodeId>,
305-
) {
307+
) -> CargoResult<()> {
306308
let new = no_dedupe || visited_deps.insert(node_index);
307309

308310
match prefix {
@@ -343,7 +345,7 @@ fn print_node<'a>(
343345
drop_println!(ws.gctx(), "{}{}", format.display(graph, node_index), star);
344346

345347
if !new || in_cycle {
346-
return;
348+
return Ok(());
347349
}
348350
print_stack.push(node_index);
349351

@@ -367,9 +369,11 @@ fn print_node<'a>(
367369
levels_continue,
368370
print_stack,
369371
kind,
370-
);
372+
)?;
371373
}
372374
print_stack.pop();
375+
376+
Ok(())
373377
}
374378

375379
/// Prints all the dependencies of a package for the given dependency kind.
@@ -387,10 +391,10 @@ fn print_dependencies<'a>(
387391
levels_continue: &mut Vec<(anstyle::Style, bool)>,
388392
print_stack: &mut Vec<NodeId>,
389393
kind: &EdgeKind,
390-
) {
394+
) -> CargoResult<()> {
391395
let deps = graph.edges_of_kind(node_index, kind);
392396
if deps.is_empty() {
393-
return;
397+
return Ok(());
394398
}
395399

396400
let name = match kind {
@@ -415,14 +419,20 @@ fn print_dependencies<'a>(
415419
}
416420
}
417421

418-
let (max_display_depth, filter_non_workspace_member) = match display_depth {
419-
DisplayDepth::MaxDisplayDepth(max) => (max, false),
420-
DisplayDepth::Workspace => (u32::MAX, true),
422+
let (max_display_depth, filter_non_workspace_member, filter_private) = match display_depth {
423+
DisplayDepth::MaxDisplayDepth(max) => (max, false, false),
424+
DisplayDepth::Workspace => (u32::MAX, true, false),
425+
DisplayDepth::Public => {
426+
if !ws.gctx().cli_unstable().unstable_options {
427+
anyhow::bail!("`--depth public` requires `-Zunstable-options`")
428+
}
429+
(u32::MAX, false, true)
430+
}
421431
};
422432

423433
// Current level exceeds maximum display depth. Skip.
424434
if levels_continue.len() + 1 > max_display_depth as usize {
425-
return;
435+
return Ok(());
426436
}
427437

428438
let mut it = deps
@@ -434,9 +444,17 @@ fn print_dependencies<'a>(
434444
if filter_non_workspace_member && !ws.is_member_id(*package_id) {
435445
return false;
436446
}
447+
if filter_private && !dep.public() {
448+
return false;
449+
}
437450
!pkgs_to_prune.iter().any(|spec| spec.matches(*package_id))
438451
}
439-
_ => true,
452+
Node::Feature { .. } => {
453+
if filter_private && !dep.public() {
454+
return false;
455+
}
456+
true
457+
}
440458
}
441459
})
442460
.peekable();
@@ -457,9 +475,11 @@ fn print_dependencies<'a>(
457475
visited_deps,
458476
levels_continue,
459477
print_stack,
460-
);
478+
)?;
461479
levels_continue.pop();
462480
}
481+
482+
Ok(())
463483
}
464484

465485
fn edge_line_color(kind: EdgeKind) -> anstyle::Style {

tests/testsuite/cargo_tree/deps.rs

+132
Original file line numberDiff line numberDiff line change
@@ -1901,6 +1901,138 @@ c v0.1.0 ([ROOT]/foo/c) (*)
19011901
.run();
19021902
}
19031903

1904+
#[cargo_test(nightly, reason = "exported_private_dependencies lint is unstable")]
1905+
fn depth_public() {
1906+
let p = project()
1907+
.file(
1908+
"Cargo.toml",
1909+
r#"
1910+
[workspace]
1911+
members = ["diamond", "left-pub", "right-priv", "dep"]
1912+
"#,
1913+
)
1914+
.file(
1915+
"diamond/Cargo.toml",
1916+
r#"
1917+
cargo-features = ["public-dependency"]
1918+
1919+
[package]
1920+
name = "diamond"
1921+
version = "0.1.0"
1922+
1923+
[dependencies]
1924+
left-pub = { path = "../left-pub", public = true }
1925+
right-priv = { path = "../right-priv", public = true }
1926+
"#,
1927+
)
1928+
.file("diamond/src/lib.rs", "")
1929+
.file(
1930+
"left-pub/Cargo.toml",
1931+
r#"
1932+
cargo-features = ["public-dependency"]
1933+
1934+
[package]
1935+
name = "left-pub"
1936+
version = "0.1.0"
1937+
1938+
[dependencies]
1939+
dep = { path = "../dep", public = true }
1940+
"#,
1941+
)
1942+
.file("left-pub/src/lib.rs", "")
1943+
.file(
1944+
"right-priv/Cargo.toml",
1945+
r#"
1946+
[package]
1947+
name = "right-priv"
1948+
version = "0.1.0"
1949+
1950+
[dependencies]
1951+
dep = { path = "../dep" }
1952+
"#,
1953+
)
1954+
.file("right-priv/src/lib.rs", "")
1955+
.file(
1956+
"dep/Cargo.toml",
1957+
r#"
1958+
[package]
1959+
name = "dep"
1960+
version = "0.1.0"
1961+
"#,
1962+
)
1963+
.file("dep/src/lib.rs", "")
1964+
.build();
1965+
1966+
p.cargo("tree --depth public")
1967+
.masquerade_as_nightly_cargo(&["public-dependency", "depth-public"])
1968+
.with_status(101)
1969+
.with_stderr_data(str![[r#"
1970+
[ERROR] `--depth public` requires `-Zunstable-options`
1971+
1972+
"#]])
1973+
.run();
1974+
1975+
p.cargo("tree --depth public -p left-pub")
1976+
.arg("-Zunstable-options")
1977+
.masquerade_as_nightly_cargo(&["public-dependency", "depth-public"])
1978+
.with_stdout_data(str![[r#"
1979+
left-pub v0.1.0 ([ROOT]/foo/left-pub)
1980+
└── dep v0.1.0 ([ROOT]/foo/dep)
1981+
1982+
"#]])
1983+
.run();
1984+
1985+
p.cargo("tree --depth public -p right-priv")
1986+
.arg("-Zunstable-options")
1987+
.masquerade_as_nightly_cargo(&["public-dependency", "depth-public"])
1988+
.with_stdout_data(str![[r#"
1989+
right-priv v0.1.0 ([ROOT]/foo/right-priv)
1990+
1991+
"#]])
1992+
.run();
1993+
1994+
p.cargo("tree --depth public -p diamond")
1995+
.arg("-Zunstable-options")
1996+
.masquerade_as_nightly_cargo(&["public-dependency", "depth-public"])
1997+
.with_stdout_data(str![[r#"
1998+
diamond v0.1.0 ([ROOT]/foo/diamond)
1999+
├── left-pub v0.1.0 ([ROOT]/foo/left-pub)
2000+
│ └── dep v0.1.0 ([ROOT]/foo/dep)
2001+
└── right-priv v0.1.0 ([ROOT]/foo/right-priv)
2002+
2003+
"#]])
2004+
.run();
2005+
2006+
p.cargo("tree --depth public")
2007+
.arg("-Zunstable-options")
2008+
.masquerade_as_nightly_cargo(&["public-dependency", "depth-public"])
2009+
.with_stdout_data(str![[r#"
2010+
dep v0.1.0 ([ROOT]/foo/dep)
2011+
2012+
diamond v0.1.0 ([ROOT]/foo/diamond)
2013+
├── left-pub v0.1.0 ([ROOT]/foo/left-pub)
2014+
│ └── dep v0.1.0 ([ROOT]/foo/dep)
2015+
└── right-priv v0.1.0 ([ROOT]/foo/right-priv)
2016+
2017+
left-pub v0.1.0 ([ROOT]/foo/left-pub) (*)
2018+
2019+
right-priv v0.1.0 ([ROOT]/foo/right-priv) (*)
2020+
2021+
"#]])
2022+
.run();
2023+
2024+
p.cargo("tree --depth public --invert dep")
2025+
.arg("-Zunstable-options")
2026+
.masquerade_as_nightly_cargo(&["public-dependency", "depth-public"])
2027+
.with_stdout_data(str![[r#"
2028+
dep v0.1.0 ([ROOT]/foo/dep)
2029+
└── left-pub v0.1.0 ([ROOT]/foo/left-pub)
2030+
└── diamond v0.1.0 ([ROOT]/foo/diamond)
2031+
2032+
"#]])
2033+
.run();
2034+
}
2035+
19042036
#[cargo_test]
19052037
fn prune() {
19062038
let p = make_simple_proj();

0 commit comments

Comments
 (0)