1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
use im::{HashMap, HashSet};
use std::{fmt, path::Path, rc::Rc};
mod recipe;
#[derive(Debug)]
enum Error {
TaskNotFound(String),
DependencyCycle(String),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::TaskNotFound(id) => write!(f, "Task not found: {}", id),
Error::DependencyCycle(id) => write!(f, "DependencyCycle: {}", id),
}
}
}
impl std::error::Error for Error {}
type Result<T> = std::result::Result<T, Error>;
#[derive(Default)]
struct Context {
tasks: HashMap<String, Rc<recipe::Task>>,
}
impl Context {
fn collect_subtasks<'a>(
&'a self,
queued: &HashSet<&'a str>,
id: &str,
) -> Result<HashSet<&'a str>> {
let (task_id, task) = match self.tasks.get_key_value(id) {
Some(t) => t,
None => {
return Err(Error::TaskNotFound(id.to_string()));
}
};
if queued.contains(id) {
return Err(Error::DependencyCycle(id.to_string()));
}
let queued_sub = queued.update(task_id);
let mut subtasks: HashSet<&'a str> = HashSet::new();
subtasks.insert(task_id);
for dep in &task.depends {
let deptasks = self.collect_subtasks(&queued_sub, dep)?;
subtasks = subtasks.union(deptasks);
}
Ok(subtasks)
}
fn collect_tasks(&self, id: &str) -> Result<HashSet<&str>> {
self.collect_subtasks(&HashSet::new(), id)
}
}
fn main() -> Result<()> {
let recipes = recipe::read_recipes(Path::new("examples")).unwrap();
let mut ctx = Context::default();
for (recipe_name, recipe) in recipes {
for (task_name, task) in recipe.tasks {
let full_name = format!("{}:{}", recipe_name, task_name);
ctx.tasks.insert(full_name, Rc::new(task));
}
}
let queue = ctx.collect_tasks("ls:build")?;
let (runnable, queued): (HashSet<&str>, HashSet<&str>) = queue
.into_iter()
.partition(|id| ctx.tasks.get(*id).unwrap().depends.is_empty());
for t in &runnable {
println!("Runnable: {} ({:?})", t, ctx.tasks.get(*t).unwrap().run);
}
for t in &queued {
println!("Queued: {} ({:?})", t, ctx.tasks.get(*t).unwrap().run);
}
Ok(())
}
|