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:
parent
2b18e45ece
commit
0461a45c9a
1 changed files with 41 additions and 40 deletions
|
@ -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;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue