diff --git a/src/bin/toke.rs b/src/bin/toke.rs index 2df93fd..1029e9b 100644 --- a/src/bin/toke.rs +++ b/src/bin/toke.rs @@ -114,8 +114,32 @@ fn main() { exit(1); } - // Execute the target command - run_command(&parsed_toml, target.to_string()); + //Run deps + run_deps(&parsed_toml, target.to_string()); + + if parsed_toml + .get("targets") + .and_then(|targets| targets.get(target)) + .and_then(|target| target.as_table()) + .and_then(|target| target.get("wildcards")) + .is_some() + { + let command_list = wildcard_iterations(&parsed_toml, target.to_string()); + for cmd in command_list { + run_command(&cmd); + } + exit(0); + } else { + run_command( + parsed_toml + .get("targets") + .and_then(|targets| targets.get(target)) + .and_then(|target| target.as_table()) + .and_then(|target| target.get("cmd")) + .and_then(|cmd| cmd.as_str()) + .unwrap_or(""), + ); + } } fn detect_cycle(parsed_toml: &toml::Value) { let mut visited_targets = HashSet::new(); @@ -182,7 +206,7 @@ fn replace_variables(parsed_toml: &mut toml::Value, cli_vars: HashMap>(), + ); + } else { + eprintln!("Invalid wildcard format on target {} : {} , it must either be a command (string starting with !) or an array", target_name,wildcards_str); + } + } else if let Some(wildcards_array) = wildcard.as_array_mut() { + for wildcard in wildcards_array { + if let Some(wildcard_str) = wildcard.as_str() { + if wildcard_str.starts_with('!') { + eprintln!("Invalid wildcard format on target {} : {} , it must either be a command (string starting with !) or an array", target_name,wildcard_str); + } else { + *wildcard = toml::Value::String(replace_variables_in_cmd( + wildcard_str, + &merged_vars, + )); + } + } + } + } + } + } + } + // Replace variables in the target's cmd value if let Some(cmd_value) = target_table.get_mut("cmd") { if let Some(cmd_str) = cmd_value.as_str() { @@ -230,15 +299,111 @@ fn replace_variables_in_cmd(cmd: &str, vars: &toml::value::Table) -> String { for capture in re.captures_iter(cmd) { if let Some(var_name) = capture.get(1).map(|m| m.as_str()) { if let Some(var_value) = vars.get(var_name).and_then(|v| v.as_str()) { - replaced_cmd = replaced_cmd.replace(&format!("${{{}}}", var_name), var_value); + // Check if the value starts with the designated prefix + if let Some(stripped_command) = var_value.strip_prefix('!') { + // Execute shell command and capture its output + let output = Command::new("sh") + .arg("-c") + .arg(stripped_command) + .output() + .expect("Failed to execute shell command"); + // Use the command output as the variable value + replaced_cmd = replaced_cmd.replace( + &format!("${{{}}}", var_name), + String::from_utf8_lossy(&output.stdout).trim(), + ); + } else { + // Replace variable with its value + replaced_cmd = replaced_cmd.replace(&format!("${{{}}}", var_name), var_value); + } } } } replaced_cmd } +fn wildcard_iterations(parsed_toml: &toml::Value, target: String) -> Vec { + // We want to loop over the target's wildcards and crate a list of all the combinations + let empty_table = toml::value::Table::new(); + let targets = parsed_toml + .get("targets") + .and_then(|targets| targets.as_table()) + .unwrap_or(&empty_table); + //Get the number of wildcards in the cmd value + //A wildcard in cmd is represented by @@, so we want to count the number of times it appears + let re = Regex::new(r#"@{2}"#).unwrap(); + let cmd = targets + .get(&target) + .and_then(|target| target.as_table()) + .and_then(|target| target.get("cmd")) + .and_then(|cmd| cmd.as_str()) + .unwrap_or(""); -fn run_command(parsed_toml: &toml::Value, target: String) { + let wildcard_count = re.find_iter(cmd).count(); + //Check if the wildcard count is different that the number of wildcards in the wildcards value + //If it is, then we have an invalid tokefile + if let Some(target_table) = targets.get(&target) { + if let Some(wildcards_value) = target_table.get("wildcards") { + if let Some(wildcards_array) = wildcards_value.as_array() { + if wildcard_count != wildcards_array.len() { + eprintln!("Invalid tokefile, the number of wildcards in the cmd value must be the same as the number of wildcards in the wildcards value"); + exit(1); + } + } + } + }; + + //Check if each wildcard has the same number of elements/iterations + let num_of_iters = match targets.get(&target) { + Some(target_table) => match target_table.get("wildcards") { + Some(wildcards_value) => match wildcards_value.as_array() { + Some(wildcards_array) => { + let first_length = wildcards_array[0].as_array().unwrap().len(); + let all_same_length = wildcards_array + .iter() + .all(|wildcard| wildcard.as_array().unwrap().len() == first_length); + if !all_same_length { + eprintln!("Invalid tokefile, all wildcards must have the same number of elements/iterations"); + exit(1); + } else { + first_length + } + } + _ => 0, + }, + _ => 0, + }, + _ => 0, + }; + + //Create a list of cmds where each index is a combination of the wildcards at that index + let mut command_list = Vec::new(); + for i in 0..num_of_iters { + let mut cmd = cmd.to_string(); + let wildcards = match targets + .get(&target) + .and_then(|target| target.as_table()) + .and_then(|target| target.get("wildcards")) + .and_then(|wildcards| wildcards.as_array()) + { + Some(wildcards) => wildcards, + _ => { + //Return an empty vector if the wildcards value is not an array + return Vec::new(); + } + }; + for wildcard in wildcards { + if let Some(wildcard_array) = wildcard.as_array() { + //Apple regex to replace the first instance of @@ with the value of the wildcard at index i + cmd = cmd.replacen("@@", wildcard_array[i].as_str().unwrap(), 1); + } + } + command_list.push(cmd); + } + command_list +} + +fn run_deps(parsed_toml: &toml::Value, target: String) { if let Some(targets) = parsed_toml .get("targets") .and_then(|targets| targets.as_table()) @@ -248,29 +413,30 @@ fn run_command(parsed_toml: &toml::Value, target: String) { if let Some(dep_array) = dep_value.as_array() { for dep in dep_array { if let Some(dep_str) = dep.as_str() { - run_command(parsed_toml, dep_str.to_string()); + run_deps(parsed_toml, dep_str.to_string()); } } } } - if let Some(cmd_value) = target_table.get("cmd") { - if let Some(cmd_str) = cmd_value.as_str() { - eprintln!("{}", cmd_str); - let status = Command::new("sh") - .arg("-c") - .arg(cmd_str) - .status() - .expect("Failed to execute command"); - if !status.success() { - eprintln!( - "Command '{}' failed with exit code {:?}", - cmd_str, - status.code() - ); - exit(1); - } - } - } } } } + +fn run_command(cmd: &str) -> String { + eprintln!("{}", cmd); + let mut binding = Command::new("sh"); + let command = binding.arg("-c").arg(cmd); + + let status = command.status().expect("Failed to execute command"); + if !status.success() { + eprintln!( + "Command '{}' failed with exit code {:?}", + cmd, + status.code() + ); + exit(1); + } + + let output = command.output().expect("Failed to execute command"); + String::from_utf8_lossy(&output.stdout).to_string() +}