1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-27 19:17:43 +00:00

install: split/doc copy into smaller functions

This commit is contained in:
Sylvestre Ledru 2023-04-14 23:20:23 +02:00
parent fb72738db4
commit 2c1aa229a0

View file

@ -682,36 +682,23 @@ fn chown_optional_user_group(path: &Path, b: &Behavior) -> UResult<()> {
Ok(()) Ok(())
} }
/// Copy one file to a new location, changing metadata. /// Perform backup before overwriting.
///
/// Returns a Result type with the Err variant containing the error message.
/// ///
/// # Parameters /// # Parameters
/// ///
/// _from_ must exist as a non-directory. /// * `to` - The destination file path.
/// _to_ must be a non-existent file, whose parent directory exists. /// * `b` - The behavior configuration.
/// ///
/// # Errors /// # Returns
/// ///
/// If the copy system call fails, we print a verbose error and return an empty error value. /// Returns an Option containing the backup path, or None if backup is not needed.
/// ///
#[allow(clippy::cognitive_complexity)] fn perform_backup(to: &Path, b: &Behavior) -> UResult<Option<PathBuf>> {
fn copy(from: &Path, to: &Path, b: &Behavior) -> UResult<()> {
if b.compare && !need_copy(from, to, b)? {
return Ok(());
}
// Declare the path here as we may need it for the verbose output below.
let mut backup_path = None;
// Perform backup, if any, before overwriting 'to'
//
// The codes actually making use of the backup process don't seem to agree
// on how best to approach the issue. (mv and ln, for example)
if to.exists() { if to.exists() {
if b.verbose { if b.verbose {
println!("removed {}", to.quote()); println!("removed {}", to.quote());
} }
backup_path = backup_control::get_backup_path(b.backup_mode, to, &b.suffix); let backup_path = backup_control::get_backup_path(b.backup_mode, to, &b.suffix);
if let Some(ref backup_path) = backup_path { if let Some(ref backup_path) = backup_path {
// TODO!! // TODO!!
if let Err(err) = fs::rename(to, backup_path) { if let Err(err) = fs::rename(to, backup_path) {
@ -723,8 +710,24 @@ fn copy(from: &Path, to: &Path, b: &Behavior) -> UResult<()> {
.into()); .into());
} }
} }
Ok(backup_path)
} else {
Ok(None)
}
} }
/// Copy a file from one path to another.
///
/// # Parameters
///
/// * `from` - The source file path.
/// * `to` - The destination file path.
///
/// # Returns
///
/// Returns an empty Result or an error in case of failure.
///
fn copy_file(from: &Path, to: &Path) -> UResult<()> {
if from.as_os_str() == "/dev/null" { if from.as_os_str() == "/dev/null" {
/* workaround a limitation of fs::copy /* workaround a limitation of fs::copy
* https://github.com/rust-lang/rust/issues/79390 * https://github.com/rust-lang/rust/issues/79390
@ -737,8 +740,21 @@ fn copy(from: &Path, to: &Path, b: &Behavior) -> UResult<()> {
} else if let Err(err) = fs::copy(from, to) { } else if let Err(err) = fs::copy(from, to) {
return Err(InstallError::InstallFailed(from.to_path_buf(), to.to_path_buf(), err).into()); return Err(InstallError::InstallFailed(from.to_path_buf(), to.to_path_buf(), err).into());
} }
Ok(())
}
if b.strip && cfg!(not(windows)) { /// Strip a file using an external program.
///
/// # Parameters
///
/// * `to` - The destination file path.
/// * `b` - The behavior configuration.
///
/// # Returns
///
/// Returns an empty Result or an error in case of failure.
///
fn strip_file(to: &Path, b: &Behavior) -> UResult<()> {
match process::Command::new(&b.strip_program).arg(to).output() { match process::Command::new(&b.strip_program).arg(to).output() {
Ok(o) => { Ok(o) => {
if !o.status.success() { if !o.status.success() {
@ -756,8 +772,21 @@ fn copy(from: &Path, to: &Path, b: &Behavior) -> UResult<()> {
return Err(InstallError::StripProgramFailed(e.to_string()).into()); return Err(InstallError::StripProgramFailed(e.to_string()).into());
} }
} }
Ok(())
} }
/// Set ownership and permissions on the destination file.
///
/// # Parameters
///
/// * `to` - The destination file path.
/// * `b` - The behavior configuration.
///
/// # Returns
///
/// Returns an empty Result or an error in case of failure.
///
fn set_ownership_and_permissions(to: &Path, b: &Behavior) -> UResult<()> {
// Silent the warning as we want to the error message // Silent the warning as we want to the error message
#[allow(clippy::question_mark)] #[allow(clippy::question_mark)]
if mode::chmod(to, b.mode()).is_err() { if mode::chmod(to, b.mode()).is_err() {
@ -766,7 +795,21 @@ fn copy(from: &Path, to: &Path, b: &Behavior) -> UResult<()> {
chown_optional_user_group(to, b)?; chown_optional_user_group(to, b)?;
if b.preserve_timestamps { Ok(())
}
/// Preserve timestamps on the destination file.
///
/// # Parameters
///
/// * `from` - The source file path.
/// * `to` - The destination file path.
///
/// # Returns
///
/// Returns an empty Result or an error in case of failure.
///
fn preserve_timestamps(from: &Path, to: &Path) -> UResult<()> {
let meta = match fs::metadata(from) { let meta = match fs::metadata(from) {
Ok(meta) => meta, Ok(meta) => meta,
Err(e) => return Err(InstallError::MetadataFailed(e).into()), Err(e) => return Err(InstallError::MetadataFailed(e).into()),
@ -776,10 +819,46 @@ fn copy(from: &Path, to: &Path, b: &Behavior) -> UResult<()> {
let accessed_time = FileTime::from_last_access_time(&meta); let accessed_time = FileTime::from_last_access_time(&meta);
match set_file_times(to, accessed_time, modified_time) { match set_file_times(to, accessed_time, modified_time) {
Ok(_) => {} Ok(_) => Ok(()),
Err(e) => show_error!("{}", e), Err(e) => {
show_error!("{}", e);
Ok(())
} }
} }
}
/// Copy one file to a new location, changing metadata.
///
/// Returns a Result type with the Err variant containing the error message.
///
/// # Parameters
///
/// _from_ must exist as a non-directory.
/// _to_ must be a non-existent file, whose parent directory exists.
///
/// # Errors
///
/// If the copy system call fails, we print a verbose error and return an empty error value.
///
fn copy(from: &Path, to: &Path, b: &Behavior) -> UResult<()> {
if b.compare && !need_copy(from, to, b)? {
return Ok(());
}
// Declare the path here as we may need it for the verbose output below.
let backup_path = perform_backup(to, b)?;
copy_file(from, to)?;
#[cfg(not(windows))]
if b.strip {
strip_file(to, b)?;
}
set_ownership_and_permissions(to, b)?;
if b.preserve_timestamps {
preserve_timestamps(from, to)?;
}
if b.verbose { if b.verbose {
print!("{} -> {}", from.quote(), to.quote()); print!("{} -> {}", from.quote(), to.quote());