use clap::ArgMatches;
use inquire::Confirm;
use crate::configs::app::AppConfig;
use crate::engine::engine::Engine;
use crate::models::context::ContextModel;
use crate::output::format::FormatOutput;
use crate::output::output::OutputKind;
use crate::output::output::OutputType;
use crate::print_template;
use crate::print_text;
use crate::utils;
pub async fn execute(name: &str, action_matches: &ArgMatches, config: &AppConfig) {
let is_output_cli = AppConfig::output().output_type() == OutputType::Cli;
let is_output_json = AppConfig::output().output_type() == OutputType::Json;
let start_time = std::time::Instant::now();
let mut flow = config
.find_flow(name)
.unwrap_or_else(|e| {
print_text!(OutputKind::Error, "{}", e);
std::process::exit(1);
})
.apply_system_tags()
.unwrap_or_else(|e| {
print_text!(OutputKind::Error, "{}", e);
std::process::exit(1);
})
.apply_args(action_matches)
.unwrap_or_else(|e| {
print_text!(OutputKind::Error, "{}", e);
std::process::exit(1);
});
if !is_output_json && flow.needs_prompt() {
let is_query_empty = match flow.input_tags.get("query") {
Some(ContextModel::String(s)) if !s.is_empty() => false,
_ => true,
};
if is_query_empty {
let ans = inquire::Text::new("Query").prompt();
match ans {
Ok(text) => {
flow.input_tags
.insert("query".to_string(), ContextModel::String(text));
}
Err(_) => return,
}
}
}
let flow = flow.apply_query_tags().unwrap_or_else(|e| {
print_text!(OutputKind::Error, "{}", e);
std::process::exit(1);
});
let mut engine = Engine::new(&config.action.system, config.action.retries, &flow)
.unwrap_or_else(|e| {
print_text!(OutputKind::Error, "{}", e);
std::process::exit(1);
});
let actions = engine.actions().to_vec();
let total = actions.len();
print_template!(
OutputKind::Info,
"Found action '{name}' ({steps} steps), starting...",
"name" => flow.name,
"steps" => total
);
if config.check_role_mismatch(&flow) {
let ans = Confirm::new("Continue with available nodes?")
.with_placeholder("\nFlow has actions with roles not found in cluster. All available nodes will be used.")
.with_default(false)
.prompt();
match ans {
Ok(true) => {}
Ok(false) => return,
Err(_) => return,
}
}
print_text!(OutputKind::Debug, "Flow: {} ({} steps)", flow.name, total);
for (i, action) in actions.iter().enumerate() {
print_template!(
OutputKind::Debug,
"[{current}/{total}] Running: {tag}",
"current" => (i + 1).to_string(),
"total" => total.to_string(),
"tag" => action.tag
);
if !engine.check_when(action).unwrap_or_else(|e| {
print_text!(OutputKind::Error, "{}", e);
std::process::exit(1);
}) {
print_template!(
OutputKind::Progress,
"[{current}/{total}] Skipped: {tag} (condition false)",
"current" => (i + 1).to_string(),
"total" => total.to_string(),
"tag" => action.tag
);
continue;
}
print_template!(
OutputKind::Progress,
"{tag} ({run})... {percent}% ({current}/{total})",
"tag" => action.tag,
"run" => action.run.to_string(),
"percent" => format!("{:.0}", ((i + 1) as f32 / total as f32) * 100.0),
"current" => (i + 1).to_string(),
"total" => total.to_string()
);
if !is_output_json && action.confirm {
print_template!(
OutputKind::Info,
"completed in {duration}",
"duration" => utils::format::format_duration(start_time.elapsed())
);
let query = format!("Execute '{}'?", FormatOutput::format_msg(&action.tag));
let resolve = engine.action_display(&action).unwrap_or_else(|e| {
print_text!(OutputKind::Error, "{}", e);
std::process::exit(1);
});
let ans = Confirm::new(&query)
.with_default(false)
.with_placeholder(&format!("\n{}", resolve))
.prompt();
match ans {
Ok(true) => {
engine.exec_action(action).await.unwrap_or_else(|e| {
print_text!(OutputKind::Error, "{}", e);
std::process::exit(1);
});
}
Ok(false) => return,
Err(_) => return,
}
} else {
engine.exec_action(action).await.unwrap_or_else(|e| {
print_text!(OutputKind::Error, "{}", e);
std::process::exit(1);
});
}
}
print_template!(
OutputKind::Debug,
"Flow completed: {name}",
"name" => flow.name
);
let result = engine.result().unwrap_or_else(|e| {
print_text!(OutputKind::Error, "{}", e);
std::process::exit(1);
});
print_template!(
OutputKind::Info,
"completed in {duration}",
"duration" => utils::format::format_duration(start_time.elapsed())
);
print_template!(
ExportContext::Success,
OutputKind::Success,
"{message}",
"message" => if result.is_empty() && is_output_cli { "No matches found." } else { &result },
);
if flow.notify && is_output_cli {
#[cfg(target_os = "macos")]
{
match std::process::Command::new("terminal-notifier")
.args(&[
"-title",
utils::app::app_name_pretty(),
"-message",
&format!(
"{} completed in {}",
flow.name,
utils::format::format_duration(start_time.elapsed())
),
])
.spawn()
{
Ok(_) => {}
Err(_) => {
print_text!(
OutputKind::Warning,
"terminal-notifier not found. Install: brew install terminal-notifier"
);
}
}
}
#[cfg(target_os = "linux")]
{
let _ = notify_rust::Notification::new()
.summary(utils::app::app_name_pretty())
.body(&format!(
"{} completed in {}",
flow.name,
utils::format::format_duration(start_time.elapsed())
))
.show();
}
}
}