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 Requires,
29
30 Suggests,
32
33 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 graph: Dag<K, DepEdge>,
78
79 node_bucket: HashMap<K, NodeIndex>,
81
82 results: HashMap<K, bool>,
84
85 provides_map: HashMap<K, K>,
87
88 requirements: HashMap<K, Vec<K>>,
89 suggestions: HashMap<K, Vec<K>>,
90
91 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 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 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 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 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 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 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 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 if self.graph.find_edge(*previous_edge, *this_edge).is_some() {
218 continue;
219 }
220
221 self.graph.add_edge(*previous_edge, *this_edge, DepEdge::Follows).ok();
223 }
224
225 let mut dep_order = vec![];
227 let mut seen_nodes = HashMap::new();
228 for dep_name in dependencies {
229
230 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 seen_nodes.insert(node.clone(), ()).is_some() {
259 return;
260 }
261
262 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 }
286
287 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 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_parents_present(depgraph, dep_chain, req);
567 }
568
569 for req in item.suggestions() {
570 assert!(dep_chain.contains(req));
571
572 validate_parents_present(depgraph, dep_chain, req);
574 }
575 true
576 }
577}