mod driver; mod recipe; mod template; use std::{collections::HashSet, fs::File, path::Path}; use clap::Parser; use rebel_common::error::*; use rebel_parse as parse; use rebel_resolve::{self as resolve, context, pin}; use rebel_runner::{self as runner, Runner}; #[derive(Parser)] #[clap(version, about)] struct Opts { /// Allow N jobs at once. /// Defaults to the number of available CPUs #[clap(short, long)] jobs: Option, /// Keep going after some tasks have failed #[clap(short, long)] keep_going: bool, /// The tasks to run #[clap(name = "task", required = true)] tasks: Vec, } fn read_pins>(path: P) -> Result { let f = File::open(path)?; let pins: pin::Pins = serde_yaml::from_reader(f) .map_err(Error::new) .context("YAML error")?; Ok(pins) } fn main() { let opts: Opts = Opts::parse(); let runner = unsafe { Runner::new(&runner::Options { jobs: opts.jobs }) }.unwrap(); let ctx = context::Context::new( recipe::read_recipes("examples/recipes").unwrap(), read_pins("examples/pins.yml").unwrap(), ) .unwrap(); let mut rsv = resolve::Resolver::new(&ctx); let mut force_run = HashSet::new(); for task in opts.tasks { let Ok((parsed, flags)) = parse::task_ref::task_ref_with_flags(&task) else { eprintln!("Invalid task syntax"); std::process::exit(1); }; let task_ref = match ctx.lookup(parsed.id, parsed.args.host, parsed.args.target) { Ok(task_ref) => task_ref, Err(err) => { eprintln!("{}", err); std::process::exit(1); } }; let errors = rsv.add_goal(&task_ref); if !errors.is_empty() { for error in errors { eprintln!("{}", error); } std::process::exit(1); } if flags.force_run { force_run.insert(task_ref); } } let taskset = rsv.into_taskset(); let mut driver = driver::Driver::new(&ctx, taskset, force_run).unwrap(); match driver.run(&runner, opts.keep_going) { Ok(success) => { if !success { std::process::exit(1); } } Err(error) => { eprintln!("{}", error); std::process::exit(1); } } }