M src/graph.rs => src/graph.rs +19 -6
@@ 7,7 7,11 @@ use petgraph::{
Direction,
};
-use crate::{cli::Config, dep_info::DepInfo, package::Package};
+use crate::{
+ cli::Config,
+ dep_info::{BuildFlag, DepInfo, DepKind},
+ package::Package,
+};
mod builder;
@@ 33,13 37,23 @@ pub fn update_dep_info(graph: &mut DepGraph) {
}
fn update_node(graph: &mut DepGraph, idx: NodeIndex<u16>) {
- // Special case for workspace members
- if graph[idx].dep_info.is_none() {
+ // Special case for roots
+ if graph[idx].is_root {
let mut outgoing = graph.neighbors_directed(idx, Direction::Outgoing).detach();
while let Some(edge_idx) = outgoing.next_edge(graph) {
graph[edge_idx].visited = true;
}
+ // Special case for proc-macro roots
+ if graph[idx].dep_info.kind == DepKind::BUILD {
+ let mut incoming = graph.neighbors_directed(idx, Direction::Incoming).detach();
+ while let Some(edge_idx) = incoming.next_edge(graph) {
+ let kind = &mut graph[edge_idx].kind;
+ kind.host = kind.target;
+ kind.target = BuildFlag::Never;
+ }
+ }
+
return;
}
@@ 63,7 77,7 @@ fn update_node(graph: &mut DepGraph, idx: NodeIndex<u16>) {
}
let node_info = node_info.expect("non-workspace members to have at least one incoming edge");
- graph[idx].dep_info = Some(node_info);
+ graph[idx].dep_info = node_info;
let mut outgoing = graph.neighbors_directed(idx, Direction::Outgoing).detach();
while let Some(edge_idx) = outgoing.next_edge(graph) {
@@ 120,8 134,7 @@ pub fn remove_excluded_deps(graph: &mut DepGraph, exclude: &[String]) {
let is_excluded = exclude.contains(&pkg.name);
if !is_excluded
- && (graph.neighbors_directed(idx, Direction::Incoming).next().is_some()
- || pkg.is_root())
+ && (graph.neighbors_directed(idx, Direction::Incoming).next().is_some() || pkg.is_root)
{
// If the package is not explicitly excluded and also has incoming edges or is a root
// (currently workspace members only), don't remove it and continue with the queue.
M src/graph/builder.rs => src/graph/builder.rs +5 -23
@@ 7,11 7,7 @@ use cargo_metadata::{
use petgraph::stable_graph::NodeIndex;
use super::DepGraph;
-use crate::{
- cli::Config,
- dep_info::{DepInfo, DepKind},
- package::Package,
-};
+use crate::{cli::Config, dep_info::DepInfo, package::Package};
pub struct DepGraphBuilder {
/// The dependency graph being built.
@@ 82,17 78,12 @@ impl DepGraphBuilder {
continue;
}
- let dep_pkg = get_package(&self.packages, &dep.pkg);
- let is_proc_macro = is_proc_macro(dep_pkg);
-
- if is_proc_macro && !config.build_deps {
- continue;
- }
-
let child_idx = match self.node_indices.entry(dep.pkg.clone()) {
HashMapEntry::Occupied(o) => *o.get(),
HashMapEntry::Vacant(v) => {
- let idx = self.graph.add_node(Package::new(dep_pkg, false));
+ let idx = self
+ .graph
+ .add_node(Package::new(get_package(&self.packages, &dep.pkg), false));
self.deps_add_queue.push_back(dep.pkg.clone());
v.insert(idx);
idx
@@ 122,7 113,7 @@ impl DepGraphBuilder {
parent_idx,
child_idx,
DepInfo {
- kind: if is_proc_macro { DepKind::BUILD } else { info.kind.into() },
+ kind: info.kind.into(),
is_target_dep: info.target.is_some(),
is_optional,
is_optional_direct: is_optional,
@@ 142,15 133,6 @@ fn get_package<'a>(packages: &'a [MetaPackage], pkg_id: &PackageId) -> &'a MetaP
packages.iter().find(|pkg| pkg.id == *pkg_id).unwrap()
}
-fn is_proc_macro(pkg: &MetaPackage) -> bool {
- let res = pkg.targets.iter().any(|t| t.kind.iter().any(|k| k == "proc-macro"));
- if res && pkg.targets.iter().any(|t| t.kind.iter().any(|k| k == "lib")) {
- eprintln!("enountered a crate that is both a regular library and a proc-macro");
- }
-
- res
-}
-
pub fn skip_dep(config: &Config, info: &cargo_metadata::DepKindInfo) -> bool {
(!config.build_deps && info.kind == MetaDepKind::Build)
|| (!config.dev_deps && info.kind == MetaDepKind::Development)
M src/output.rs => src/output.rs +18 -22
@@ 30,31 30,27 @@ pub fn dot(graph: &DepGraph) -> Dot<'_, &DepGraph> {
&|_, (_, pkg)| {
let mut attrs = Vec::new();
- match pkg.dep_info {
- Some(info) => {
- if let Some(attr) = attr_for_dep_kind(info.kind) {
- attrs.push(attr);
- }
+ if pkg.is_root {
+ attrs.push("shape = box");
+ }
- match (info.is_target_dep, info.is_optional) {
- (true, true) => {
- attrs.push("style = \"dashed,filled\"");
- attrs.push("fillcolor = lightgrey");
- }
- (true, false) => {
- attrs.push("style = filled");
- attrs.push("fillcolor = lightgrey");
- }
- (false, true) => {
- attrs.push("style = dashed");
- }
- (false, false) => {}
- }
+ if let Some(attr) = attr_for_dep_kind(pkg.dep_info.kind) {
+ attrs.push(attr);
+ }
+
+ match (pkg.dep_info.is_target_dep, pkg.dep_info.is_optional) {
+ (true, true) => {
+ attrs.push("style = \"dashed,filled\"");
+ attrs.push("fillcolor = lightgrey");
+ }
+ (true, false) => {
+ attrs.push("style = filled");
+ attrs.push("fillcolor = lightgrey");
}
- None => {
- // Workspace member
- attrs.push("shape = box");
+ (false, true) => {
+ attrs.push("style = dashed");
}
+ (false, false) => {}
}
attrs.join(", ")
M src/package.rs => src/package.rs +21 -9
@@ 4,36 4,39 @@ use std::{
rc::Rc,
};
-use cargo_metadata::Source;
+use cargo_metadata::{Package as MetaPackage, Source};
use semver::Version;
-use crate::dep_info::DepInfo;
+use crate::dep_info::{DepInfo, DepKind};
#[derive(Clone)]
pub struct Package {
pub name: String,
pub version: Version,
pub source: Option<Source>,
- pub dep_info: Option<DepInfo>,
+ pub dep_info: DepInfo,
+ pub is_root: bool,
pub name_uses: Option<Rc<Cell<u16>>>,
}
impl Package {
- pub fn new(pkg: &cargo_metadata::Package, is_ws_member: bool) -> Self {
+ pub fn new(pkg: &MetaPackage, is_root: bool) -> Self {
+ let mut dep_info = DepInfo::default();
+ if is_proc_macro(pkg) {
+ dep_info.kind = DepKind::BUILD;
+ }
+
Self {
name: pkg.name.clone(),
version: pkg.version.clone(),
source: pkg.source.clone(),
- dep_info: if is_ws_member { None } else { Some(DepInfo::default()) },
+ dep_info,
+ is_root,
name_uses: None,
}
}
- pub fn is_root(&self) -> bool {
- self.dep_info.is_none()
- }
-
//pub fn dep_kind(&self) -> DepKind {
// self.dep_info.map(|di| di.kind).unwrap_or(DepKind::Normal)
//}
@@ 49,3 52,12 @@ impl Debug for Package {
Ok(())
}
}
+
+fn is_proc_macro(pkg: &MetaPackage) -> bool {
+ let res = pkg.targets.iter().any(|t| t.kind.iter().any(|k| k == "proc-macro"));
+ if res && pkg.targets.iter().any(|t| t.kind.iter().any(|k| k == "lib")) {
+ eprintln!("enountered a crate that is both a regular library and a proc-macro");
+ }
+
+ res
+}