main.rs
Raw
#[macro_use]
extern crate serde_derive;
extern crate docopt;
extern crate chrono;
mod config;
use config::Config;
mod job;
use job::Job;
mod run;
use run::Run;
use docopt::Docopt;
use std::env;
use std::io;
use std::fs;
use std::path::{Path, PathBuf};
use std::process;
const USAGE: &'static str = "
Job Runner
Usage:
job <command> [<name>]
job [options]
Options:
-h --help Show this screen.
--version Show version.
Commands:
list List available projects
info <name> Show information for <name>
run <name> Run job <name>
";
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
#[derive(Debug, Deserialize)]
struct Args {
arg_command: Option<Command>,
arg_name: String,
}
#[derive(Debug, Deserialize)]
enum Command {
List, Info, Run,
}
fn list_jobs(dir: &Path) -> io::Result<Vec<Job>> {
let mut v: Vec<Job> = vec![];
for entry in try!(fs::read_dir(dir)) {
let entry = try!(entry);
if !try!(fs::metadata(entry.path())).is_dir() { continue; }
match Job::from_dir(entry.path().as_path()) {
Ok(j) => v.push(j),
Err(_) => continue,
}
}
Ok(v)
}
fn print_job_list(conf: &Config) {
let l = match list_jobs(conf.base_dir.as_path()) {
Ok(v) => v,
Err(e) => { println!("Unable to get job list: {}", e); return },
};
println!("Available jobs:");
for job in l.iter() {
println!("{}", job);
}
}
fn print_job_info(job_name: &String, conf: &Config) {
let job = match Job::from_dir(conf.base_dir.join(job_name).as_path()) {
Ok(x) => x,
Err(e) => { println!("Error retrieving configuration for {}: {}", job_name, e); return },
};
println!("{}", job);
}
fn print_job_run(job_name: &String, conf: &Config) {
let mut job = match Job::from_dir(conf.base_dir.join(job_name).as_path()) {
Ok(x) => x,
Err(e) => { println!("Error retrieving configuration for {}: {}", job_name, e); return },
};
job.name = job_name.clone(); //This is to allow for directories in name
let mut run = Run::new(&job, conf);
//TODO: do we want to exit nonzero if the job exited nonzero? probably
match run.output() {
Ok(result) => println!("Run of {} ({}) at {} completed, output in {:?}",
job.display,
job.name,
result.run_start.to_rfc3339(),
result.archive_dir),
Err(e) => {
println!("Run failed: {}", e);
process::exit(2);
},
}
}
fn main() {
let args: Args = Docopt::new(USAGE)
.and_then(|d| d.version(Some(VERSION.to_string())).deserialize())
.unwrap_or_else(|e| e.exit());
let conf_dir = match env::current_dir() {
Ok(ref p) => p.to_path_buf(),
Err(e) => { println!("Could not get current dir: {}", e); PathBuf::from("/tmp/jobs") },
};
let config = match Config::from_file(&conf_dir.join("config.toml")) {
Ok(c) => c,
Err(e) => { println!("Error reading configuration file in {:?}: {}", conf_dir, e); process::exit(1); },
};
match args.arg_command {
Some(Command::List) => print_job_list(&config),
Some(Command::Info) | Some(Command::Run) if args.arg_name.is_empty() => {
println!("{:?} needs a job name", args.arg_command.unwrap());
println!("{}", USAGE);
process::exit(1);
},
Some(Command::Info) => print_job_info(&args.arg_name, &config),
Some(Command::Run) => print_job_run(&args.arg_name, &config),
None => {
println!("No command specified");
println!("{}", USAGE);
},
}
//println!("{:?}", args);
}