diff --git a/src/cli.rs b/src/cli.rs index f1dcc99..9e9d5a2 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,6 +1,24 @@ -use crate::models::{Pipeline, Task}; +use crate::model_injection::inject_pipeline_metadata; +use crate::models::{Pipeline, RoxFile, Task}; use clap::{crate_version, Arg, ArgAction, Command}; +/// Dyanmically construct the CLI from the Roxfile +pub fn construct_cli(roxfile: RoxFile, file_path: &str) -> clap::Command { + let mut cli = cli_builder(); + + // Tasks + let task_subcommands = build_task_subcommands(&roxfile.tasks); + cli = cli.subcommands(vec![task_subcommands]); + + // Pipelines + if let Some(pipelines) = roxfile.pipelines { + let sorted_pipelines = inject_pipeline_metadata(pipelines, file_path); + let pipeline_subcommands = build_pipeline_subcommands(&sorted_pipelines); + cli = cli.subcommands(vec![pipeline_subcommands]); + } + cli +} + /// Construct the CLI pub fn cli_builder() -> Command { Command::new("rox") diff --git a/src/lib.rs b/src/lib.rs index cb689f3..3281a81 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,112 +1,28 @@ +mod cli; mod execution; mod file_requirements; +mod model_injection; mod models; +mod output; mod utils; mod version_requirements; -use std::collections::HashMap; - -use models::RoxFile; +use crate::cli::{cli_builder, construct_cli}; use crate::execution::{execute_stages, execute_tasks, PassFail, TaskResult}; -mod cli; -mod output; +use crate::model_injection::{inject_task_metadata, inject_template_values}; +use std::collections::HashMap; use std::error::Error; type RoxResult = Result>; -/// Inject additional metadata into each Pipeline and sort based on name. -fn inject_pipeline_metadata( - pipelines: Vec, - file_path: &str, -) -> Vec { - let mut sorted_pipelines: Vec = pipelines - .into_iter() - .map(|mut pipeline| { - pipeline.file_path = Some(file_path.to_owned()); - pipeline - }) - .collect(); - sorted_pipelines.sort_by(|x, y| x.name.to_lowercase().cmp(&y.name.to_lowercase())); - sorted_pipelines -} - -/// Get used Template's information and inject set values -fn inject_template_values(mut task: models::Task, template: &models::Template) -> models::Task { - task.command = { - let mut template_command = template.command.clone(); - let template_symbols = template.symbols.clone(); - let task_values = task.values.clone().unwrap(); - - for i in 0..task_values.len() { - template_command = template_command.replace( - template_symbols.get(i).unwrap(), - task_values.get(i).unwrap(), - ); - } - Some(template_command) - }; - task -} - -#[test] -fn inject_template_values_valid() { - let test_task = models::Task { - name: "Test".to_string(), - command: None, - file_path: None, - uses: None, - values: Some(vec!["1".to_owned(), "2".to_owned()]), - description: None, - hide: None, - workdir: None, - }; - let test_template = models::Template { - name: "Test".to_string(), - command: "This is {one} and {two}".to_owned(), - symbols: vec!["{one}".to_owned(), "{two}".to_owned()], - }; - let output_task = inject_template_values(test_task, &test_template); - assert_eq!(output_task.command.unwrap(), "This is 1 and 2".to_owned()) -} - -/// Inject additional metadata into each Task and sort based on name. -fn inject_task_metadata(tasks: Vec, file_path: &str) -> Vec { - let mut sorted_tasks: Vec = tasks - .into_iter() - .map(|mut task| { - task.file_path = Some(file_path.to_owned()); - task - }) - .collect(); - sorted_tasks.sort_by(|x, y| x.name.to_lowercase().cmp(&y.name.to_lowercase())); - sorted_tasks -} - /// Get the filepath from the CLI fn get_filepath() -> String { - let cli = cli::cli_builder(); + let cli = cli_builder(); // Get the file arg from the CLI if set let cli_matches = cli.clone().arg_required_else_help(false).get_matches(); cli_matches.get_one::("roxfile").unwrap().to_owned() } -/// Dyanmically construct the CLI from the Roxfile -fn construct_cli(roxfile: RoxFile, file_path: &str) -> clap::Command { - let mut cli = cli::cli_builder(); - - // Tasks - let task_subcommands = cli::build_task_subcommands(&roxfile.tasks); - cli = cli.subcommands(vec![task_subcommands]); - - // Pipelines - if let Some(pipelines) = roxfile.pipelines.clone() { - let sorted_pipelines = inject_pipeline_metadata(pipelines, file_path); - let pipeline_subcommands = cli::build_pipeline_subcommands(&sorted_pipelines); - cli = cli.subcommands(vec![pipeline_subcommands]); - } - cli -} - // Entrypoint for the Crate CLI pub fn rox() -> RoxResult<()> { let start = std::time::Instant::now(); @@ -118,11 +34,11 @@ pub fn rox() -> RoxResult<()> { // Get the file arg from the CLI if set let file_path = get_filepath(); let roxfile = utils::parse_file_contents(utils::load_file(&file_path)); - utils::horizontal_rule(); + utils::print_horizontal_rule(); - // Build/Generate the CLI based on the loaded Roxfile - let tasks = inject_task_metadata(roxfile.tasks.clone(), &file_path); + // Build & Generate the CLI based on the loaded Roxfile let cli = construct_cli(roxfile.clone(), &file_path); + let tasks = inject_task_metadata(roxfile.tasks, &file_path); let cli_matches = cli.get_matches(); // Run File and Version checks @@ -130,7 +46,7 @@ pub fn rox() -> RoxResult<()> { // Check Versions if roxfile.version_requirements.is_some() { for version_check in roxfile.version_requirements.into_iter().flatten() { - version_requirements::check_version(version_check.clone()); + version_requirements::check_version(version_check); } } diff --git a/src/model_injection.rs b/src/model_injection.rs new file mode 100644 index 0000000..b5f443e --- /dev/null +++ b/src/model_injection.rs @@ -0,0 +1,69 @@ +use crate::models; + +/// Inject additional metadata into each Pipeline and sort based on name. +pub fn inject_pipeline_metadata( + pipelines: Vec, + file_path: &str, +) -> Vec { + let mut sorted_pipelines: Vec = pipelines + .into_iter() + .map(|mut pipeline| { + pipeline.file_path = Some(file_path.to_owned()); + pipeline + }) + .collect(); + sorted_pipelines.sort_by(|x, y| x.name.to_lowercase().cmp(&y.name.to_lowercase())); + sorted_pipelines +} + +/// Get used Template's information and inject set values +pub fn inject_template_values(mut task: models::Task, template: &models::Template) -> models::Task { + task.command = { + let mut template_command = template.command.clone(); + let template_symbols = template.symbols.clone(); + let task_values = task.values.clone().unwrap(); + + for i in 0..task_values.len() { + template_command = template_command.replace( + template_symbols.get(i).unwrap(), + task_values.get(i).unwrap(), + ); + } + Some(template_command) + }; + task +} + +#[test] +fn inject_template_values_valid() { + let test_task = models::Task { + name: "Test".to_string(), + command: None, + file_path: None, + uses: None, + values: Some(vec!["1".to_owned(), "2".to_owned()]), + description: None, + hide: None, + workdir: None, + }; + let test_template = models::Template { + name: "Test".to_string(), + command: "This is {one} and {two}".to_owned(), + symbols: vec!["{one}".to_owned(), "{two}".to_owned()], + }; + let output_task = inject_template_values(test_task, &test_template); + assert_eq!(output_task.command.unwrap(), "This is 1 and 2".to_owned()) +} + +/// Inject additional metadata into each Task and sort based on name. +pub fn inject_task_metadata(tasks: Vec, file_path: &str) -> Vec { + let mut sorted_tasks: Vec = tasks + .into_iter() + .map(|mut task| { + task.file_path = Some(file_path.to_owned()); + task + }) + .collect(); + sorted_tasks.sort_by(|x, y| x.name.to_lowercase().cmp(&y.name.to_lowercase())); + sorted_tasks +} diff --git a/src/utils.rs b/src/utils.rs index 46e8121..dc9c56f 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -35,7 +35,7 @@ where } /// A reusable println! to serve as a visual break -pub fn horizontal_rule() { +pub fn print_horizontal_rule() { println!("-------------------------------------------"); }