diff --git a/Cargo.lock b/Cargo.lock index 79a34a18..bc1a1a62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -917,9 +917,9 @@ dependencies = [ [[package]] name = "krates" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "926bc1b844661829bdb2e685d5c51676cc7265770ae1a29f376a37dedda8b279" +checksum = "9120c4d72191846f2f52ceaf84a0b48393a9f0e3969348914d8309838b22b7cd" dependencies = [ "cargo_metadata", "cfg-expr", diff --git a/src/bans.rs b/src/bans.rs index 375e9895..170803a4 100644 --- a/src/bans.rs +++ b/src/bans.rs @@ -130,11 +130,8 @@ impl TreeSkipper { skip_crates.insert(i, pkg_id.clone()); if depth < max_depth { - for dep in graph - .edges_directed(node_id, Direction::Outgoing) - .filter(|edge| !matches!(edge.weight(), krates::Edge::Feature)) - { - pending.push((dep.target(), depth + 1)); + for dep in krates.direct_dependencies(node_id) { + pending.push((dep.node_id, depth + 1)); } } } @@ -185,7 +182,6 @@ impl fmt::Debug for DupGraph { pub type OutputGraph = dyn Fn(DupGraph) -> Result<(), Error> + Send + Sync; use crate::diag::{Check, Diag, Pack, Severity}; -use krates::petgraph::{visit::EdgeRef, Direction}; pub fn check( ctx: crate::CheckCtx<'_, ValidConfig>, diff --git a/src/bans/graph.rs b/src/bans/graph.rs index a9d9a5bb..048d0312 100644 --- a/src/bans/graph.rs +++ b/src/bans/graph.rs @@ -41,6 +41,7 @@ type Id = pg::graph::NodeIndex; #[derive(Debug)] pub enum Shape { r#box, + diamond, } #[allow(non_camel_case_types)] @@ -76,6 +77,12 @@ struct EdgeAttributes<'a> { const INDENT: &str = " "; +#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] +struct DupNode<'k> { + kid: &'k Kid, + feature: Option<&'k str>, +} + pub(crate) fn create_graph( dup_name: &str, highlight: GraphHighlight, @@ -92,42 +99,103 @@ pub(crate) fn create_graph( let duplicates: Vec<_> = dup_ids.iter().map(|di| krates[*di].id.clone()).collect(); for (index, dupid) in dup_ids.iter().zip(duplicates.iter()) { - let nid = graph.add_node(dupid); - node_map.insert(dupid, nid); - node_stack.push((krates::NodeId::new(*index), dupid)); + let dn = DupNode { + kid: dupid, + feature: None, + }; + let nid = graph.add_node(dn); + node_map.insert(dn, nid); + node_stack.push((krates::NodeId::new(*index), nid)); } { let kg = krates.graph(); - let mut visited = HashSet::new(); - while let Some((nid, pid)) = node_stack.pop() { - let target = node_map[pid]; - - for edge in kg.edges_directed(nid, pg::Direction::Incoming) { - match &kg[edge.source()] { - krates::Node::Krate { krate, .. } => { - if let krates::Edge::Dep { kind, .. } - | krates::Edge::DepFeature { kind, .. } = edge.weight() - { - if let Some(pindex) = node_map.get(&krate.id) { - graph.update_edge(*pindex, target, *kind); + if true { + while let Some((nid, target)) = node_stack.pop() { + for edge in kg.edges_directed(nid, pg::Direction::Incoming) { + match &kg[edge.source()] { + krates::Node::Krate { krate, .. } => { + if let krates::Edge::Dep { kind, .. } + | krates::Edge::DepFeature { kind, .. } = edge.weight() + { + let dn = DupNode { + kid: &krate.id, + feature: None, + }; + + if let Some(pindex) = node_map.get(&dn) { + graph.update_edge(*pindex, target, *kind); + } else { + let pindex = graph.add_node(DupNode { + kid: &krate.id, + feature: None, + }); + + graph.update_edge(pindex, target, *kind); + + node_map.insert(dn, pindex); + node_stack.push((edge.source(), pindex)); + } + } + } + krates::Node::Feature { krate_index, .. } => { + if *krate_index == nid && visited.insert(edge.source()) { + node_stack.push((edge.source(), target)); + } + } + } + } + } + } else { + while let Some((src_id, tar_id)) = node_stack.pop() { + let target = tar_id; + + for edge in kg.edges_directed(src_id, pg::Direction::Incoming) { + let source = edge.source(); + match &kg[source] { + krates::Node::Krate { krate, .. } => { + if let krates::Edge::Dep { kind, .. } + | krates::Edge::DepFeature { kind, .. } = edge.weight() + { + let node = DupNode { + kid: &krate.id, + feature: None, + }; + + if let Some(pindex) = node_map.get(&node) { + graph.update_edge(*pindex, target, *kind); + } else { + let pindex = graph.add_node(node); + + graph.update_edge(pindex, target, *kind); + + node_map.insert(node, pindex); + node_stack.push((source, pindex)); + } + } + } + krates::Node::Feature { krate_index, name } => { + let kid = &krates[*krate_index].id; + + let node = DupNode { + kid, + feature: Some(name.as_str()), + }; + + if let Some(pindex) = node_map.get(&node) { + graph.update_edge(*pindex, target, DepKind::Normal); } else { - let pindex = graph.add_node(&krate.id); + let pindex = graph.add_node(node); - graph.update_edge(pindex, target, *kind); + graph.update_edge(pindex, target, DepKind::Normal); - node_map.insert(&krate.id, pindex); - node_stack.push((edge.source(), &krate.id)); + node_map.insert(node, pindex); + node_stack.push((source, pindex)); } } } - krates::Node::Feature { krate_index, .. } => { - if *krate_index == nid && visited.insert(edge.source()) { - node_stack.push((edge.source(), pid)); - } - } } } } @@ -141,14 +209,17 @@ pub(crate) fn create_graph( // Find all of the edges that lead to each duplicate, and also keep track of // any additional crate duplicates, to make them stand out more in the dotgraph for id in &duplicates { - let dup_node = node_map[id]; + let dup_node = node_map[&DupNode { + kid: id, + feature: None, + }]; let mut set = HashSet::new(); node_stack.push(dup_node); while let Some(nid) = node_stack.pop() { let node = &graph[nid]; - let mut iditer = node.repr.splitn(3, ' '); + let mut iditer = node.kid.repr.splitn(3, ' '); let name = iditer.next().unwrap(); match dupe_nodes.entry(name) { @@ -195,34 +266,44 @@ pub(crate) fn create_graph( print_graph( &graph, |node| { - let node_weight = *node.weight(); - let repr = &node_weight.repr; - - let mut i = repr.splitn(3, ' '); - let name = i.next().unwrap(); - let _version = i.next().unwrap(); - let source = i.next().unwrap(); - - if dupe_nodes.contains_key(name) { - let label = if source != "(registry+https://github.com/rust-lang/crates.io-index)" { - &repr[name.len() + 1..] - } else { - &repr[name.len() + 1..repr.len() - source.len() - 1] - }; + let node_weight = node.weight(); + if let Some(feat) = &node_weight.feature { NodeAttributes { - label: Some(label), - shape: Some(Shape::r#box), - color: Some("red"), - style: Some(Style::rounded), + label: Some(feat), + shape: Some(Shape::diamond), ..Default::default() } } else { - NodeAttributes { - label: Some(&repr[0..repr.len() - source.len() - 1]), - shape: Some(Shape::r#box), - style: Some(Style::rounded), - ..Default::default() + let repr = &node_weight.kid.repr; + + let mut i = repr.splitn(3, ' '); + let name = i.next().unwrap(); + let _version = i.next().unwrap(); + let source = i.next().unwrap(); + + if dupe_nodes.contains_key(name) { + let label = + if source != "(registry+https://github.com/rust-lang/crates.io-index)" { + &repr[name.len() + 1..] + } else { + &repr[name.len() + 1..repr.len() - source.len() - 1] + }; + + NodeAttributes { + label: Some(label), + shape: Some(Shape::r#box), + color: Some("red"), + style: Some(Style::rounded), + ..Default::default() + } + } else { + NodeAttributes { + label: Some(&repr[0..repr.len() - source.len() - 1]), + shape: Some(Shape::r#box), + style: Some(Style::rounded), + ..Default::default() + } } } }, @@ -275,13 +356,13 @@ pub(crate) fn create_graph( } fn print_graph<'a: 'b, 'b, NP, EP, SG>( - graph: &'a pg::Graph<&'a crate::Kid, DepKind>, + graph: &'a pg::Graph, DepKind>, node_print: NP, edge_print: EP, subgraphs: SG, ) -> Result where - NP: Fn((Id, &'b &'a Kid)) -> NodeAttributes<'b>, + NP: Fn((Id, &'b DupNode<'a>)) -> NodeAttributes<'b>, EP: Fn(&pg::graph::EdgeReference<'_, DepKind, u32>) -> EdgeAttributes<'b>, SG: Fn(&mut String) -> Result<(), Error>, { diff --git a/src/cargo-deny/common.rs b/src/cargo-deny/common.rs index bf4a180b..f3a25e7f 100644 --- a/src/cargo-deny/common.rs +++ b/src/cargo-deny/common.rs @@ -124,7 +124,8 @@ impl KrateContext { gb.include_targets(cfg_targets); } - gb.ignore_kind(DepKind::Dev, krates::Scope::NonWorkspace); + let scope = krates::Scope::NonWorkspace; // krates::Scope::All + gb.ignore_kind(DepKind::Dev, scope); gb.workspace(self.workspace); if !self.exclude.is_empty() || !cfg_excludes.is_empty() {