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

install: Use show! macro for noncritical errors during execution

Drop the previous flags that would tell whether a noncritical error occured
during execution in favor of the `show!` macro from the error submodule.

This allows us to generate regular error types during execution to signify
failures inside the program, but without prematurely aborting program execution
if not needed or specified.

Also make verbose outputs use `print!` and friends instead of `show_error!` to
ensure verbose output is redirected to stdout, not stderr.
This commit is contained in:
Andreas Hartmann 2021-07-14 08:39:12 +02:00
parent 2b18e45ece
commit 0461a45c9a

View file

@ -63,7 +63,7 @@ enum InstallError {
MetadataFailed(std::io::Error), MetadataFailed(std::io::Error),
NoSuchUser(String), NoSuchUser(String),
NoSuchGroup(String), NoSuchGroup(String),
SilentError(), OmittingDirectory(PathBuf),
} }
impl UCustomError for InstallError { impl UCustomError for InstallError {
@ -119,7 +119,7 @@ impl Display for InstallError {
IE::MetadataFailed(e) => write!(f, "{}", e.to_string()), IE::MetadataFailed(e) => write!(f, "{}", e.to_string()),
IE::NoSuchUser(user) => write!(f, "no such user: {}", user), IE::NoSuchUser(user) => write!(f, "no such user: {}", user),
IE::NoSuchGroup(group) => write!(f, "no such group: {}", group), IE::NoSuchGroup(group) => write!(f, "no such group: {}", group),
IE::SilentError() => write!(f, ""), IE::OmittingDirectory(dir) => write!(f, "omitting directory '{}'", dir.display()),
} }
} }
} }
@ -416,44 +416,46 @@ fn behavior(matches: &ArgMatches) -> UResult<Behavior> {
/// GNU man pages describe this functionality as creating 'all components of /// GNU man pages describe this functionality as creating 'all components of
/// the specified directories'. /// the specified directories'.
/// ///
/// Returns an integer intended as a program return code. /// Returns a Result type with the Err variant containing the error message.
/// ///
fn directory(paths: Vec<String>, b: Behavior) -> UResult<()> { fn directory(paths: Vec<String>, b: Behavior) -> UResult<()> {
if paths.is_empty() { if paths.is_empty() {
Err(InstallError::DirNeedsArg().into()) Err(InstallError::DirNeedsArg().into())
} else { } else {
let mut all_successful = true;
for path in paths.iter().map(Path::new) { for path in paths.iter().map(Path::new) {
// if the path already exist, don't try to create it again // if the path already exist, don't try to create it again
if !path.exists() { if !path.exists() {
// Differently than the primary functionality (MainFunction::Standard), the directory // Differently than the primary functionality
// functionality should create all ancestors (or components) of a directory regardless // (MainFunction::Standard), the directory functionality should
// of the presence of the "-D" flag. // create all ancestors (or components) of a directory
// NOTE: the GNU "install" sets the expected mode only for the target directory. All // regardless of the presence of the "-D" flag.
// created ancestor directories will have the default mode. Hence it is safe to use //
// fs::create_dir_all and then only modify the target's dir mode. // NOTE: the GNU "install" sets the expected mode only for the
if let Err(e) = fs::create_dir_all(path) { // target directory. All created ancestor directories will have
show_error!("{}: {}", path.display(), e); // the default mode. Hence it is safe to use fs::create_dir_all
all_successful = false; // and then only modify the target's dir mode.
if let Err(e) =
fs::create_dir_all(path).map_err_context(|| format!("{}", path.display()))
{
show!(e);
continue; continue;
} }
if b.verbose { if b.verbose {
show_error!("creating directory '{}'", path.display()); println!("creating directory '{}'", path.display());
} }
} }
if mode::chmod(path, b.mode()).is_err() { if mode::chmod(path, b.mode()).is_err() {
all_successful = false; // Error messages are printed by the mode::chmod function!
uucore::error::set_exit_code(1);
continue; continue;
} }
} }
if all_successful { // If the exit code was set, or show! has been called at least once
Ok(()) // (which sets the exit code as well), function execution will end after
} else { // this return.
Err(InstallError::SilentError().into()) Ok(())
}
} }
} }
@ -467,7 +469,7 @@ fn is_new_file_path(path: &Path) -> bool {
/// Perform an install, given a list of paths and behavior. /// Perform an install, given a list of paths and behavior.
/// ///
/// Returns an integer intended as a program return code. /// Returns a Result type with the Err variant containing the error message.
/// ///
fn standard(mut paths: Vec<String>, b: Behavior) -> UResult<()> { fn standard(mut paths: Vec<String>, b: Behavior) -> UResult<()> {
let target: PathBuf = b let target: PathBuf = b
@ -504,7 +506,7 @@ fn standard(mut paths: Vec<String>, b: Behavior) -> UResult<()> {
/// Copy some files into a directory. /// Copy some files into a directory.
/// ///
/// Prints verbose information and error messages. /// Prints verbose information and error messages.
/// Returns an integer intended as a program return code. /// Returns a Result type with the Err variant containing the error message.
/// ///
/// # Parameters /// # Parameters
/// ///
@ -515,22 +517,19 @@ fn copy_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> UR
if !target_dir.is_dir() { if !target_dir.is_dir() {
return Err(InstallError::TargetDirIsntDir(target_dir.to_path_buf()).into()); return Err(InstallError::TargetDirIsntDir(target_dir.to_path_buf()).into());
} }
let mut all_successful = true;
for sourcepath in files.iter() { for sourcepath in files.iter() {
if !sourcepath.exists() { if !sourcepath.exists() {
show_error!( let err = UIoError::new(
"cannot stat '{}': No such file or directory", std::io::ErrorKind::NotFound,
sourcepath.display() format!("cannot stat '{}'", sourcepath.display()),
); );
show!(err);
all_successful = false;
continue; continue;
} }
if sourcepath.is_dir() { if sourcepath.is_dir() {
show_error!("omitting directory '{}'", sourcepath.display()); let err = InstallError::OmittingDirectory(sourcepath.to_path_buf());
all_successful = false; show!(err);
continue; continue;
} }
@ -538,21 +537,20 @@ fn copy_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> UR
let filename = sourcepath.components().last().unwrap(); let filename = sourcepath.components().last().unwrap();
targetpath.push(filename); targetpath.push(filename);
if copy(sourcepath, &targetpath, b).is_err() { if let Err(e) = copy(sourcepath, &targetpath, b) {
all_successful = false; show!(e);
} }
} }
if all_successful { // If the exit code was set, or show! has been called at least once
Ok(()) // (which sets the exit code as well), function execution will end after
} else { // this return.
Err(InstallError::SilentError().into()) Ok(())
}
} }
/// Copy a file to another file. /// Copy a file to another file.
/// ///
/// Prints verbose information and error messages. /// Prints verbose information and error messages.
/// Returns an integer intended as a program return code. /// Returns a Result type with the Err variant containing the error message.
/// ///
/// # Parameters /// # Parameters
/// ///
@ -565,6 +563,8 @@ fn copy_file_to_file(file: &Path, target: &Path, b: &Behavior) -> UResult<()> {
/// Copy one file to a new location, changing metadata. /// Copy one file to a new location, changing metadata.
/// ///
/// Returns a Result type with the Err variant containing the error message.
///
/// # Parameters /// # Parameters
/// ///
/// _from_ must exist as a non-directory. /// _from_ must exist as a non-directory.
@ -707,6 +707,7 @@ fn copy(from: &Path, to: &Path, b: &Behavior) -> UResult<()> {
} }
/// Return true if a file is necessary to copy. This is the case when: /// Return true if a file is necessary to copy. This is the case when:
///
/// - _from_ or _to_ is nonexistent; /// - _from_ or _to_ is nonexistent;
/// - either file has a sticky bit or set[ug]id bit, or the user specified one; /// - either file has a sticky bit or set[ug]id bit, or the user specified one;
/// - either file isn't a regular file; /// - either file isn't a regular file;