use anyhow::Result;
use std::path::Path;
use crate::executor::ParallelExecutor;
use crate::node::Node;
use crate::ssh::known_hosts::StrictHostKeyChecking;
use crate::ui::OutputFormatter;
use crate::utils::output::save_outputs_to_files;
pub struct ExecuteCommandParams<'a> {
pub nodes: Vec<Node>,
pub command: &'a str,
pub max_parallel: usize,
pub key_path: Option<&'a Path>,
pub verbose: bool,
pub strict_mode: StrictHostKeyChecking,
pub use_agent: bool,
pub use_password: bool,
pub output_dir: Option<&'a Path>,
pub timeout: Option<u64>,
pub jump_hosts: Option<&'a str>,
}
pub async fn execute_command(params: ExecuteCommandParams<'_>) -> Result<()> {
println!(
"{}",
OutputFormatter::format_command_header(params.command, params.nodes.len())
);
let key_path = params.key_path.map(|p| p.to_string_lossy().to_string());
let executor = ParallelExecutor::new_with_all_options(
params.nodes,
params.max_parallel,
key_path,
params.strict_mode,
params.use_agent,
params.use_password,
)
.with_timeout(params.timeout)
.with_jump_hosts(params.jump_hosts.map(|s| s.to_string()));
let results = executor.execute(params.command).await?;
if let Some(dir) = params.output_dir {
save_outputs_to_files(&results, dir, params.command).await?;
}
for result in &results {
result.print_output(params.verbose);
}
let success_count = results.iter().filter(|r| r.is_success()).count();
let failed_count = results.len() - success_count;
println!(
"{}",
OutputFormatter::format_summary(results.len(), success_count, failed_count)
);
if failed_count > 0 {
std::process::exit(1);
}
Ok(())
}