pub mod file_io; pub mod moose; use anyhow::Result; /** * A module to enable us to use the agent-cli as a means to interact with the user's * local terminal based programs. */ use std::process::Command; use crate::question_and_answers::Question; use crate::survey::utils::AppSpinner; /// Executes a shell command and returns the output as a Result string /// /// If the command fails, the error is returned as a Result string pub fn execute_command(command: &str, args: Option<&[&str]>) -> Result { let shell = std::env::var("SHELL").unwrap_or_else(|_| "sh".to_string()); let full_command = match args { Some(args) => { let quoted_args: Vec = args .iter() .map(|&arg| { if arg.contains(' ') || arg.contains('*') { format!("\"{}\"", arg) } else { arg.to_string() } }) .collect(); format!("{} {}", command, quoted_args.join(" ")) } None => command.to_string(), }; // Confirm that the user wants to run the command Question::confirm(&format!("Run command: {}", full_command)) .with_confirm_default(true) .with_help(&format!( "Double check that this is indeed what you want to run. Running arbitrary commands can result in unexpected behavior.", )) .get_answer()?; let mut spinner = AppSpinner::new(&format!("Running command: {}", &full_command)); let output = Command::new(shell).arg("-c").arg(&full_command).output()?; if output.status.success() { spinner.stop_with_success_message(&format!("Successfully ran command: {}", full_command)); Ok(String::from_utf8_lossy(&output.stdout).to_string()) } else { spinner.stop_with_error_message("Command failed!"); Err(anyhow::anyhow!(format!( "Command {} failed | stdout: {}, stderr: {}", // Combine command and args. Make sure to include quotes around the args if they are present if let Some(args) = args { format!("{} {}", command, args.join(" ")) } else { command.to_string() }, String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr) ))) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_execute_valid_command() { let result = execute_command("echo", Some(&["hello"])); assert!(result.is_ok()); assert_eq!(result.unwrap().trim(), "hello"); } #[test] fn test_execute_invalid_command() { let result = execute_command("nonexistentcommand", None); assert!(result.is_err()); } #[test] fn test_execute_command_with_args() { let result = execute_command("ls", Some(&["~"])); println!("Result: {:?}", result); assert!(result.is_ok()); assert!(result.unwrap().contains("Documents")); } }