use std::io::{self, IsTerminal, Write};
use anyhow::{Result, bail};
pub fn is_affirmative(s: &str) -> bool {
s.eq_ignore_ascii_case("y") || s.eq_ignore_ascii_case("yes")
}
pub fn should_refuse_noninteractive(is_tty: bool, assume_yes: bool) -> bool {
!is_tty && !assume_yes
}
pub fn confirm_or_refuse(prompt: &str, assume_yes: bool) -> Result<bool> {
if assume_yes {
return Ok(true);
}
if should_refuse_noninteractive(io::stdin().is_terminal(), assume_yes) {
bail!(
"Refusing to proceed without confirmation in a non-interactive session. \
Re-run in an interactive terminal, or pass --force/--yes to allow it."
);
}
print!("{prompt} [y/N]: ");
io::stdout().flush()?;
let mut input = String::new();
io::stdin().read_line(&mut input)?;
Ok(is_affirmative(input.trim()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn affirmative_accepts_only_y_yes() {
assert!(is_affirmative("y"));
assert!(is_affirmative("Y"));
assert!(is_affirmative("yes"));
assert!(is_affirmative("YES"));
assert!(!is_affirmative("n"));
assert!(!is_affirmative(""));
assert!(!is_affirmative("sure"));
}
#[test]
fn refuses_noninteractive_without_optin() {
assert!(should_refuse_noninteractive(false, false));
assert!(!should_refuse_noninteractive(false, true));
assert!(!should_refuse_noninteractive(true, false));
}
#[test]
fn confirm_returns_true_immediately_when_assume_yes() {
assert!(confirm_or_refuse("do the thing?", true).expect("assume_yes is infallible"));
}
}