use crate::config::loader;
use crate::crypto::decrypt_variables;
use crate::process::executor::CommandExecutor;
use anyhow::{anyhow, Result};
use std::io::{self, IsTerminal, Write};
use std::path::Path;
fn is_interactive_terminal() -> bool {
if std::env::var("STAND_FORCE_NON_TTY").is_ok() {
return false;
}
io::stdin().is_terminal()
}
fn prompt_confirmation(env_name: &str) -> Result<bool> {
print!(
"Environment '{}' requires confirmation.\nAre you sure you want to proceed? [y/N]: ",
env_name
);
io::stdout().flush()?;
let mut input = String::new();
io::stdin().read_line(&mut input)?;
let response = input.trim().to_lowercase();
Ok(response == "y" || response == "yes")
}
pub fn execute_with_environment(
project_path: &Path,
env_name: &str,
command: Vec<String>,
skip_confirmation: bool,
) -> Result<i32> {
let config = loader::load_config_toml_with_inheritance(project_path)?;
let env = config.environments.get(env_name).ok_or_else(|| {
let mut available: Vec<_> = config.environments.keys().cloned().collect();
available.sort();
anyhow!(
"Environment '{}' not found. Available: {}",
env_name,
available.join(", ")
)
})?;
if env.requires_confirmation.unwrap_or(false) && !skip_confirmation {
if !is_interactive_terminal() {
return Err(anyhow!(
"Environment '{}' requires confirmation but stdin is not a terminal.\n\
Use -y or --yes to skip confirmation in non-interactive environments.",
env_name
));
}
if !prompt_confirmation(env_name)? {
return Err(anyhow!(
"Execution cancelled. Use -y or --yes to skip confirmation."
));
}
}
if command.is_empty() {
return Err(anyhow!("Command cannot be empty"));
}
let program = command[0].clone();
let args = command[1..].to_vec();
let decrypted_vars = decrypt_variables(env.variables.clone(), project_path)
.map_err(|e| anyhow!("Failed to decrypt variables: {}", e))?;
let executor = CommandExecutor::new(program, args).with_env(decrypted_vars);
executor.execute()
}