mod config;
mod builder;
mod logger;
extern crate rustc_serialize;
extern crate docopt;
extern crate term;
extern crate notify;
use docopt::Docopt;
use std::process;
use std::io::prelude::*;
use std::fs::File;
use std::io::Error;
use std::path::Path;
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const USAGE: &'static str = "
comet ☄
Usage:
comet [options]
comet --version
Options:
-h --help Show this screen.
--version Show version.
-p PATH, --path=PATH Specifies the working directory. [default: .]
-w --watch Watch the working directory.
";
#[derive(Debug, RustcDecodable)]
struct Args {
flag_path: String,
flag_version: bool,
flag_watch: bool
}
fn read_config_file(cwd: &str) -> Result<String, Error> {
let mut f = try!(File::open(Path::new(cwd).join(".comet.json")));
let mut file_content = String::new();
try!(f.read_to_string(&mut file_content));
Ok(file_content)
}
fn watch(configuration: config::Config, cwd: &str) {
use notify::{RecommendedWatcher, Error, Watcher};
use std::sync::mpsc::channel;
let watch_path = Path::new(cwd).join(&configuration.watch);
let (tx, rx) = channel();
let w: Result<RecommendedWatcher, Error> = Watcher::new(tx);
match w {
Ok(mut watcher) => {
match watcher.watch(watch_path) {
Ok(()) => {
loop {
match rx.recv() {
_ => {
logger::stdout("detected change. starting build");
run(&configuration, cwd);
}
}
}
},
Err(err) => {
logger::stderr("[ERR] Error while watching");
logger::stderr(format!("{:?}", err));
}
}
},
Err(err) => {
logger::stderr("[ERR] Failed to instantiate filesystem watcher");
logger::stderr(format!("Reason: {:?}", err));
}
}
}
fn run(configuration: &config::Config, cwd: &str) {
match builder::build(configuration, cwd) {
Ok(results) => {
for stats in results.results {
logger::stdout("------------------\n");
if stats.success {
logger::success(format!("Command: {}", stats.script));
logger::success(stats.stdout);
} else {
logger::stderr(format!("Command: {}", stats.script));
logger::stderr(stats.stderr);
}
}
},
Err(err) => {
println!("[ERR] {:?}", err);
}
}
}
fn main() {
let args: Args = Docopt::new(USAGE)
.and_then(|d| d.decode())
.unwrap_or_else(|e| e.exit());
if args.flag_version {
logger::stdout(format!("comet ☄ -- v{}", VERSION));
process::exit(0);
}
logger::stdout("comet ☄");
let cwd = if args.flag_path.len() == 0 {
".".into()
} else {
args.flag_path
};
let json = match read_config_file(&cwd) {
Ok(fc) => fc,
Err(err) => {
logger::stderr("[ERR] Could not read configuration file");
logger::stderr(format!("[ERR] Reason {:?}", err));
std::process::exit(1)
}
};
let configuration = match config::from_json(&json) {
Ok(cfg) => cfg,
Err(err) => {
logger::stderr("[ERR] Failed to parse configuration file");
logger::stderr(format!("[ERR] Reason: {:?}", err));
std::process::exit(1)
}
};
logger::stdout(format!("configuration script {:?}", configuration.script));
if args.flag_watch {
logger::stdout("Comet is watching...");
watch(configuration, &cwd);
}
else {
run(&configuration, &cwd);
}
}