cargo_deps/
graph.rs

1use crate::{
2    config::Config,
3    dep::{DepKind, ResolvedDep},
4    error::{Error, Result},
5    project::RootDepsMap,
6};
7use std::{collections::HashMap, fmt, io::Write};
8
9pub type Node = usize;
10
11#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
12pub struct Edge(pub Node, pub Node);
13
14impl Edge {
15    pub fn label<W: Write>(&self, w: &mut W, dg: &DepGraph) -> Result<()> {
16        use crate::dep::DepKind::{Build, Dev, Optional, Regular, Unknown};
17
18        let parent = dg.get(self.0).unwrap();
19        let child = dg.get(self.1).unwrap();
20
21        // Special case: always color edge from root to root dep by its actual root dependency kind.
22        // Otherwise, the root dep could also be a dep of a regular dep which will cause the root ->
23        // root dep edge to appear regular, which is misleading as it is not regular in Cargo.toml.
24        let child_kind = if let Some(dep_kinds_map) = &dg.root_deps_map.get(&parent.name) {
25            if let Some(kinds) = dep_kinds_map.get(&child.name) {
26                if kinds.contains(&Regular) {
27                    Regular
28                } else if kinds.contains(&Build) {
29                    Build
30                } else if kinds.contains(&Dev) {
31                    Dev
32                } else if kinds.contains(&Optional) {
33                    Optional
34                } else {
35                    Unknown
36                }
37            } else {
38                return Err(Error::Generic(format!(
39                    "Crate '{}' is not a dependency of a root crate. This is probably a logic \
40                     error.",
41                    child.name
42                )));
43            }
44        } else {
45            child.kind()
46        };
47
48        match (parent.kind(), child_kind) {
49            (Regular, Regular) => writeln!(w, ";")?,
50            (Build, _) | (Regular, Build) => writeln!(w, " [color=purple, style=dashed];")?,
51            (Dev, _) | (Regular, Dev) => writeln!(w, " [color=blue, style=dashed];")?,
52            (Optional, _) | (Regular, Optional) => writeln!(w, " [color=red, style=dashed];")?,
53            _ => writeln!(w, " [color=orange, style=dashed];")?,
54        }
55
56        Ok(())
57    }
58}
59
60impl fmt::Display for Edge {
61    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
62        let &Self(il, ir) = self;
63        write!(f, "n{} -> n{}", il, ir)
64    }
65}
66
67#[derive(Debug)]
68pub struct DepGraph {
69    /// Vector of nodes containing resolved dependency information as well as the indices of parent
70    /// and children nodes.
71    pub nodes: Vec<ResolvedDep>,
72    pub edges: Vec<Edge>,
73    pub root_deps_map: RootDepsMap,
74    pub cfg: Config,
75}
76
77impl DepGraph {
78    pub fn new(cfg: Config) -> Self {
79        Self {
80            nodes: vec![],
81            edges: vec![],
82            root_deps_map: HashMap::new(),
83            cfg,
84        }
85    }
86
87    /// Performs a topological sort on the edges.
88    pub fn topological_sort(&mut self) -> Result<()> {
89        // Create a clone of the nodes list so we can remove parents and children without affecting
90        // the original list. We work on the original list of edges, clearing it as we go, because
91        // we construct a new one at the end, in topological order.
92        let mut graph_nodes = self.nodes.clone();
93        // Will contain indices of the nodes in sorted order.
94        let mut l: Vec<Node> = vec![];
95        // Set of nodes with no incoming edges.
96        let mut s: Vec<Node> = vec![];
97
98        // Populate initial list of start nodes which have no incoming edges.
99        for (i, node) in self.nodes.iter().enumerate() {
100            if node.parents.is_empty() {
101                s.push(i);
102            }
103        }
104
105        while let Some(n) = s.pop() {
106            l.push(n);
107
108            while let Some(child) = graph_nodes[n].children.pop() {
109                assert_ne!(n, child);
110
111                // Remove the edge from n -> child.
112                let edge_index = self
113                    .edges
114                    .iter()
115                    .position(|Edge(a, b)| a == &n && b == &child)
116                    .unwrap();
117                self.edges.remove(edge_index);
118                let node_index = graph_nodes[child]
119                    .parents
120                    .iter()
121                    .position(|node| *node == n)
122                    .unwrap();
123                graph_nodes[child].parents.remove(node_index);
124
125                // If child has no other parents, it is in the next topological level.
126                if graph_nodes[child].parents.is_empty() {
127                    s.push(child);
128                }
129            }
130        }
131
132        if self.edges.is_empty() {
133            // Add back the edges, this time in topological order.
134            for n in l.iter() {
135                'child_loop: for child in self.nodes[*n].children.iter() {
136                    // Push an edge for each child, unless filtering of transitive deps is enabled,
137                    // in which case skip to the next child if a transitive dependency exists to the
138                    // child through one of the other children nodes.
139                    if !self.cfg.transitive_deps {
140                        for c in self.nodes[*n].children.iter().filter(|c| *c != child) {
141                            if self.transitive_dep(*c, *child) {
142                                continue 'child_loop;
143                            }
144                        }
145                    }
146                    self.edges.push(Edge(*n, *child));
147                }
148            }
149
150            Ok(())
151        } else {
152            Err(Error::Generic("Cycle detected in dependency graph".into()))
153        }
154    }
155
156    /// Sets the kind of each dependency based on how the dependencies are declared in the manifest.
157    pub fn set_resolved_kind(&mut self) -> Result<()> {
158        // Set regular kind for all root nodes.
159        for node in self.nodes.iter_mut() {
160            if self.root_deps_map.contains_key(&node.name) {
161                node.is_regular = true;
162            }
163        }
164
165        // Iterate over edges in topologically-sorted order to propogate the kinds.
166        for ed in self.edges.iter() {
167            // Get the parent attributes and drop the `parent` binding to avoid having two
168            // simultaneous mutable references.
169            let (
170                parent_name,
171                parent_depth,
172                parent_regular,
173                parent_build,
174                parent_dev,
175                parent_optional,
176            ) = {
177                let parent = &mut self.nodes[ed.0];
178
179                // If the parent depth isn't set yet, set it to 0.
180                if parent.depth.is_none() {
181                    parent.depth = Some(0);
182                }
183
184                (
185                    parent.name.to_string(),
186                    parent.depth,
187                    parent.is_regular,
188                    parent.is_build,
189                    parent.is_dev,
190                    parent.is_optional,
191                )
192            };
193            let mut child = &mut self.nodes[ed.1];
194
195            // If the child depth isn't set yet, set it based on the parent depth.
196            if child.depth.is_none() {
197                child.depth = Some(parent_depth.unwrap() + 1);
198            }
199
200            if let Some(dep_kinds_map) = self.root_deps_map.get(&parent_name) {
201                // If this is an edge from the root node,
202                // set the kind based on how the dependency is declared in the manifest file.
203                if let Some(kinds) = dep_kinds_map.get(&child.name) {
204                    for kind in kinds {
205                        match *kind {
206                            DepKind::Regular => child.is_regular = true,
207                            DepKind::Build => child.is_build = true,
208                            DepKind::Dev => child.is_dev = true,
209                            DepKind::Optional => child.is_optional = true,
210                            _ => (),
211                        }
212                    }
213                } else {
214                    return Err(Error::Generic(format!(
215                        "Crate '{}' is not a dependency of a root crate. This is probably a logic \
216                         error.",
217                        child.name
218                    )));
219                }
220            } else {
221                // If this is an edge from a dependency node, propagate the kind. This is a set
222                // of flags because a dependency can appear several times in the graph, and the
223                // kind of dependency may vary based on the path to that dependency. The flags
224                // start at false, and once they become true, they stay true.
225                // ResolvedDep::kind() will pick a kind based on their priority.
226
227                if parent_regular {
228                    child.is_regular = true;
229                }
230                if parent_build {
231                    child.is_build = true;
232                }
233                if parent_dev {
234                    child.is_dev = true;
235                }
236                if parent_optional {
237                    child.is_optional = true;
238                }
239            }
240        }
241
242        Ok(())
243    }
244
245    /// Forces the version to be displayed on dependencies that have the same name (but a different
246    /// version) as another dependency.
247    pub fn show_version_on_duplicates(&mut self) {
248        // Build a list of node IDs, sorted by the name of the dependency on that node.
249        let dep_ids_sorted_by_name = {
250            let mut deps = self.nodes.iter().enumerate().collect::<Vec<_>>();
251            deps.sort_by_key(|dep| &*dep.1.name);
252            deps.iter().map(|dep| dep.0).collect::<Vec<_>>()
253        };
254
255        for (i, &dep_id_i) in dep_ids_sorted_by_name
256            .iter()
257            .enumerate()
258            .take(dep_ids_sorted_by_name.len() - 1)
259        {
260            // Find other nodes with the same name.
261            // We need to iterate one more time after the last node to handle the break.
262            for (j, &dep) in dep_ids_sorted_by_name
263                .iter()
264                .enumerate()
265                .take(dep_ids_sorted_by_name.len() + 1)
266                .skip(i + 1)
267            {
268                // Stop once we've found a node with a different name or reached the end of the
269                // list.
270                if j >= dep_ids_sorted_by_name.len()
271                    || self.nodes[dep_id_i].name != self.nodes[dep].name
272                {
273                    // If there are at least two nodes with the same name
274                    if j >= i + 2 {
275                        // Set force_write_ver = true on all nodes
276                        // from dep_ids_sorted_by_name[i] to dep_ids_sorted_by_name[j - 1].
277                        // Remember: j is pointing on the next node with a *different* name!
278                        // Remember also: i..j includes i but excludes j.
279                        for &dep_id_k in dep_ids_sorted_by_name.iter().take(j).skip(i) {
280                            self.nodes[dep_id_k].force_write_ver = true;
281                        }
282                    }
283
284                    break;
285                }
286            }
287        }
288    }
289
290    pub fn add_child(
291        &mut self,
292        parent: usize,
293        dep_name: &str,
294        dep_ver: &str,
295        registry: &Option<String>,
296    ) {
297        let child = self.find_or_add(dep_name, dep_ver, registry);
298
299        if parent == child {
300            return;
301        }
302
303        self.edges.push(Edge(parent, child));
304
305        self.nodes[parent].children.push(child);
306        self.nodes[child].parents.push(parent);
307    }
308
309    pub fn get(&self, id: usize) -> Option<&ResolvedDep> {
310        if id < self.nodes.len() {
311            return Some(&self.nodes[id]);
312        }
313        None
314    }
315
316    pub fn find(&self, name: &str, ver: &str) -> Option<usize> {
317        for (i, d) in self.nodes.iter().enumerate() {
318            if d.name == name && d.ver == ver {
319                return Some(i);
320            }
321        }
322        None
323    }
324
325    pub fn find_or_add(&mut self, name: &str, ver: &str, registry: &Option<String>) -> usize {
326        if let Some(i) = self.find(name, ver) {
327            return i;
328        }
329        self.nodes.push(ResolvedDep::new(
330            name.to_owned(),
331            ver.to_owned(),
332            registry.clone(),
333        ));
334        self.nodes.len() - 1
335    }
336
337    pub fn render_to<W: Write>(self, output: &mut W) -> Result<()> {
338        // Keep track of all added nodes.
339        let mut nodes_added = vec![];
340
341        writeln!(output, "digraph dependencies {{")?;
342
343        // Output all non-subgraph nodes.
344        for (i, dep) in self.nodes.iter().enumerate() {
345            // Skip subgraph nodes, will be declared in the subgraph.
346            if let Some(sub_deps) = &self.cfg.subgraph {
347                if sub_deps.contains(&dep.name) {
348                    continue;
349                }
350            }
351
352            // Skip nodes below the maximum depth, if specified.
353            // These nodes will still be output later if specified in a subgraph.
354            if let Some(depth) = self.cfg.depth {
355                // The depth can be None if nodes have been filtered out.
356                if dep.depth.is_none() || dep.depth.unwrap() > depth {
357                    continue;
358                }
359            }
360
361            // Skip orphan nodes.
362            // Orphan nodes will still be output later if specified in a subgraph.
363            if !self.cfg.include_orphans {
364                if let DepKind::Unknown = dep.kind() {
365                    continue;
366                }
367            }
368
369            // Skip registries.
370            if let Some(registries) = &self.cfg.registries {
371                if let Some(registry) = &dep.registry {
372                    if !registries.contains(registry) {
373                        continue;
374                    }
375                } else {
376                    continue;
377                }
378            }
379
380            // Add the node.
381            write!(output, "\tn{}", i)?;
382            dep.label(output, &self)?;
383            nodes_added.push(i);
384        }
385        writeln!(output)?;
386
387        // Output any subgraph nodes.
388        if let Some(sub_deps) = &self.cfg.subgraph {
389            writeln!(output, "\tsubgraph cluster_subgraph {{")?;
390            if let Some(sub_name) = &self.cfg.subgraph_name {
391                writeln!(output, "\t\tlabel=\"{}\";", sub_name)?;
392            }
393            writeln!(output, "\t\tcolor=brown;")?;
394            writeln!(output, "\t\tstyle=dashed;")?;
395            writeln!(output)?;
396
397            for (i, dep) in self.nodes.iter().enumerate() {
398                if sub_deps.contains(&dep.name) {
399                    write!(output, "\t\tn{}", i)?;
400                    dep.label(output, &self)?;
401
402                    nodes_added.push(i);
403                }
404            }
405
406            writeln!(output, "\t}}\n")?;
407        }
408
409        // Output edges.
410        for ed in &self.edges {
411            // Only add edges if both nodes exist in the graph.
412            if !(nodes_added.contains(&ed.0) && nodes_added.contains(&ed.1)) {
413                continue;
414            }
415
416            write!(output, "\t{}", ed)?;
417            ed.label(output, &self)?;
418        }
419
420        writeln!(output, "}}")?;
421
422        Ok(())
423    }
424
425    // TODO: make this function more efficient with memoization:
426    // ahead of time, generate a list of all dependencies (direct and indirect)
427    // for all nodes, and then this function can simply check if child is in
428    // parent's list of dependencies (or possibly remove this function
429    // entirely)
430    fn transitive_dep(&self, parent: usize, child: usize) -> bool {
431        for c in self.nodes[parent].children.iter() {
432            if *c == child || self.transitive_dep(*c, child) {
433                return true;
434            }
435        }
436        false
437    }
438}