summaryrefslogtreecommitdiffstats
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs144
1 files changed, 68 insertions, 76 deletions
diff --git a/src/main.rs b/src/main.rs
index 98d1b8d..8c5708f 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,96 +1,88 @@
-use std::collections::{HashMap, HashSet};
-// use std::io::{self, Write};
-use std::io;
-// use std::process::Command;
-
-struct Task {
- // action: String,
- deps: Vec<String>,
+use im::{HashMap, HashSet};
+use std::{fmt, path::Path, rc::Rc};
+
+mod recipe;
+
+#[derive(Debug)]
+enum Error {
+ TaskNotFound(String),
+ DependencyCycle(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"));
+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),
}
- };
-
- if queued.contains(id) {
- return Err(io::Error::new(
- io::ErrorKind::InvalidData,
- "Dependency cycle",
- ));
}
+}
+
+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()));
+ }
+ };
- let mut queued_sub = queued.clone();
- queued_sub.insert(task_id);
+ 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);
+ 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();
+ for dep in &task.depends {
+ let deptasks = self.collect_subtasks(&queued_sub, dep)?;
+ subtasks = subtasks.union(deptasks);
+ }
+
+ Ok(subtasks)
}
- Ok(subtasks)
+ fn collect_tasks(&self, id: &str) -> Result<HashSet<&str>> {
+ self.collect_subtasks(&HashSet::new(), id)
+ }
}
-fn collect_tasks<'a>(tasks: &'a HashMap<String, Task>, id: &str) -> io::Result<HashSet<&'a str>> {
- collect_subtasks(&HashSet::new(), tasks, 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));
+ }
+ }
-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
+ let queue = ctx.collect_tasks("ls:build")?;
+ let (runnable, queued): (HashSet<&str>, HashSet<&str>) = queue
.into_iter()
- .partition::<HashSet<_>, _>(|id| tasks.get(*id).unwrap().deps.is_empty());
+ .partition(|id| ctx.tasks.get(*id).unwrap().depends.is_empty());
for t in &runnable {
- println!("Runnable: {}", t);
+ println!("Runnable: {} ({:?})", t, ctx.tasks.get(*t).unwrap().run);
}
for t in &queued {
- println!("Queued: {}", t);
+ println!("Queued: {} ({:?})", t, ctx.tasks.get(*t).unwrap().run);
}
Ok(())