use std::io::{IsTerminal, Write};
use std::process::{Command, Stdio};
pub fn die(message: &str) -> ! {
eprintln!("{}", message);
std::process::exit(1);
}
pub fn run_cmd(cmd: &[String], cwd: Option<&std::path::Path>, inherit: bool) -> std::process::ExitStatus {
let mut command = Command::new(&cmd[0]);
if cmd.len() > 1 {
command.args(&cmd[1..]);
}
if let Some(cwd) = cwd {
command.current_dir(cwd);
}
if inherit {
command.stdin(Stdio::inherit()).stdout(Stdio::inherit()).stderr(Stdio::inherit());
}
match command.status() {
Ok(status) => status,
Err(_) => {
die("failed to run command");
}
}
}
pub fn cmd_output(cmd: &[String]) -> Option<String> {
let mut command = Command::new(&cmd[0]);
if cmd.len() > 1 {
command.args(&cmd[1..]);
}
match command.output() {
Ok(out) if out.status.success() => Some(String::from_utf8_lossy(&out.stdout).trim().to_string()),
_ => None,
}
}
pub fn shell_escape(arg: &str) -> String {
if arg.chars().all(|c| c.is_ascii_alphanumeric() || "-._/".contains(c)) {
return arg.to_string();
}
let escaped = arg.replace('\'', "'\\''");
format!("'{}'", escaped)
}
pub fn print_json(value: &serde_json::Value) {
let _ = std::io::stdout().write_all(serde_json::to_string_pretty(value).unwrap().as_bytes());
let _ = std::io::stdout().write_all(b"\n");
}
pub fn confirm_apply() -> bool {
if !std::io::stdin().is_terminal() {
return false;
}
eprint!("Apply patch? [y/N] ");
let _ = std::io::stdout().flush();
let mut input = String::new();
if std::io::stdin().read_line(&mut input).is_ok() {
let s = input.trim().to_lowercase();
return s == "y" || s == "yes";
}
false
}