dependy/
lib.rs

1extern crate daggy;
2extern crate petgraph;
3
4use self::daggy::{Dag, Walker, NodeIndex};
5use petgraph::dot::Dot;
6
7use std::collections::HashMap;
8use std::fmt;
9use std::fs::File;
10use std::hash::Hash;
11use std::io::Write;
12use std::io;
13
14#[derive(Debug)]
15pub enum DepError<K> where K: Clone {
16    RequirementsNotFound(K),
17    RequirementNotFound(K, K),
18    SuggestionsNotFound(K),
19    SuggestionNotFound(K, K),
20    DependencyNotFound(K),
21    CircularDependency(K, K),
22}
23
24#[derive(Copy, Clone, Debug, PartialEq)]
25pub enum DepEdge {
26    /// Dependency B Requires dependency A, and a failure of A
27    /// prevents B from running
28    Requires,
29
30    /// Dependency B Suggests dependency A, and a failure of A
31    Suggests,
32
33    /// Dependency B follows dependency A in the list
34    Follows,
35}
36impl fmt::Display for DepEdge {
37    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
38        match self {
39            &DepEdge::Requires => write!(f, "Requires"),
40            &DepEdge::Suggests => write!(f, "Suggests"),
41            &DepEdge::Follows => write!(f, "Follows"),
42        }
43    }
44}
45
46pub trait Dependency<K> where K: Clone + Eq + Hash {
47    fn name(&self) -> &K;
48    fn requirements(&self) -> &Vec<K>;
49    fn suggestions(&self) -> &Vec<K>;
50    fn provides(&self) -> &Vec<K>;
51}
52
53#[derive(Debug, Clone)]
54pub struct InternalDependency<K> where K: Clone + Eq + Hash {
55    name: K,
56    requirements: Vec<K>,
57    suggestions: Vec<K>,
58    provides: Vec<K>,
59}
60impl<K> Dependency<K> for InternalDependency<K> where K: Clone + Eq + Hash {
61    fn name(&self) -> &K {
62        &self.name
63    }
64    fn requirements(&self) -> &Vec<K> {
65        &self.requirements
66    }
67    fn suggestions(&self) -> &Vec<K> {
68        &self.suggestions
69    }
70    fn provides(&self) -> &Vec<K> {
71        &self.provides
72    }
73}
74#[derive(Debug)]
75pub struct Dependy<K> where K: Clone + Eq + Hash {
76    /// The graph structure, which we will iterate over.
77    graph: Dag<K, DepEdge>,
78
79    /// A hashmap containing all nodes in the graph, indexed by name.
80    node_bucket: HashMap<K, NodeIndex>,
81
82    /// Whether results were successful or not.
83    results: HashMap<K, bool>,
84
85    /// A mapping of "provides" to actual names.
86    provides_map: HashMap<K, K>,
87
88    requirements: HashMap<K, Vec<K>>,
89    suggestions: HashMap<K, Vec<K>>,
90
91    /// Useed for testing, and making sure the graph is sane.
92    dep_map: HashMap<K, InternalDependency<K>>,
93}
94
95impl<K> Dependy<K> where K: Clone + Eq + Hash + fmt::Display {
96    pub fn new() -> Dependy<K> {
97        Dependy {
98            graph: Dag::new(),
99            node_bucket: HashMap::new(),
100            results: HashMap::new(),
101            requirements: HashMap::new(),
102            suggestions: HashMap::new(),
103            provides_map: HashMap::new(),
104            dep_map: HashMap::new(),
105        }
106    }
107
108    pub fn add_dependency<T: Dependency<K>>(&mut self, dependency: &T) {
109        let name = dependency.name().clone();
110        let new_node = self.graph.add_node(name.clone());
111        self.node_bucket.insert(name.clone(), new_node.clone());
112
113        let sd = InternalDependency {
114            name: dependency.name().clone(),
115            requirements: dependency.requirements().clone(),
116            suggestions: dependency.suggestions().clone(),
117            provides: dependency.provides().clone(),
118        };
119        self.dep_map.insert(name.clone(), sd);
120
121        // Also add aliases
122        self.provides_map.insert(name.clone(), name.clone());
123        for alias in dependency.provides() {
124            self.node_bucket.insert(alias.clone(), new_node.clone());
125            self.provides_map.insert(alias.clone(), name.clone());
126        }
127
128        self.suggestions.insert(name.clone(), dependency.suggestions().clone());
129        self.requirements.insert(name.clone(), dependency.requirements().clone());
130    }
131
132    pub fn resolve_named_dependencies(&mut self,
133                                      dependencies: &Vec<K>)
134                                      -> Result<Vec<K>, DepError<K>> {
135
136        let mut to_resolve = dependencies.clone();
137
138        loop {
139            if to_resolve.is_empty() {
140                break;
141            }
142
143            // If this dep_name has been resolved, skip it.
144            let dep_name = to_resolve.remove(0);
145            let dep_name = match self.provides_map.get(&dep_name) {
146                Some(s) => s.clone(),
147                None => return Err(DepError::DependencyNotFound(dep_name.clone())),
148            };
149
150            // Resolve all requirements.
151            match self.requirements.get(&dep_name) {
152                None => return Err(DepError::RequirementsNotFound(dep_name.clone())),
153                Some(ref reqs) => {
154                    for req in *reqs {
155                        to_resolve.push(req.clone());
156                        let target = match self.node_bucket.get(req) {
157                            None => {
158                                return Err(DepError::RequirementNotFound(dep_name, req.clone()))
159                            }
160                            Some(e) => e,
161                        };
162
163                        // Don't add extra edges.
164                        if self.graph.find_edge(*target, self.node_bucket[&dep_name]).is_some() {
165                            continue;
166                        }
167
168                        if let Err(_) = self.graph
169                            .add_edge(*target, self.node_bucket[&dep_name], DepEdge::Requires) {
170                            return Err(DepError::CircularDependency(dep_name.clone(), req.clone()));
171                        }
172                    }
173                }
174            }
175
176            // Also resolve all suggestions.
177            match self.suggestions.get(&dep_name) {
178                None => return Err(DepError::SuggestionsNotFound(dep_name.clone())),
179                Some(ref reqs) => {
180                    for req in *reqs {
181                        to_resolve.push(req.clone());
182                        let target = match self.node_bucket.get(req) {
183                            None => return Err(DepError::SuggestionNotFound(dep_name, req.clone())),
184                            Some(e) => e,
185                        };
186
187                        // Don't add extra edges.
188                        if self.graph.find_edge(*target, self.node_bucket[&dep_name]).is_some() {
189                            continue;
190                        }
191
192                        if let Err(_) = self.graph
193                            .add_edge(*target, self.node_bucket[&dep_name], DepEdge::Suggests) {
194                            return Err(DepError::CircularDependency(dep_name.clone(), req.clone()));
195                        }
196                    }
197                }
198            }
199        }
200
201        // Add "Follows" dependencies, if no other dependency exists.
202        let num_deps = dependencies.len();
203        for i in 1..num_deps {
204            let previous_dep = dependencies[i - 1].clone();
205            let this_dep = dependencies[i].clone();
206
207            let previous_edge = match self.node_bucket.get(&previous_dep) {
208                Some(s) => s,
209                None => return Err(DepError::DependencyNotFound(previous_dep)),
210            };
211            let this_edge = match self.node_bucket.get(&this_dep) {
212                Some(s) => s,
213                None => return Err(DepError::DependencyNotFound(this_dep)),
214            };
215
216            // Don't add a "Follows" dependency if one already exists.
217            if self.graph.find_edge(*previous_edge, *this_edge).is_some() {
218                continue;
219            }
220
221            // If we get a "CircularDependency", that's fine, we just won't add this edge.
222            self.graph.add_edge(*previous_edge, *this_edge, DepEdge::Follows).ok();
223        }
224
225        // Sort everything into a "dependency order"
226        let mut dep_order = vec![];
227        let mut seen_nodes = HashMap::new();
228        for dep_name in dependencies {
229
230            // Pick a node from the bucket and visit it.  This will cause
231            // all nodes in the graph to be visited, in order.
232            let some_node = self.node_bucket.get(dep_name).unwrap().clone();
233            self.visit_node(&mut seen_nodes, &some_node, &mut dep_order);
234        }
235        Ok(dep_order)
236    }
237
238    pub fn resolve_dependencies<T: Dependency<K>>(&mut self,
239                                               dependencies: Vec<T>)
240                                               -> Result<Vec<K>, DepError<K>> {
241        let mut to_resolve = vec![];
242        for dep in &dependencies {
243            to_resolve.push(dep.name().clone());
244        }
245        self.resolve_named_dependencies(&to_resolve)
246    }
247
248    pub fn save_dot(&self, output: &mut File) -> io::Result<()> {
249        write!(output, "{}", Dot::new(self.graph.graph()))
250    }
251
252    fn visit_node(&mut self,
253                  seen_nodes: &mut HashMap<NodeIndex, ()>,
254                  node: &NodeIndex,
255                  dep_order: &mut Vec<K>) {
256
257        // If this node has been seen already, don't re-visit it.
258        if seen_nodes.insert(node.clone(), ()).is_some() {
259            return;
260        }
261
262        // 1. Visit all parents
263        // 2. Visit ourselves
264        // 3. Visit all children
265
266        let parents = self.graph.parents(*node);
267        let mut to_visit = vec![];
268        for (_, parent_index) in parents.iter(&self.graph) {
269            to_visit.push(parent_index);
270        }
271        for parent_index in to_visit {
272            self.visit_node(seen_nodes, &parent_index, dep_order);
273        }
274
275        dep_order.push(self.graph[*node].clone());
276        // let children = self.graph.children(*node);
277        // let mut to_visit = vec![];
278        // for (_, child_index) in children.iter(&self.graph) {
279        // to_visit.push(child_index);
280        // }
281        // for child_index in to_visit {
282        // self.visit_node(seen_nodes, &child_index, dep_order);
283        // }
284        //
285    }
286
287    // pub fn parents_of_named(&mut self, name: &String) -> Vec<String> {
288    // let parents = self.graph.parents(self.node_bucket[name]);
289    // let mut retval = vec![];
290    // for (parent, parent_index) in parents.iter(&self.graph) {
291    // retval.push(parent);
292    // }
293    // retval
294    // }
295    //
296    pub fn required_parents_of_named(&self, name: &K) -> Vec<&K> {
297        let parents = self.graph.parents(self.node_bucket[name]);
298        let mut retval = vec![];
299        for (edge, node) in parents.iter(&self.graph) {
300            if *(self.graph.edge_weight(edge).unwrap()) != DepEdge::Requires {
301                continue;
302            }
303            retval.push(self.graph.node_weight(node).unwrap());
304        }
305        retval
306    }
307
308    pub fn mark_successful(&mut self, dep: &K) {
309        self.results.insert(dep.clone(), true);
310    }
311
312    pub fn mark_failure(&mut self, dep: &K) {
313        self.results.insert(dep.clone(), false);
314    }
315
316    pub fn reset_results(&mut self) {
317        self.results.clear();
318    }
319}
320
321#[cfg(test)]
322mod tests {
323    use super::*;
324    struct SimpleDep {
325        name: String,
326        requirements: Vec<String>,
327        suggestions: Vec<String>,
328        provides: Vec<String>,
329    }
330    impl SimpleDep {
331        pub fn new(name: &str,
332                   requirements: Vec<String>,
333                   suggestions: Vec<String>,
334                   provides: Vec<String>)
335                   -> SimpleDep {
336            SimpleDep {
337                name: name.to_owned(),
338                requirements: requirements,
339                suggestions: suggestions,
340                provides: provides,
341            }
342        }
343    }
344    impl Dependency<String> for SimpleDep {
345        fn name(&self) -> &String {
346            &self.name
347        }
348        fn requirements(&self) -> &Vec<String> {
349            &self.requirements
350        }
351        fn suggestions(&self) -> &Vec<String> {
352            &self.suggestions
353        }
354        fn provides(&self) -> &Vec<String> {
355            &self.provides
356        }
357    }
358    #[test]
359    fn single_dep() {
360        let mut depgraph = Dependy::new();
361        let d1 = SimpleDep::new("single", vec![], vec![], vec![]);
362        depgraph.add_dependency(&d1);
363
364        let dep_chain = depgraph.resolve_dependencies(vec![d1]).unwrap();
365        assert_eq!(dep_chain.len(), 1);
366        assert_eq!(dep_chain[0], "single");
367    }
368
369    #[test]
370    fn two_deps() {
371        let mut depgraph = Dependy::new();
372        let d1 = SimpleDep::new("first", vec!["second".to_string()], vec![], vec![]);
373        let d2 = SimpleDep::new("second", vec![], vec![], vec![]);
374        depgraph.add_dependency(&d1);
375        depgraph.add_dependency(&d2);
376
377        let dep_chain = depgraph.resolve_dependencies(vec![d1]).unwrap();
378        assert_eq!(dep_chain.len(), 2);
379        assert_eq!(dep_chain[0], "second");
380        assert_eq!(dep_chain[1], "first");
381    }
382
383    #[test]
384    fn three_deps() {
385        let mut depgraph = Dependy::new();
386        let d1 = SimpleDep::new("first", vec!["second".to_string()], vec![], vec![]);
387        let d2 = SimpleDep::new("second", vec!["third".to_string()], vec![], vec![]);
388        let d3 = SimpleDep::new("third", vec![], vec![], vec![]);
389        depgraph.add_dependency(&d1);
390        depgraph.add_dependency(&d2);
391        depgraph.add_dependency(&d3);
392
393        let dep_chain = depgraph.resolve_dependencies(vec![d1]).unwrap();
394        assert_eq!(dep_chain.len(), 3);
395        assert_eq!(dep_chain[0], "third");
396        assert_eq!(dep_chain[1], "second");
397        assert_eq!(dep_chain[2], "first");
398    }
399
400    #[test]
401    fn provides() {
402        let mut depgraph = Dependy::new();
403        let d1 = SimpleDep::new("first", vec!["deux".to_string()], vec![], vec![]);
404        let d2 = SimpleDep::new("second", vec![], vec![], vec!["deux".to_string()]);
405        depgraph.add_dependency(&d1);
406        depgraph.add_dependency(&d2);
407
408        let dep_chain = depgraph.resolve_dependencies(vec![d1]).unwrap();
409        assert_eq!(dep_chain.len(), 2);
410        assert_eq!(dep_chain[0], "second");
411        assert_eq!(dep_chain[1], "first");
412    }
413
414
415    #[test]
416    fn follows() {
417        let mut depgraph = Dependy::new();
418        let d1 = SimpleDep::new("first", vec![], vec![], vec![]);
419        let d2 = SimpleDep::new("second", vec![], vec![], vec!["deux".to_string()]);
420        let d3 = SimpleDep::new("third", vec![], vec![], vec![]);
421        depgraph.add_dependency(&d1);
422        depgraph.add_dependency(&d2);
423        depgraph.add_dependency(&d3);
424
425        let dep_chain = depgraph.resolve_dependencies(vec![d1, d2, d3]).unwrap();
426        assert_eq!(dep_chain.len(), 3);
427        assert_eq!(dep_chain[0], "first");
428        assert_eq!(dep_chain[1], "second");
429        assert_eq!(dep_chain[2], "third");
430    }
431
432    #[test]
433    fn depends_and_follows() {
434        let mut depgraph = Dependy::new();
435        let d1 = SimpleDep::new("first", vec!["third".to_string()], vec![], vec![]);
436        let d2 = SimpleDep::new("second", vec![], vec![], vec!["deux".to_string()]);
437        let d3 = SimpleDep::new("third", vec![], vec![], vec![]);
438        depgraph.add_dependency(&d1);
439        depgraph.add_dependency(&d2);
440        depgraph.add_dependency(&d3);
441
442        let dep_chain = depgraph.resolve_dependencies(vec![d1, d3, d2]).unwrap();
443        assert_eq!(dep_chain.len(), 3);
444        assert_eq!(dep_chain[0], "third");
445        assert_eq!(dep_chain[1], "first");
446        assert_eq!(dep_chain[2], "second");
447    }
448
449    #[test]
450    fn complex_sequence() {
451        let mut depgraph = Dependy::new();
452        let build_ltc_os = SimpleDep::new("build-ltc-os",
453                                          vec!["checkout-ltc-os".to_string()],
454                                          vec![],
455                                          vec![]);
456        depgraph.add_dependency(&build_ltc_os);
457        let checkout_ltc_os = SimpleDep::new("checkout-ltc-os", vec![], vec![], vec![]);
458        depgraph.add_dependency(&checkout_ltc_os);
459        let connectivity_test = SimpleDep::new("connectivity-test",
460                                               vec!["serial-test".to_string()],
461                                               vec![],
462                                               vec![]);
463        depgraph.add_dependency(&connectivity_test);
464        let finish_ltc_tests = SimpleDep::new("finish-ltc-tests",
465                                              vec!["serial-test".to_string(),
466                                                   "connectivity-test".to_string(),
467                                                   "led-test".to_string(),
468                                                   "rgb-test".to_string(),
469                                                   "status-leds".to_string()],
470                                              vec![],
471                                              vec![]);
472        depgraph.add_dependency(&finish_ltc_tests);
473        let led_test = SimpleDep::new("led-test", vec!["serial-test".to_string()], vec![], vec![]);
474        depgraph.add_dependency(&led_test);
475        let mass_erase = SimpleDep::new("mass-erase", vec!["swd".to_string()], vec![], vec![]);
476        depgraph.add_dependency(&mass_erase);
477        let measure_reset_pulse = SimpleDep::new("measure-reset-pulse",
478                                                 vec!["pi-blaster".to_string()],
479                                                 vec![],
480                                                 vec![]);
481        depgraph.add_dependency(&measure_reset_pulse);
482        let pi_blaster = SimpleDep::new("pi-blaster", vec![], vec![], vec![]);
483        depgraph.add_dependency(&pi_blaster);
484        let program_app = SimpleDep::new("program-app",
485                                         vec!["finish-ltc-tests".to_string()],
486                                         vec![],
487                                         vec![]);
488        depgraph.add_dependency(&program_app);
489        let program_os_pvt1c = SimpleDep::new("program-os-pvt1c",
490                                              vec!["swd".to_string(), "mass-erase".to_string()],
491                                              vec![],
492                                              vec![]);
493        depgraph.add_dependency(&program_os_pvt1c);
494        let rgb_test = SimpleDep::new("rgb-test", vec!["serial-test".to_string()], vec![], vec![]);
495        depgraph.add_dependency(&rgb_test);
496        let serial_test = SimpleDep::new("serial-test",
497                                         vec!["upload-program".to_string()],
498                                         vec![],
499                                         vec![]);
500        depgraph.add_dependency(&serial_test);
501        let status_leds = SimpleDep::new("status-leds",
502                                         vec!["serial-test".to_string()],
503                                         vec![],
504                                         vec![]);
505        depgraph.add_dependency(&status_leds);
506        let swd = SimpleDep::new("swd",
507                                 vec!["measure-reset-pulse".to_string()],
508                                 vec![],
509                                 vec![]);
510        depgraph.add_dependency(&swd);
511        let test_setup = SimpleDep::new("test-setup",
512                                        vec!["program-os-pvt1c".to_string()],
513                                        vec![],
514                                        vec![]);
515        depgraph.add_dependency(&test_setup);
516        let upload_program = SimpleDep::new("upload-program",
517                                            vec!["program-os-pvt1c".to_string(),
518                                                 "test-setup".to_string()],
519                                            vec![],
520                                            vec![]);
521        depgraph.add_dependency(&upload_program);
522        let wait_forever = SimpleDep::new("wait-forever", vec![], vec![], vec![]);
523        depgraph.add_dependency(&wait_forever);
524
525        let dep_chain = depgraph.resolve_dependencies(vec![mass_erase,
526                                       program_os_pvt1c,
527                                       upload_program,
528                                       finish_ltc_tests,
529                                       program_app])
530            .unwrap();
531
532        {
533            let mut dotfile = File::create("./depgraph.dot").expect("Unable to open depgraph.dot");
534            depgraph.save_dot(&mut dotfile).expect("Unable to write dotfile");
535        }
536
537        println!("Resolved dep chain: {:?}", dep_chain);
538        for depname in &dep_chain {
539            validate_parents_present(&depgraph, &dep_chain, &depname);
540        }
541    }
542
543    fn index_of(vector: &Vec<String>, x: &String) -> Option<usize> {
544        for (idx, val) in vector.iter().enumerate() {
545            if val == x {
546                return Some(idx);
547            }
548        }
549        return None;
550    }
551
552    fn validate_parents_present(depgraph: &Dependy<String>,
553                                dep_chain: &Vec<String>,
554                                depname: &String)
555                                -> bool {
556        // Get the next item from the depgraph.  It _must_ exist.
557        let item = depgraph.dep_map.get(depname).unwrap();
558        let my_index = index_of(dep_chain, depname).unwrap();
559        for req in item.requirements() {
560            assert!(dep_chain.contains(req));
561
562            let their_index = index_of(dep_chain, req).unwrap();
563            assert!(their_index < my_index);
564
565            // Validate that the requirement has all elements present.
566            validate_parents_present(depgraph, dep_chain, req);
567        }
568
569        for req in item.suggestions() {
570            assert!(dep_chain.contains(req));
571
572            // Validate that the requirement has all elements present.
573            validate_parents_present(depgraph, dep_chain, req);
574        }
575        true
576    }
577}