1use petgraph::visit::Bfs;
2use petgraph::visit::EdgeRef;
3use petgraph::{Direction, Graph};
4use std::collections::HashMap;
5use std::rc::Rc;
6
7use crate::api::search::PullRequest;
8
9pub type FlatDep = Vec<(Rc<PullRequest>, Option<Rc<PullRequest>>)>;
10
11pub fn build(prs: &[Rc<PullRequest>]) -> Graph<Rc<PullRequest>, usize> {
12 let mut tree = Graph::<Rc<PullRequest>, usize>::new();
13 let heads = prs.iter().map(|pr| pr.head());
14 let handles: Vec<_> = prs.iter().map(|pr| tree.add_node(pr.clone())).collect();
15 let handles_by_head: HashMap<_, _> = heads.zip(handles.iter()).collect();
16
17 for (i, pr) in prs.iter().enumerate() {
18 let head_handle = handles[i];
19 if let Some(&base_handle) = handles_by_head.get(pr.base()) {
20 tree.add_edge(*base_handle, head_handle, 1);
21 }
22 }
23
24 tree
25}
26
27pub fn log(graph: &Graph<Rc<PullRequest>, usize>) -> FlatDep {
30 let roots: Vec<_> = graph.externals(Direction::Incoming).collect();
31 let mut out = Vec::new();
32
33 for root in roots {
34 let mut bfs = Bfs::new(&graph, root);
35 while let Some(node) = bfs.next(&graph) {
36 let parent = graph.edges_directed(node, Direction::Incoming).next();
37 let node: Rc<PullRequest> = graph[node].clone();
38
39 match parent {
40 Some(parent) => out.push((node, Some(graph[parent.source()].clone()))),
41 None => out.push((node, None)),
42 }
43 }
44 }
45
46 out.sort_by_key(|(dep, _)| {
47 dep.state().clone()
48 });
49
50 out
51}