use clap::{Arg, Command};
use crate::app::args::Args;
use crate::types::{list::*, map::*};
use std::path::PathBuf;
pub fn app() -> Command {
trace!("app");
Command::new("Sita")
.name(env!("CARGO_PKG_NAME"))
.version(env!("CARGO_PKG_VERSION"))
.author(env!("CARGO_PKG_AUTHORS"))
.about(env!("CARGO_PKG_DESCRIPTION"))
.arg(Arg::new("input")
.help("An input path.\nExample file: --input \"example.html\" …\nExample directory: --input \"examples/\" …\nExample glob: --input \"examples/**/*\" …")
.short('i')
.long("input")
.alias("inputs")
.value_name("FILE | DIRECTORY | GLOB")
.value_parser(clap::value_parser!(PathBuf))
.action(clap::ArgAction::Append)
.num_args(1..)
)
.arg(Arg::new("output")
.help("An output path.\nExample file: --output \"example.html\" …\nExample directory: --output \"examples/\" …\nExample glob: --output \"examples/**/*\" …")
.short('o')
.long("output")
.alias("outputs")
.value_name("FILE | DIRECTORY | GLOB")
.value_parser(clap::value_parser!(PathBuf))
.action(clap::ArgAction::Append)
.num_args(1..)
)
.arg(Arg::new("template")
.help("A template path.\nExample file: --template \"example.html\" …\nExample directory: --template \"examples/\" …\nExample glob: --template \"examples/**/*\" …")
.short('t')
.long("template")
.alias("templates")
.value_name("FILE | DIRECTORY | GLOB")
.value_parser(clap::value_parser!(PathBuf))
.action(clap::ArgAction::Append)
.num_args(1..)
)
.arg(Arg::new("extra")
.help("An extra path such as for helpers, scripts, utilities, etc.\nExample file: --extra \"example.rhai\" …\nExample directory: --extra \"extras/\" …\nExample glob: --extra \"extras/**/*\" …")
.short('e')
.long("extra")
.alias("extras")
.value_name("FILE | DIRECTORY | GLOB")
.value_parser(clap::value_parser!(PathBuf))
.action(clap::ArgAction::Append)
)
.arg(Arg::new("set")
.help("Set a variable name to a value.\nExample: --set pi 3.1415 …")
.short('s')
.long("set")
.num_args(2)
.value_names(&["NAME", "VALUE"])
.value_parser(clap::value_parser!(String))
.action(clap::ArgAction::Append)
)
.arg(Arg::new("test")
.help("Print test output for debugging, verifying, tracing, and the like.\nExample: --test")
.long("test")
.action(clap::ArgAction::SetTrue)
)
.arg(Arg::new("output_file_name_extension")
.help("The output file name extension.\nDefault: \"html\".\nExample: --output-extension \"html\"")
.long("output-extension")
.value_name("EXTENSION")
.value_parser(clap::value_parser!(PathBuf))
.action(clap::ArgAction::Append)
)
.arg(Arg::new("verbose")
.help("Set the verbosity level: 0=none, 1=error, 2=warn, 3=info, 4=debug, 5=trace.\nExample: --verbose …")
.short('v')
.long("verbose")
.action(clap::ArgAction::Count)
)
}
pub fn args() -> Args {
trace!("args");
let matches = app().get_matches();
trace!("args ➡ matches: {:?}", matches);
let input_list: Option<List<PathBuf>> = match matches.get_many("input") {
Some(paths) => Some(paths.map(|path: &PathBuf| path.to_owned()).collect()),
None => None,
};
let output_list: Option<List<PathBuf>> = match matches.get_many("output") {
Some(paths) => Some(paths.map(|path: &PathBuf| path.to_owned()).collect()),
_ => None,
};
let output_file_name_extension: Option<PathBuf> = match matches.get_one::<PathBuf>("output_file_name_extension") {
Some(x) => Some(x.to_owned()),
_ => None,
};
let extra_list: Option<List<PathBuf>> = match matches.get_many("extra") {
Some(paths) => Some(paths.map(|path: &PathBuf| path.to_owned()).collect()),
_ => None,
};
let settings = match matches.get_occurrences("set") {
Some(occurrences) => {
let occurrences: Vec<Vec<&String>> = occurrences.map(Iterator::collect).collect();
let map: Map<String, String> =
occurrences.into_iter().map(|occurrence|
(
occurrence[0].to_owned(),
occurrence[1].to_owned()
)
).collect();
Some(map)
},
None => None,
};
let template_list: Option<List<PathBuf>> = match matches.get_many("template") {
Some(paths) => Some(paths.map(|path: &PathBuf| path.to_owned()).collect()),
_ => None,
};
let test = matches.get_flag("test");
let log_level = match matches.get_count("verbose") {
0 => None,
1 => Some(::log::Level::Error),
2 => Some(::log::Level::Warn),
3 => Some(::log::Level::Info),
4 => Some(::log::Level::Debug),
5 => Some(::log::Level::Trace),
_ => Some(::log::Level::Trace),
};
let args = Args {
input_list: input_list,
log_level: log_level,
output_list: output_list,
output_file_name_extension: output_file_name_extension,
settings: settings,
template_list: template_list,
extra_list: extra_list,
test: test,
};
trace!("args ➡ args: {:?}", args);
args
}
#[cfg(test)]
mod tests {
use crate::testing::*;
use assertables::*;
#[test]
fn test_test() {
let mut command = std::process::Command::new(&*COMMAND_OS);
command.args(&["--test"]);
let target = r#"Args { "#;
assert_command_stdout_contains!(command, &target);
}
#[test]
fn test_verbose() {
assert_program_args_stdout_contains!(&*COMMAND_OS, &["--test"], r#" log_level: None"#);
assert_program_args_stdout_contains!(&*COMMAND_OS, &["--test", "-v"], r#" log_level: Some(Error)"#);
assert_program_args_stdout_contains!(&*COMMAND_OS, &["--test", "-vv"], r#" log_level: Some(Warn)"#);
assert_program_args_stdout_contains!(&*COMMAND_OS, &["--test", "-vvv"], r#" log_level: Some(Info)"#);
assert_program_args_stdout_contains!(&*COMMAND_OS, &["--test", "-vvvv"], r#" log_level: Some(Debug)"#);
assert_program_args_stdout_contains!(&*COMMAND_OS, &["--test", "-vvvvv"], r#" log_level: Some(Trace)"#);
assert_program_args_stdout_contains!(&*COMMAND_OS, &["--test", "--verbose"], r#" log_level: Some(Error)"#);
assert_program_args_stdout_contains!(&*COMMAND_OS, &["--test", "--verbose", "--verbose"], r#" log_level: Some(Warn)"#);
assert_program_args_stdout_contains!(&*COMMAND_OS, &["--test", "--verbose", "--verbose", "--verbose"], r#" log_level: Some(Info)"#);
assert_program_args_stdout_contains!(&*COMMAND_OS, &["--test", "--verbose", "--verbose", "--verbose", "--verbose"], r#" log_level: Some(Debug)"#);
assert_program_args_stdout_contains!(&*COMMAND_OS, &["--test", "--verbose", "--verbose", "--verbose", "--verbose", "--verbose"], r#" log_level: Some(Trace)"#);
}
#[test]
fn test_input() {
let s = "alfa";
let target = format!(" input_list: Some([\"{}\"])", &s);
let mut command = std::process::Command::new(&*COMMAND_OS);
command.args(&["--test", "-i", &s]);
assert_command_stdout_contains!(command, &target);
let mut command = std::process::Command::new(&*COMMAND_OS);
command.args(&["--test", "--input", &s]);
assert_command_stdout_contains!(command, &target);
let mut command = std::process::Command::new(&*COMMAND_OS);
command.args(&["--test", "--inputs", &s]);
assert_command_stdout_contains!(command, &target);
let s1 = "alfa";
let s2 = "bravo";
let s3 = "charlie";
let s4 = "delta";
let target = format!(" input_list: Some([\"{}\", \"{}\", \"{}\", \"{}\"])", &s1, &s2, &s3, &s4);
let mut command = std::process::Command::new(&*COMMAND_OS);
command.args(&["--test", "-i", &s1, &s2, "--input", &s3, &s4]);
assert_command_stdout_contains!(command, &target);
let mut command = std::process::Command::new(&*COMMAND_OS);
command.args(&["--test", "--input", &s1, &s2, "--input", &s3, &s4]);
assert_command_stdout_contains!(command, &target);
let mut command = std::process::Command::new(&*COMMAND_OS);
command.args(&["--test", "--inputs", &s1, &s2, "--inputs", &s3, &s4]);
assert_command_stdout_contains!(command, &target);
}
#[test]
fn test_output() {
let s = "alfa";
let target = format!(" output_list: Some([\"{}\"])", &s);
let mut command = std::process::Command::new(&*COMMAND_OS);
command.args(&["--test", "-o", &s]);
assert_command_stdout_contains!(command, &target);
let mut command = std::process::Command::new(&*COMMAND_OS);
command.args(&["--test", "--output", &s]);
assert_command_stdout_contains!(command, &target);
let mut command = std::process::Command::new(&*COMMAND_OS);
command.args(&["--test", "--outputs", &s]);
assert_command_stdout_contains!(command, &target);
let s1 = "alfa";
let s2 = "bravo";
let s3 = "charlie";
let s4 = "delta";
let target = format!(" output_list: Some([\"{}\", \"{}\", \"{}\", \"{}\"])", &s1, &s2, &s3, &s4);
let mut command = std::process::Command::new(&*COMMAND_OS);
command.args(&["--test", "-o", &s1, &s2, "-o", &s3, &s4]);
assert_command_stdout_contains!(command, &target);
let mut command = std::process::Command::new(&*COMMAND_OS);
command.args(&["--test", "--output", &s1, &s2, "--output", &s3, &s4]);
assert_command_stdout_contains!(command, &target);
let mut command = std::process::Command::new(&*COMMAND_OS);
command.args(&["--test", "--outputs", &s1, &s2, "--outputs", &s3, &s4]);
assert_command_stdout_contains!(command, &target);
}
#[test]
fn test_clap_output_file_name_extension() {
let mut command = std::process::Command::new(&*COMMAND_OS);
command.args(&["--test", "--output-extension", "alfa"]);
let target = r#" output_file_name_extension: Some("alfa")"#;
assert_command_stdout_contains!(command, &target);
}
#[test]
fn test_template() {
let s = "alfa";
let target = format!(" template_list: Some([\"{}\"", &s);
let mut command = std::process::Command::new(&*COMMAND_OS);
command.args(&["--test", "-t", &s]);
assert_command_stdout_contains!(command, &target);
let mut command = std::process::Command::new(&*COMMAND_OS);
command.args(&["--test", "--template", &s]);
assert_command_stdout_contains!(command, &target);
let mut command = std::process::Command::new(&*COMMAND_OS);
command.args(&["--test", "--templates", &s]);
assert_command_stdout_contains!(command, &target);
let s1 = "alfa";
let s2 = "bravo";
let s3 = "charlie";
let s4 = "delta";
let target = format!(" template_list: Some([\"{}\", \"{}\", \"{}\", \"{}\"])", &s1, &s2, &s3, &s4);
let mut command = std::process::Command::new(&*COMMAND_OS);
command.args(&["--test", "-t", &s1, &s2, "-t", &s3, &s4]);
assert_command_stdout_contains!(command, &target);
let mut command = std::process::Command::new(&*COMMAND_OS);
command.args(&["--test", "--template", &s1, &s2, "--template", &s3, &s4]);
assert_command_stdout_contains!(command, &target);
let mut command = std::process::Command::new(&*COMMAND_OS);
command.args(&["--test", "--templates", &s1, &s2, "--templates", &s3, &s4]);
assert_command_stdout_contains!(command, &target);
}
}