pub extern crate rayon;
use std::slice;
#[macro_export]
macro_rules! cmd {
($cmd:expr $(, $arg:expr)*; in $cd:expr $(; where $var:ident = $val:expr)*) => {{
use std::process;
if process::Command::new($cmd)
$(
.args({
use $crate::ToSlice;
($arg).to_slice()
})
)*
$(
.env(stringify!($var), $val)
)*
.current_dir($cd)
.stdout(process::Stdio::inherit())
.stderr(process::Stdio::inherit())
.status().is_err() {
return Err(());
}
}};
($cmd:expr $(, $arg:expr)* $(; where $var:ident = $val:expr)*) => {{
use std::process;
if process::Command::new($cmd)
$(
.args({
use $crate::ToSlice;
($arg).to_slice()
})
)*
$(
.env(stringify!($var), $val)
)*
.stdout(process::Stdio::inherit())
.stderr(process::Stdio::inherit())
.status().is_err() {
return Err(());
}
}};
}
pub trait ToSlice<T> {
fn to_slice(&self) -> &[T];
}
impl<T> ToSlice<T> for T {
fn to_slice(&self) -> &[T] {
unsafe { slice::from_raw_parts(self as *const T, 1) }
}
}
impl<T> ToSlice<T> for [T] {
fn to_slice(&self) -> &[T] {
self
}
}
#[macro_export]
macro_rules! par {
() => {
Ok(())
};
($a:expr) => {{
try!($a);
Ok(())
}};
($a:expr, $($rest:expr),*) => {{
let (a, b) = $crate::rayon::join(|| $a, || par!($($rest),*));
try!(a);
try!(b);
Ok(())
}};
}
#[macro_export]
macro_rules! build {
{ $($name:ident($($dep:ident),*) => $cont:expr,)* } => {
use std::io::Write;
use std::sync::Mutex;
use std::{env, io, process};
enum Error {
Failed(&'static str),
NotFound,
}
#[derive(Default)]
struct CakeBuild {
$(
$name: Mutex<bool>
),*
}
fn unit(name: &str) {
let mut stdout = io::stdout();
writeln!(stdout, "== Running recipe {} ==", name).unwrap();
}
impl CakeBuild {
$(
fn $name(&self) -> Result<(), Error> {
fn inner() -> Result<(), ()> {
unit(stringify!($name));
$cont;
Ok(())
}
try!(par!(
$(
{
let mut lock = self.$dep.lock().unwrap();
if !*lock {
try!(self.$dep());
}
*lock = true;
Ok(())
}
),*
));
inner().map_err(|_| Error::Failed(stringify!($name)))
}
)*
fn run_recipe(&self, cmd: &str) -> Result<(), Error> {
match cmd {
$(
stringify!($name) => {
let res = self.$name();
*self.$name.lock().unwrap() = true;
res
}
)*
_ => Err(Error::NotFound),
}
}
}
fn main() {
let build = CakeBuild::default();
let stderr = io::stderr();
let mut run = false;
for i in env::args().skip(1) {
run = true;
if let Err(x) = build.run_recipe(&i) {
let mut stderr = stderr.lock();
match x {
Error::NotFound => writeln!(stderr, "recipe, {}, not found.", i),
Error::Failed(name) => writeln!(stderr, "recipe, {}, failed.", name),
}.unwrap();
stderr.flush().unwrap();
process::exit(1);
}
}
let mut stderr = stderr.lock();
if !run {
writeln!(stderr, "No argument given. Aborting.").unwrap();
}
}
};
}