~jplatte/cargo-depgraph

3c9c80b7b768370ceb15af4727917da19c2c725f — Jonas Platte 2 years ago 2304548
Mark in-workspace proc-macro crates as host-only
4 files changed, 63 insertions(+), 60 deletions(-)

M src/graph.rs
M src/graph/builder.rs
M src/output.rs
M src/package.rs
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
}