use std::error::Error;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::{env, process};
use clap::{App, AppSettings, Arg, SubCommand};
use log::LevelFilter;
use simple_logger::SimpleLogger;
use workflow::{Step, Workflow, WorkflowExecutor};
fn main() {
let matches = App::new("Workflow")
.version(clap::crate_version!())
.author(clap::crate_authors!())
.about(clap::crate_description!())
.setting(AppSettings::ArgRequiredElseHelp)
.arg(
Arg::with_name("log-level")
.long("log-level")
.help("Sets the logging level")
.default_value("info"),
)
.subcommand(
SubCommand::with_name("execute")
.alias("exec")
.alias("e")
.about("Execute given workflow")
.arg(
Arg::with_name("FILE")
.help("Sets the workflow file to use")
.required(true),
),
)
.subcommand(
SubCommand::with_name("validate")
.alias("v")
.about("Validate given workflow")
.arg(
Arg::with_name("FILE")
.help("Sets the workflow file to use")
.required(true),
),
)
.subcommand(
SubCommand::with_name("generate")
.alias("g")
.about("Generate workflow file"),
)
.get_matches();
configure_logging(matches.value_of("log-level").unwrap()).expect("unable to configure logging");
if let Some(args) = matches.subcommand_matches("execute") {
let file = args.value_of("FILE").unwrap();
match execute_workflow(file) {
Ok(_) => {}
Err(e) => {
log::error!("{}", e);
process::exit(1);
}
}
} else if let Some(args) = matches.subcommand_matches("validate") {
let file = args.value_of("FILE").unwrap();
match validate_workflow(file) {
Ok(w) => log::info!("Workflow `{}` is valid", w.id),
Err(e) => {
log::error!("{}", e);
process::exit(1);
}
}
} else if matches.subcommand_matches("generate").is_some() {
match generate_workflow() {
Ok(w) => {
let content = serde_yaml::to_string(&w).unwrap();
println!("{}", content);
}
Err(e) => {
log::error!("{}", e);
process::exit(1);
}
}
}
}
fn execute_workflow<P: AsRef<Path>>(path: P) -> Result<(), Box<dyn Error>> {
let cwd = env::current_dir()?;
let path = get_workflow_path(path)?;
let workflow = Workflow::from_file(path)?;
let executor = WorkflowExecutor::with_cache(cwd.join("workflows"))?;
executor.execute(&workflow)
}
fn validate_workflow<P: AsRef<Path>>(path: P) -> Result<Workflow, Box<dyn Error>> {
let path = get_workflow_path(path)?;
Workflow::from_file(path)
}
fn generate_workflow() -> Result<Workflow, Box<dyn Error>> {
let step = Step {
name: None,
uses: None,
exec: Some("echo Hello, world.".to_string()),
with: None,
};
Ok(Workflow {
id: "hello-world".to_string(),
name: Some("Hello world".to_string()),
author: None,
description: Some("Simple workflow that print `Hello, world.`".to_string()),
steps: vec![step],
})
}
fn get_workflow_path<P: AsRef<Path>>(path: P) -> Result<PathBuf, Box<dyn Error>> {
let cwd = env::current_dir()?;
if path.as_ref().starts_with(".") {
Ok(cwd.join(path))
} else {
Ok(path.as_ref().to_path_buf())
}
}
fn configure_logging(level: &str) -> Result<(), Box<dyn Error>> {
SimpleLogger::new()
.with_level(LevelFilter::from_str(level).unwrap_or(LevelFilter::Debug))
.init()
.map_err(|v| v.into())
}