maker 0.0.1

Generic Rusty declarative build system like GNU Make
Documentation
type RecipeFn = dyn Fn(&str, &[String]);

pub struct Target {
    name: String,
    is_file: bool,
    file_dependencies: Vec<String>,
    dependencies: Vec<Target>,
    recipe: Option<Box<RecipeFn>>,
}

impl Target {
    pub fn new_phony(name: &str) -> Self {
        Self {
            name: name.to_string(),
            is_file: false,
            file_dependencies: Vec::new(),
            dependencies: Vec::new(),
            recipe: None,
        }
    }

    pub fn new_file(name: &str) -> Self {
        let mut target = Self::new_phony(name);
        target.is_file = true;
        target
    }

    pub fn depends_on_file(mut self, file: &str) -> Self {
        self.file_dependencies.push(file.to_string());
        self
    }

    pub fn depends_on_target(mut self, target: Target) -> Self {
        self.dependencies.push(target);
        self
    }

    pub fn recipe<F>(mut self, recipe: F) -> Self
    where
        F: Fn(&str, &[String]) + 'static,
    {
        self.recipe = Some(Box::new(recipe) as Box<RecipeFn>);
        self
    }

    pub fn make(&self) {
        if let Some(ref recipe) = self.recipe {
            let deps: Vec<String> = self.file_dependencies.to_vec();
            recipe(&self.name, &deps);
        }
        for dep in &self.dependencies {
            dep.make();
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::process::Command;

    #[test]
    fn target_construction() {
        let obj = Target::new_file("main.o")
            .depends_on_file("main.c")
            .recipe(|target, deps| {
                Command::new("gcc")
                    .arg("-o")
                    .arg(target)
                    .args(deps)
                    .status()
                    .unwrap();
            });
        let bin = Target::new_file("main")
            .depends_on_target(obj)
            .recipe(|target, deps| {
                Command::new("ld")
                    .arg("-o")
                    .arg(target)
                    .args(deps)
                    .status()
                    .unwrap();
            });
        bin.make();
    }
}