diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index 78ba25306..56da7155c 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -11,12 +11,12 @@ use clap::{crate_version, parser::ValueSource, Arg, ArgAction, Command}; use remove_dir_all::remove_dir_all; use std::collections::VecDeque; use std::fs::{self, File, Metadata}; -use std::io::{stderr, stdin, BufRead, ErrorKind, Write}; +use std::io::ErrorKind; use std::ops::BitOr; use std::path::{Path, PathBuf}; use uucore::display::Quotable; use uucore::error::{UResult, USimpleError, UUsageError}; -use uucore::{format_usage, show_error}; +use uucore::{format_usage, prompt_yes, show_error}; use walkdir::{DirEntry, WalkDir}; #[derive(Eq, PartialEq, Clone, Copy)] @@ -133,11 +133,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { }; if options.interactive == InteractiveMode::Once && (options.recursive || files.len() > 3) { let msg = if options.recursive { - "Remove all arguments recursively? " + "Remove all arguments recursively?" } else { - "Remove all arguments? " + "Remove all arguments?" }; - if !prompt(msg) { + if !prompt_yes!("{}", msg) { return Ok(()); } } @@ -451,7 +451,7 @@ fn prompt_file(path: &Path, options: &Options, is_dir: bool) -> bool { if options.interactive == InteractiveMode::Always { if let Ok(metadata) = fs::symlink_metadata(path) { if metadata.is_symlink() { - return prompt(&(format!("remove symbolic link {}? ", path.quote()))); + return prompt_yes!("remove symbolic link {}?", path.quote()); } } } @@ -470,25 +470,18 @@ fn prompt_file(path: &Path, options: &Options, is_dir: bool) -> bool { if let Ok(metadata) = file.metadata() { if metadata.permissions().readonly() { if metadata.len() == 0 { - prompt( - &(format!( - "remove write-protected regular empty file {}? ", - path.quote() - )), + prompt_yes!( + "remove write-protected regular empty file {}?", + path.quote() ) } else { - prompt( - &(format!( - "remove write-protected regular file {}? ", - path.quote() - )), - ) + prompt_yes!("remove write-protected regular file {}?", path.quote()) } } else if options.interactive == InteractiveMode::Always { if metadata.len() == 0 { - prompt(&(format!("remove regular empty file {}? ", path.quote()))) + prompt_yes!("remove regular empty file {}?", path.quote()) } else { - prompt(&(format!("remove file {}? ", path.quote()))) + prompt_yes!("remove file {}?", path.quote()) } } else { true @@ -501,22 +494,15 @@ fn prompt_file(path: &Path, options: &Options, is_dir: bool) -> bool { if err.kind() == ErrorKind::PermissionDenied { if let Ok(metadata) = fs::metadata(path) { if metadata.len() == 0 { - prompt( - &(format!( - "remove write-protected regular empty file {}? ", - path.quote() - )), + prompt_yes!( + "remove write-protected regular empty file {}?", + path.quote() ) } else { - prompt( - &(format!( - "remove write-protected regular file {}? ", - path.quote() - )), - ) + prompt_yes!("remove write-protected regular file {}?", path.quote()) } } else { - prompt(&(format!("remove write-protected regular file {}? ", path.quote()))) + prompt_yes!("remove write-protected regular file {}?", path.quote()) } } else { true @@ -536,9 +522,9 @@ fn handle_writable_directory(path: &Path, options: &Options, metadata: &Metadata // Why is S_IWUSR showing up as a u16 on macos? let user_writable = (mode & (libc::S_IWUSR as u32)) != 0; if !user_writable { - prompt(&(format!("remove write-protected directory {}? ", path.quote()))) + prompt_yes!("remove write-protected directory {}?", path.quote()) } else if options.interactive == InteractiveMode::Always { - prompt(&(format!("remove directory {}? ", path.quote()))) + prompt_yes!("remove directory {}?", path.quote()) } else { true } @@ -551,9 +537,9 @@ fn handle_writable_directory(path: &Path, options: &Options, metadata: &Metadata use windows_sys::Win32::Storage::FileSystem::FILE_ATTRIBUTE_READONLY; let not_user_writable = (metadata.file_attributes() & FILE_ATTRIBUTE_READONLY) != 0; if not_user_writable { - prompt(&(format!("remove write-protected directory {}? ", path.quote()))) + prompt_yes!("remove write-protected directory {}?", path.quote()) } else if options.interactive == InteractiveMode::Always { - prompt(&(format!("remove directory {}? ", path.quote()))) + prompt_yes!("remove directory {}?", path.quote()) } else { true } @@ -564,14 +550,14 @@ fn handle_writable_directory(path: &Path, options: &Options, metadata: &Metadata #[cfg(not(unix))] fn handle_writable_directory(path: &Path, options: &Options, metadata: &Metadata) -> bool { if options.interactive == InteractiveMode::Always { - prompt(&(format!("remove directory {}? ", path.quote()))) + prompt_yes!("remove directory {}?", path.quote()) } else { true } } fn prompt_descend(path: &Path) -> bool { - prompt(&(format!("descend into directory {}? ", path.quote()))) + prompt_yes!("descend into directory {}?", path.quote()) } fn normalize(path: &Path) -> PathBuf { @@ -582,20 +568,6 @@ fn normalize(path: &Path) -> PathBuf { uucore::fs::normalize_path(path) } -fn prompt(msg: &str) -> bool { - let _ = stderr().write_all(format!("{}: {}", uucore::util_name(), msg).as_bytes()); - let _ = stderr().flush(); - - let mut buf = Vec::new(); - let stdin = stdin(); - let mut stdin = stdin.lock(); - let read = stdin.read_until(b'\n', &mut buf); - match read { - Ok(x) if x > 0 => matches!(buf[0], b'y' | b'Y'), - _ => false, - } -} - #[cfg(not(windows))] fn is_symlink_dir(_metadata: &Metadata) -> bool { false diff --git a/tests/by-util/test_rm.rs b/tests/by-util/test_rm.rs index 98273fedd..ee81cf8d9 100644 --- a/tests/by-util/test_rm.rs +++ b/tests/by-util/test_rm.rs @@ -460,24 +460,10 @@ fn test_rm_prompts() { let mut child: Child = scene.ucmd().arg("-ri").arg("a").run_no_wait(); let mut child_stdin = child.stdin.take().unwrap(); - child_stdin.write_all(yes.as_bytes()).unwrap(); - child_stdin.flush().unwrap(); - child_stdin.write_all(yes.as_bytes()).unwrap(); - child_stdin.flush().unwrap(); - child_stdin.write_all(yes.as_bytes()).unwrap(); - child_stdin.flush().unwrap(); - child_stdin.write_all(yes.as_bytes()).unwrap(); - child_stdin.flush().unwrap(); - child_stdin.write_all(yes.as_bytes()).unwrap(); - child_stdin.flush().unwrap(); - child_stdin.write_all(yes.as_bytes()).unwrap(); - child_stdin.flush().unwrap(); - child_stdin.write_all(yes.as_bytes()).unwrap(); - child_stdin.flush().unwrap(); - child_stdin.write_all(yes.as_bytes()).unwrap(); - child_stdin.flush().unwrap(); - child_stdin.write_all(yes.as_bytes()).unwrap(); - child_stdin.flush().unwrap(); + for _ in 0..9 { + child_stdin.write_all(yes.as_bytes()).unwrap(); + child_stdin.flush().unwrap(); + } let output = child.wait_with_output().unwrap(); @@ -494,10 +480,10 @@ fn test_rm_prompts() { trimmed_output.sort(); - assert!(trimmed_output.len() == answers.len()); + assert_eq!(trimmed_output.len(), answers.len()); for (i, checking_string) in trimmed_output.iter().enumerate() { - assert!(checking_string == answers[i]); + assert_eq!(checking_string, answers[i]); } assert!(!at.dir_exists("a")); @@ -530,7 +516,10 @@ fn test_rm_force_prompts_order() { let output = child.wait_with_output().unwrap(); let string_output = String::from_utf8(output.stderr).expect("Couldn't convert output.stderr to string"); - assert!(string_output.trim() == "rm: remove regular empty file 'empty'?"); + assert_eq!( + string_output.trim(), + "rm: remove regular empty file 'empty'?" + ); assert!(!at.file_exists(empty_file)); at.touch(empty_file);