mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
cp: accept shortcuts for stringly-enum arguments
This commit is contained in:
parent
bfc7411dec
commit
d4546ced26
3 changed files with 88 additions and 63 deletions
|
@ -37,8 +37,8 @@ use uucore::{backup_control, update_control};
|
|||
// requires these enum.
|
||||
pub use uucore::{backup_control::BackupMode, update_control::UpdateMode};
|
||||
use uucore::{
|
||||
format_usage, help_about, help_section, help_usage, prompt_yes, show_error, show_warning,
|
||||
util_name,
|
||||
format_usage, help_about, help_section, help_usage, prompt_yes,
|
||||
shortcut_value_parser::ShortcutValueParser, show_error, show_warning, util_name,
|
||||
};
|
||||
|
||||
use crate::copydir::copy_directory;
|
||||
|
@ -396,22 +396,14 @@ static PRESERVABLE_ATTRIBUTES: &[&str] = &[
|
|||
"ownership",
|
||||
"timestamps",
|
||||
"context",
|
||||
"link",
|
||||
"links",
|
||||
"xattr",
|
||||
"all",
|
||||
];
|
||||
|
||||
#[cfg(not(unix))]
|
||||
static PRESERVABLE_ATTRIBUTES: &[&str] = &[
|
||||
"mode",
|
||||
"timestamps",
|
||||
"context",
|
||||
"link",
|
||||
"links",
|
||||
"xattr",
|
||||
"all",
|
||||
];
|
||||
static PRESERVABLE_ATTRIBUTES: &[&str] =
|
||||
&["mode", "timestamps", "context", "links", "xattr", "all"];
|
||||
|
||||
pub fn uu_app() -> Command {
|
||||
const MODE_ARGS: &[&str] = &[
|
||||
|
@ -543,7 +535,7 @@ pub fn uu_app() -> Command {
|
|||
.overrides_with_all(MODE_ARGS)
|
||||
.require_equals(true)
|
||||
.default_missing_value("always")
|
||||
.value_parser(["auto", "always", "never"])
|
||||
.value_parser(ShortcutValueParser::new(["auto", "always", "never"]))
|
||||
.num_args(0..=1)
|
||||
.help("control clone/CoW copies. See below"),
|
||||
)
|
||||
|
@ -559,9 +551,7 @@ pub fn uu_app() -> Command {
|
|||
.long(options::PRESERVE)
|
||||
.action(ArgAction::Append)
|
||||
.use_value_delimiter(true)
|
||||
.value_parser(clap::builder::PossibleValuesParser::new(
|
||||
PRESERVABLE_ATTRIBUTES,
|
||||
))
|
||||
.value_parser(ShortcutValueParser::new(PRESERVABLE_ATTRIBUTES))
|
||||
.num_args(0..)
|
||||
.require_equals(true)
|
||||
.value_name("ATTR_LIST")
|
||||
|
@ -655,7 +645,7 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::SPARSE)
|
||||
.long(options::SPARSE)
|
||||
.value_name("WHEN")
|
||||
.value_parser(["never", "auto", "always"])
|
||||
.value_parser(ShortcutValueParser::new(["never", "auto", "always"]))
|
||||
.help("control creation of sparse files. See below"),
|
||||
)
|
||||
// TODO: implement the following args
|
||||
|
|
|
@ -61,6 +61,7 @@ pub enum UpdateMode {
|
|||
}
|
||||
|
||||
pub mod arguments {
|
||||
use crate::shortcut_value_parser::ShortcutValueParser;
|
||||
use clap::ArgAction;
|
||||
|
||||
pub static OPT_UPDATE: &str = "update";
|
||||
|
@ -71,7 +72,7 @@ pub mod arguments {
|
|||
clap::Arg::new(OPT_UPDATE)
|
||||
.long("update")
|
||||
.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"])
|
||||
.value_parser(ShortcutValueParser::new(["none", "all", "older"]))
|
||||
.num_args(0..=1)
|
||||
.default_missing_value("older")
|
||||
.require_equals(true)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
//
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
// spell-checker:ignore (flags) reflink (fs) tmpfs (linux) rlimit Rlim NOFILE clob btrfs ROOTDIR USERDIR procfs outfile uufs xattrs
|
||||
// spell-checker:ignore (flags) reflink (fs) tmpfs (linux) rlimit Rlim NOFILE clob btrfs neve ROOTDIR USERDIR procfs outfile uufs xattrs
|
||||
|
||||
use crate::common::util::TestScenario;
|
||||
#[cfg(not(windows))]
|
||||
|
@ -286,16 +286,18 @@ fn test_cp_arg_update_interactive_error() {
|
|||
|
||||
#[test]
|
||||
fn test_cp_arg_update_none() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
for argument in ["--update=none", "--update=non", "--update=n"] {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
||||
.arg("--update=none")
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.no_stdout();
|
||||
ucmd.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg(TEST_HOW_ARE_YOU_SOURCE)
|
||||
.arg(argument)
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.no_stdout();
|
||||
|
||||
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "How are you?\n");
|
||||
assert_eq!(at.read(TEST_HOW_ARE_YOU_SOURCE), "How are you?\n");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1402,29 +1404,28 @@ fn test_cp_preserve_no_args_before_opts() {
|
|||
|
||||
#[test]
|
||||
fn test_cp_preserve_all() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let src_file = "a";
|
||||
let dst_file = "b";
|
||||
for argument in ["--preserve=all", "--preserve=al"] {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let src_file = "a";
|
||||
let dst_file = "b";
|
||||
|
||||
// Prepare the source file
|
||||
at.touch(src_file);
|
||||
#[cfg(unix)]
|
||||
at.set_mode(src_file, 0o0500);
|
||||
// Prepare the source file
|
||||
at.touch(src_file);
|
||||
#[cfg(unix)]
|
||||
at.set_mode(src_file, 0o0500);
|
||||
|
||||
// TODO: create a destination that does not allow copying of xattr and context
|
||||
// Copy
|
||||
ucmd.arg(src_file)
|
||||
.arg(dst_file)
|
||||
.arg("--preserve=all")
|
||||
.succeeds();
|
||||
// TODO: create a destination that does not allow copying of xattr and context
|
||||
// Copy
|
||||
ucmd.arg(src_file).arg(dst_file).arg(argument).succeeds();
|
||||
|
||||
#[cfg(all(unix, not(target_os = "freebsd")))]
|
||||
{
|
||||
// Assert that the mode, ownership, and timestamps are preserved
|
||||
// NOTICE: the ownership is not modified on the src file, because that requires root permissions
|
||||
let metadata_src = at.metadata(src_file);
|
||||
let metadata_dst = at.metadata(dst_file);
|
||||
assert_metadata_eq!(metadata_src, metadata_dst);
|
||||
#[cfg(all(unix, not(target_os = "freebsd")))]
|
||||
{
|
||||
// Assert that the mode, ownership, and timestamps are preserved
|
||||
// NOTICE: the ownership is not modified on the src file, because that requires root permissions
|
||||
let metadata_src = at.metadata(src_file);
|
||||
let metadata_dst = at.metadata(dst_file);
|
||||
assert_metadata_eq!(metadata_src, metadata_dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1472,6 +1473,35 @@ fn test_cp_preserve_all_context_fails_on_non_selinux() {
|
|||
.fails();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_preserve_link_parses() {
|
||||
// TODO: Also check whether --preserve=link did the right thing!
|
||||
for argument in [
|
||||
"--preserve=links",
|
||||
"--preserve=link",
|
||||
"--preserve=li",
|
||||
"--preserve=l",
|
||||
] {
|
||||
new_ucmd!()
|
||||
.arg(argument)
|
||||
.arg(TEST_COPY_FROM_FOLDER_FILE)
|
||||
.arg(TEST_HELLO_WORLD_DEST)
|
||||
.succeeds()
|
||||
.no_output();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_preserve_invalid_rejected() {
|
||||
new_ucmd!()
|
||||
.arg("--preserve=invalid-value")
|
||||
.arg(TEST_COPY_FROM_FOLDER_FILE)
|
||||
.arg(TEST_HELLO_WORLD_DEST)
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.no_stdout();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "android")]
|
||||
#[cfg(disabled_until_fixed)] // FIXME: the test looks to .succeed on android
|
||||
|
@ -2196,14 +2226,16 @@ fn test_cp_reflink_none() {
|
|||
#[test]
|
||||
#[cfg(any(target_os = "linux", target_os = "android", target_os = "macos"))]
|
||||
fn test_cp_reflink_never() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.arg("--reflink=never")
|
||||
.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg(TEST_EXISTING_FILE)
|
||||
.succeeds();
|
||||
for argument in ["--reflink=never", "--reflink=neve", "--reflink=n"] {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.arg(argument)
|
||||
.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg(TEST_EXISTING_FILE)
|
||||
.succeeds();
|
||||
|
||||
// Check the content of the destination file
|
||||
assert_eq!(at.read(TEST_EXISTING_FILE), "Hello, World!\n");
|
||||
// Check the content of the destination file
|
||||
assert_eq!(at.read(TEST_EXISTING_FILE), "Hello, World!\n");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -2286,19 +2318,21 @@ fn test_cp_sparse_never_empty() {
|
|||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[test]
|
||||
fn test_cp_sparse_always_empty() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
for argument in ["--sparse=always", "--sparse=alway", "--sparse=al"] {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
const BUFFER_SIZE: usize = 4096 * 4;
|
||||
let buf: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];
|
||||
const BUFFER_SIZE: usize = 4096 * 4;
|
||||
let buf: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];
|
||||
|
||||
at.make_file("src_file1");
|
||||
at.write_bytes("src_file1", &buf);
|
||||
at.make_file("src_file1");
|
||||
at.write_bytes("src_file1", &buf);
|
||||
|
||||
ucmd.args(&["--sparse=always", "src_file1", "dst_file_sparse"])
|
||||
.succeeds();
|
||||
ucmd.args(&[argument, "src_file1", "dst_file_sparse"])
|
||||
.succeeds();
|
||||
|
||||
assert_eq!(at.read_bytes("dst_file_sparse"), buf);
|
||||
assert_eq!(at.metadata("dst_file_sparse").blocks(), 0);
|
||||
assert_eq!(at.read_bytes("dst_file_sparse"), buf);
|
||||
assert_eq!(at.metadata("dst_file_sparse").blocks(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue