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
90
91
92
93
94
95
96
97
|
use std::collections::{HashMap, HashSet};
// use std::io::{self, Write};
use std::io;
// use std::process::Command;
struct Task {
// action: String,
deps: Vec<String>,
}
// impl Task {
// fn run(&self) -> io::Result<()> {
// let output = Command::new("sh").arg("-c").arg(&self.action).output()?;
// let stdout = io::stdout();
// let mut handle = stdout.lock();
// handle.write_all(&output.stdout)?;
// Ok(())
// }
// }
fn collect_subtasks<'a>(
queued: &HashSet<&'a str>,
tasks: &'a HashMap<String, Task>,
id: &str,
) -> io::Result<HashSet<&'a str>> {
let (task_id, task) = match tasks.get_key_value(id) {
Some(t) => t,
None => {
return Err(io::Error::new(io::ErrorKind::NotFound, "Task not found"));
}
};
if queued.contains(id) {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Dependency cycle",
));
}
let mut queued_sub = queued.clone();
queued_sub.insert(task_id);
let mut subtasks: HashSet<&'a str> = HashSet::new();
subtasks.insert(task_id);
for dep in &task.deps {
let deptasks = collect_subtasks(&queued_sub, tasks, dep)?;
subtasks = subtasks.union(&deptasks).copied().collect();
}
Ok(subtasks)
}
fn collect_tasks<'a>(tasks: &'a HashMap<String, Task>, id: &str) -> io::Result<HashSet<&'a str>> {
collect_subtasks(&HashSet::new(), tasks, id)
}
fn main() -> io::Result<()> {
let mut tasks = HashMap::new();
tasks.insert(
String::from("ls"),
Task {
// action: String::from("ls"),
deps: vec!["foo".to_owned(), "bar".to_owned()],
},
);
tasks.insert(
String::from("foo"),
Task {
// action: String::from("echo foo"),
deps: vec!["bar".to_owned()],
},
);
tasks.insert(
String::from("bar"),
Task {
// action: String::from("echo bar"),
deps: vec![],
},
);
let queue = collect_tasks(&tasks, "ls")?;
let (runnable, queued) = queue
.into_iter()
.partition::<HashSet<_>, _>(|id| tasks.get(*id).unwrap().deps.is_empty());
for t in &runnable {
println!("Runnable: {}", t);
}
for t in &queued {
println!("Queued: {}", t);
}
Ok(())
}
|