core mv cp: update help doc for 'update' functionality

This commit is contained in:
John Shin 2023-04-27 05:14:46 -07:00
parent 9dc84e9061
commit 2f8df653c5
3 changed files with 63 additions and 21 deletions

View file

@ -279,6 +279,21 @@ static PRESERVABLE_ATTRIBUTES: &[&str] = &[
"all",
];
static CP_UPDATE_LONG_HELP: &str =
"Do not copy a non-directory that has an existing destination with the same or newer modification timestamp;
instead, silently skip the file without failing. If timestamps are being preserved, the comparison is to the
source timestamp truncated to the resolutions of the destination file system and of the system calls used to
update timestamps; this avoids duplicate work if several cp -pu commands are executed with the same source
and destination. This option is ignored if the -n or --no-clobber option is also specified. Also, if
--preserve=links is also specified (like with cp -au for example), that will take precedence; consequently,
depending on the order that files are processed from the source, newer files in the destination may be
replaced, to mirror hard links in the source. which gives more control over which existing files in the
destination are replaced, and its value can be one of the following:
all This is the default operation when an --update option is not specified, and results in all existing files in the destination being replaced.
none This is similar to the --no-clobber option, in that no files in the destination are replaced, but also skipping a file does not induce a failure.
older This is the default operation when --update is specified, and results in files being replaced if theyre older than the corresponding source file.";
#[cfg(not(unix))]
static PRESERVABLE_ATTRIBUTES: &[&str] =
&["mode", "timestamps", "context", "links", "xattr", "all"];
@ -558,6 +573,7 @@ pub fn uu_app() -> Command {
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let matches = uu_app()
.after_help(backup_control::BACKUP_CONTROL_LONG_HELP)
.after_help(CP_UPDATE_LONG_HELP)
.try_get_matches_from(args);
// The error is parsed here because we do not want version or help being printed to stderr.
@ -1628,22 +1644,38 @@ fn copy_file(
}
CopyMode::Update => {
if dest.exists() {
let dest_metadata = fs::symlink_metadata(dest)?;
match options.update {
update_control::UpdateMode::ReplaceAll => {
copy_helper(
source,
dest,
options,
context,
source_is_symlink,
source_is_fifo,
symlinked_files,
)?;
}
update_control::UpdateMode::ReplaceNone => return Ok(()),
update_control::UpdateMode::ReplaceIfOlder => {
let dest_metadata = fs::symlink_metadata(dest)?;
let src_time = source_metadata.modified()?;
let dest_time = dest_metadata.modified()?;
if src_time <= dest_time {
return Ok(());
} else {
copy_helper(
source,
dest,
options,
context,
source_is_symlink,
source_is_fifo,
symlinked_files,
)?;
let src_time = source_metadata.modified()?;
let dest_time = dest_metadata.modified()?;
if src_time <= dest_time {
return Ok(());
} else {
copy_helper(
source,
dest,
options,
context,
source_is_symlink,
source_is_fifo,
symlinked_files,
)?;
}
}
}
} else {
copy_helper(

View file

@ -67,11 +67,23 @@ static OPT_VERBOSE: &str = "verbose";
static OPT_PROGRESS: &str = "progress";
static ARG_FILES: &str = "files";
static MV_UPDATE_LONG_HELP: &str =
"Do not move a non-directory that has an existing destination with the same or newer modification timestamp;
instead, silently skip the file without failing. If the move is across file system boundaries, the comparison is
to the source timestamp truncated to the resolutions of the destination file system and of the system calls used
to update timestamps; this avoids duplicate work if several mv -u commands are executed with the same source
and destination. This option is ignored if the -n or --no-clobber option is also specified. which gives more control
over which existing files in the destination are replaced, and its value can be one of the following:
all This is the default operation when an --update option is not specified, and results in all existing files in the destination being replaced.
none This is similar to the --no-clobber option, in that no files in the destination are replaced, but also skipping a file does not induce a failure.
older This is the default operation when --update is specified, and results in files being replaced if theyre older than the corresponding source file.";
#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let mut app = uu_app()
.after_help(backup_control::BACKUP_CONTROL_LONG_HELP)
.after_help(update_control::UPDATE_CONTROL_LONG_HELP);
.after_help(MV_UPDATE_LONG_HELP);
let matches = app.try_get_matches_from_mut(args)?;
if !matches.contains_id(OPT_TARGET_DIRECTORY)

View file

@ -2,8 +2,6 @@ use clap::ArgMatches;
pub static UPDATE_CONTROL_VALUES: &[&str] = &["all", "none", "old", ""];
pub const UPDATE_CONTROL_LONG_HELP: &str = "VERY LONG HELP";
#[derive(Clone, Eq, PartialEq)]
pub enum UpdateMode {
ReplaceAll,
@ -20,10 +18,10 @@ pub mod arguments {
pub fn update() -> clap::Arg {
clap::Arg::new(OPT_UPDATE)
.long("update")
.help("some help")
.help("move only when the SOURCE file is newer than the destination file or when the destination file is missing")
.value_parser(["", "none", "all", "older"])
.num_args(0..=1)
.default_missing_value("all")
.default_missing_value("older")
.require_equals(true)
.overrides_with("update")
.action(clap::ArgAction::Set)
@ -32,7 +30,7 @@ pub mod arguments {
pub fn update_no_args() -> clap::Arg {
clap::Arg::new(OPT_UPDATE_NO_ARG)
.short('u')
.help("like ")
.help("like --update but does not accept an argument")
.action(ArgAction::SetTrue)
}
}