Added wildcard support to be able to perform loops
This commit is contained in:
parent
3dec6b952a
commit
9445dafdf8
1 changed files with 190 additions and 24 deletions
214
src/bin/toke.rs
214
src/bin/toke.rs
|
@ -114,8 +114,32 @@ fn main() {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the target command
|
//Run deps
|
||||||
run_command(&parsed_toml, target.to_string());
|
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) {
|
fn detect_cycle(parsed_toml: &toml::Value) {
|
||||||
let mut visited_targets = HashSet::new();
|
let mut visited_targets = HashSet::new();
|
||||||
|
@ -182,7 +206,7 @@ fn replace_variables(parsed_toml: &mut toml::Value, cli_vars: HashMap<String, St
|
||||||
};
|
};
|
||||||
|
|
||||||
// Iterate over each target
|
// Iterate over each target
|
||||||
for (_, target_value) in targets.iter_mut() {
|
for (target_name, target_value) in targets.iter_mut() {
|
||||||
if let Some(target_table) = target_value.as_table_mut() {
|
if let Some(target_table) = target_value.as_table_mut() {
|
||||||
// Parse local variables for the target
|
// Parse local variables for the target
|
||||||
let map = toml::value::Table::new();
|
let map = toml::value::Table::new();
|
||||||
|
@ -199,6 +223,51 @@ fn replace_variables(parsed_toml: &mut toml::Value, cli_vars: HashMap<String, St
|
||||||
merged_vars.insert(key.clone(), toml::Value::String(value.clone()));
|
merged_vars.insert(key.clone(), toml::Value::String(value.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Replace variables in the target's wildcards value
|
||||||
|
if let Some(wildcards_value) = target_table.get_mut("wildcards") {
|
||||||
|
if let Some(wildcards_array) = wildcards_value.as_array_mut() {
|
||||||
|
for wildcard in wildcards_array {
|
||||||
|
//Check if the value is a string
|
||||||
|
//If it is, then it must be a command, so we need to check if it starts with the designated prefix
|
||||||
|
if let Some(wildcards_str) = wildcard.as_str() {
|
||||||
|
if let Some(stripped_command) = wildcards_str.strip_prefix('!') {
|
||||||
|
let replaced_command =
|
||||||
|
replace_variables_in_cmd(stripped_command, &merged_vars);
|
||||||
|
// Execute shell command and capture its output
|
||||||
|
let output = Command::new("sh")
|
||||||
|
.arg("-c")
|
||||||
|
.arg(replaced_command)
|
||||||
|
.output()
|
||||||
|
.expect("Failed to execute shell command");
|
||||||
|
// Use the command output as the variable value
|
||||||
|
*wildcard = toml::Value::Array(
|
||||||
|
String::from_utf8_lossy(&output.stdout)
|
||||||
|
.trim()
|
||||||
|
.split('\n')
|
||||||
|
.map(|w| toml::Value::String(w.to_string()))
|
||||||
|
.collect::<Vec<toml::Value>>(),
|
||||||
|
);
|
||||||
|
} 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
|
// Replace variables in the target's cmd value
|
||||||
if let Some(cmd_value) = target_table.get_mut("cmd") {
|
if let Some(cmd_value) = target_table.get_mut("cmd") {
|
||||||
if let Some(cmd_str) = cmd_value.as_str() {
|
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) {
|
for capture in re.captures_iter(cmd) {
|
||||||
if let Some(var_name) = capture.get(1).map(|m| m.as_str()) {
|
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()) {
|
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
|
replaced_cmd
|
||||||
}
|
}
|
||||||
|
fn wildcard_iterations(parsed_toml: &toml::Value, target: String) -> Vec<String> {
|
||||||
|
// 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
|
if let Some(targets) = parsed_toml
|
||||||
.get("targets")
|
.get("targets")
|
||||||
.and_then(|targets| targets.as_table())
|
.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() {
|
if let Some(dep_array) = dep_value.as_array() {
|
||||||
for dep in dep_array {
|
for dep in dep_array {
|
||||||
if let Some(dep_str) = dep.as_str() {
|
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()
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue