summaryrefslogtreecommitdiffstats
path: root/src/main.rs
blob: 98d1b8d45396d0ac46c5824d6d33b4c881b3597f (plain)
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(())
}