1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

Merge pull request #2221 from jfinkels/head-display-multiple-errors-2

head: display errors for each input file instead of terminating at the first error
This commit is contained in:
Sylvestre Ledru 2021-05-20 23:24:35 +02:00 committed by GitHub
commit efb781f59a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 52 additions and 40 deletions

View file

@ -2,7 +2,7 @@ use clap::{App, Arg};
use std::convert::TryFrom; use std::convert::TryFrom;
use std::ffi::OsString; use std::ffi::OsString;
use std::io::{self, ErrorKind, Read, Seek, SeekFrom, Write}; use std::io::{self, ErrorKind, Read, Seek, SeekFrom, Write};
use uucore::{crash, executable, show_error}; use uucore::{crash, executable, show_error, show_error_custom_description};
const EXIT_FAILURE: i32 = 1; const EXIT_FAILURE: i32 = 1;
const EXIT_SUCCESS: i32 = 0; const EXIT_SUCCESS: i32 = 0;
@ -400,7 +400,8 @@ fn head_file(input: &mut std::fs::File, options: &HeadOptions) -> std::io::Resul
} }
} }
fn uu_head(options: &HeadOptions) { fn uu_head(options: &HeadOptions) -> Result<(), u32> {
let mut error_count = 0;
let mut first = true; let mut first = true;
for fname in &options.files { for fname in &options.files {
let res = match fname.as_str() { let res = match fname.as_str() {
@ -433,30 +434,22 @@ fn uu_head(options: &HeadOptions) {
name => { name => {
let mut file = match std::fs::File::open(name) { let mut file = match std::fs::File::open(name) {
Ok(f) => f, Ok(f) => f,
Err(err) => match err.kind() { Err(err) => {
ErrorKind::NotFound => { let prefix = format!("cannot open '{}' for reading", name);
crash!( match err.kind() {
EXIT_FAILURE, ErrorKind::NotFound => {
"head: cannot open '{}' for reading: No such file or directory", show_error_custom_description!(prefix, "No such file or directory");
name }
); ErrorKind::PermissionDenied => {
show_error_custom_description!(prefix, "Permission denied");
}
_ => {
show_error_custom_description!(prefix, "{}", err);
}
} }
ErrorKind::PermissionDenied => { error_count += 1;
crash!( continue;
EXIT_FAILURE, }
"head: cannot open '{}' for reading: Permission denied",
name
);
}
_ => {
crash!(
EXIT_FAILURE,
"head: cannot open '{}' for reading: {}",
name,
err
);
}
},
}; };
if (options.files.len() > 1 && !options.quiet) || options.verbose { if (options.files.len() > 1 && !options.quiet) || options.verbose {
if !first { if !first {
@ -468,21 +461,22 @@ fn uu_head(options: &HeadOptions) {
} }
}; };
if res.is_err() { if res.is_err() {
if fname.as_str() == "-" { let name = if fname.as_str() == "-" {
crash!( "standard input"
EXIT_FAILURE,
"head: error reading standard input: Input/output error"
);
} else { } else {
crash!( fname
EXIT_FAILURE, };
"head: error reading {}: Input/output error", let prefix = format!("error reading {}", name);
fname show_error_custom_description!(prefix, "Input/output error");
); error_count += 1;
}
} }
first = false; first = false;
} }
if error_count > 0 {
Err(error_count)
} else {
Ok(())
}
} }
pub fn uumain(args: impl uucore::Args) -> i32 { pub fn uumain(args: impl uucore::Args) -> i32 {
@ -492,9 +486,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
crash!(EXIT_FAILURE, "head: {}", s); crash!(EXIT_FAILURE, "head: {}", s);
} }
}; };
uu_head(&args); match uu_head(&args) {
Ok(_) => EXIT_SUCCESS,
EXIT_SUCCESS Err(_) => EXIT_FAILURE,
}
} }
#[cfg(test)] #[cfg(test)]

View file

@ -162,6 +162,18 @@ fn test_no_such_file_or_directory() {
.stderr_contains("cannot open 'no_such_file.toml' for reading: No such file or directory"); .stderr_contains("cannot open 'no_such_file.toml' for reading: No such file or directory");
} }
/// Test that each non-existent files gets its own error message printed.
#[test]
fn test_multiple_nonexistent_files() {
new_ucmd!()
.args(&["bogusfile1", "bogusfile2"])
.fails()
.stdout_does_not_contain("==> bogusfile1 <==")
.stderr_contains("cannot open 'bogusfile1' for reading: No such file or directory")
.stdout_does_not_contain("==> bogusfile2 <==")
.stderr_contains("cannot open 'bogusfile2' for reading: No such file or directory");
}
// there was a bug not caught by previous tests // there was a bug not caught by previous tests
// where for negative n > 3, the total amount of lines // where for negative n > 3, the total amount of lines
// was correct, but it would eat from the second line // was correct, but it would eat from the second line

View file

@ -315,7 +315,12 @@ impl CmdResult {
} }
pub fn stdout_does_not_contain<T: AsRef<str>>(&self, cmp: T) -> &CmdResult { pub fn stdout_does_not_contain<T: AsRef<str>>(&self, cmp: T) -> &CmdResult {
assert!(!self.stdout_str().contains(cmp.as_ref())); assert!(
!self.stdout_str().contains(cmp.as_ref()),
"'{}' contains '{}' but should not",
self.stdout_str(),
cmp.as_ref(),
);
self self
} }