mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
feature(cp): also implement --dereference/-L
This commit is contained in:
parent
f76a0ec972
commit
c483fa501b
2 changed files with 167 additions and 9 deletions
|
@ -418,6 +418,11 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
.conflicts_with(OPT_DEREFERENCE)
|
||||
// -d sets this option
|
||||
.help("never follow symbolic links in SOURCE"))
|
||||
.arg(Arg::with_name(OPT_DEREFERENCE)
|
||||
.short("L")
|
||||
.long(OPT_DEREFERENCE)
|
||||
.conflicts_with(OPT_NO_DEREFERENCE)
|
||||
.help("always follow symbolic links in SOURCE"))
|
||||
.arg(Arg::with_name(OPT_ARCHIVE)
|
||||
.short("a")
|
||||
.long(OPT_ARCHIVE)
|
||||
|
@ -432,11 +437,6 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
.long(OPT_COPY_CONTENTS)
|
||||
.conflicts_with(OPT_ATTRIBUTES_ONLY)
|
||||
.help("NotImplemented: copy contents of special files when recursive"))
|
||||
.arg(Arg::with_name(OPT_DEREFERENCE)
|
||||
.short("L")
|
||||
.long(OPT_DEREFERENCE)
|
||||
.conflicts_with(OPT_NO_DEREFERENCE)
|
||||
.help("NotImplemented: always follow symbolic links in SOURCE"))
|
||||
.arg(Arg::with_name(OPT_PARENTS)
|
||||
.long(OPT_PARENTS)
|
||||
.help("NotImplemented: use full source file name under DIRECTORY"))
|
||||
|
@ -546,7 +546,7 @@ impl FromStr for Attribute {
|
|||
return Err(Error::InvalidArgument(format!(
|
||||
"invalid attribute '{}'",
|
||||
value
|
||||
)))
|
||||
)));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -568,7 +568,6 @@ impl Options {
|
|||
fn from_matches(matches: &ArgMatches) -> CopyResult<Options> {
|
||||
let not_implemented_opts = vec![
|
||||
OPT_COPY_CONTENTS,
|
||||
OPT_DEREFERENCE,
|
||||
OPT_PARENTS,
|
||||
OPT_SPARSE,
|
||||
OPT_STRIP_TRAILING_SLASHES,
|
||||
|
@ -649,7 +648,7 @@ impl Options {
|
|||
return Err(Error::InvalidArgument(format!(
|
||||
"invalid argument '{}' for \'reflink\'",
|
||||
value
|
||||
)))
|
||||
)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -927,7 +926,7 @@ fn copy_directory(root: &Path, target: &Target, options: &Options) -> CopyResult
|
|||
for path in WalkDir::new(root) {
|
||||
let p = or_continue!(path);
|
||||
let is_symlink = fs::symlink_metadata(p.path())?.file_type().is_symlink();
|
||||
let path = if options.no_dereference && is_symlink {
|
||||
let path = if (options.no_dereference || options.dereference) && is_symlink {
|
||||
// we are dealing with a symlink. Don't follow it
|
||||
match env::current_dir() {
|
||||
Ok(cwd) => cwd.join(resolve_relative_path(p.path())),
|
||||
|
|
|
@ -351,6 +351,60 @@ fn test_cp_arg_suffix() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_deref_conflicting_options() {
|
||||
let (_at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
ucmd.arg("-LP")
|
||||
.arg(TEST_COPY_TO_FOLDER)
|
||||
.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.fails();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cp_deref() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
#[cfg(not(windows))]
|
||||
let _r = fs::symlink(
|
||||
TEST_HELLO_WORLD_SOURCE,
|
||||
at.subdir.join(TEST_HELLO_WORLD_SOURCE_SYMLINK),
|
||||
);
|
||||
#[cfg(windows)]
|
||||
let _r = symlink_file(
|
||||
TEST_HELLO_WORLD_SOURCE,
|
||||
at.subdir.join(TEST_HELLO_WORLD_SOURCE_SYMLINK),
|
||||
);
|
||||
//using -L option
|
||||
let result = scene
|
||||
.ucmd()
|
||||
.arg("-L")
|
||||
.arg(TEST_HELLO_WORLD_SOURCE)
|
||||
.arg(TEST_HELLO_WORLD_SOURCE_SYMLINK)
|
||||
.arg(TEST_COPY_TO_FOLDER)
|
||||
.run();
|
||||
|
||||
// Check that the exit code represents a successful copy.
|
||||
let exit_success = result.success;
|
||||
assert!(exit_success);
|
||||
let path_to_new_symlink = at
|
||||
.subdir
|
||||
.join(TEST_COPY_TO_FOLDER)
|
||||
.join(TEST_HELLO_WORLD_SOURCE_SYMLINK);
|
||||
// unlike -P/--no-deref, we expect a file, not a link
|
||||
assert!(at.file_exists(
|
||||
&path_to_new_symlink
|
||||
.clone()
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.unwrap()
|
||||
));
|
||||
// Check the content of the destination file that was copied.
|
||||
assert_eq!(at.read(TEST_COPY_TO_FOLDER_FILE), "Hello, World!\n");
|
||||
let path_to_check = path_to_new_symlink.to_str().unwrap();
|
||||
assert_eq!(at.read(&path_to_check), "Hello, World!\n");
|
||||
}
|
||||
#[test]
|
||||
fn test_cp_no_deref() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
|
@ -395,6 +449,111 @@ fn test_cp_no_deref() {
|
|||
assert_eq!(at.read(&path_to_check), "Hello, World!\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
// For now, disable the test on Windows. Symlinks aren't well support on Windows.
|
||||
// It works on Unix for now and it works locally when run from a powershell
|
||||
#[cfg(not(windows))]
|
||||
fn test_cp_deref_folder_to_folder() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let cwd = env::current_dir().unwrap();
|
||||
|
||||
let path_to_new_symlink = at.subdir.join(TEST_COPY_FROM_FOLDER);
|
||||
|
||||
// Change the cwd to have a correct symlink
|
||||
assert!(env::set_current_dir(&path_to_new_symlink).is_ok());
|
||||
|
||||
#[cfg(not(windows))]
|
||||
let _r = fs::symlink(TEST_HELLO_WORLD_SOURCE, TEST_HELLO_WORLD_SOURCE_SYMLINK);
|
||||
#[cfg(windows)]
|
||||
let _r = symlink_file(TEST_HELLO_WORLD_SOURCE, TEST_HELLO_WORLD_SOURCE_SYMLINK);
|
||||
|
||||
// Back to the initial cwd (breaks the other tests)
|
||||
assert!(env::set_current_dir(&cwd).is_ok());
|
||||
|
||||
//using -P -R option
|
||||
let result = scene
|
||||
.ucmd()
|
||||
.arg("-L")
|
||||
.arg("-R")
|
||||
.arg("-v")
|
||||
.arg(TEST_COPY_FROM_FOLDER)
|
||||
.arg(TEST_COPY_TO_FOLDER_NEW)
|
||||
.run();
|
||||
println!("cp output {}", result.stdout);
|
||||
|
||||
// Check that the exit code represents a successful copy.
|
||||
let exit_success = result.success;
|
||||
assert!(exit_success);
|
||||
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
let scene2 = TestScenario::new("ls");
|
||||
let result = scene2.cmd("ls").arg("-al").arg(path_to_new_symlink).run();
|
||||
println!("ls source {}", result.stdout);
|
||||
|
||||
let path_to_new_symlink = at.subdir.join(TEST_COPY_TO_FOLDER_NEW);
|
||||
|
||||
let result = scene2.cmd("ls").arg("-al").arg(path_to_new_symlink).run();
|
||||
println!("ls dest {}", result.stdout);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
// No action as this test is disabled but kept in case we want to
|
||||
// try to make it work in the future.
|
||||
let a = Command::new("cmd").args(&["/C", "dir"]).output();
|
||||
println!("output {:#?}", a);
|
||||
|
||||
let a = Command::new("cmd")
|
||||
.args(&["/C", "dir", &at.as_string()])
|
||||
.output();
|
||||
println!("output {:#?}", a);
|
||||
|
||||
let a = Command::new("cmd")
|
||||
.args(&["/C", "dir", path_to_new_symlink.to_str().unwrap()])
|
||||
.output();
|
||||
println!("output {:#?}", a);
|
||||
|
||||
let path_to_new_symlink = at.subdir.join(TEST_COPY_FROM_FOLDER);
|
||||
|
||||
let a = Command::new("cmd")
|
||||
.args(&["/C", "dir", path_to_new_symlink.to_str().unwrap()])
|
||||
.output();
|
||||
println!("output {:#?}", a);
|
||||
|
||||
let path_to_new_symlink = at.subdir.join(TEST_COPY_TO_FOLDER_NEW);
|
||||
|
||||
let a = Command::new("cmd")
|
||||
.args(&["/C", "dir", path_to_new_symlink.to_str().unwrap()])
|
||||
.output();
|
||||
println!("output {:#?}", a);
|
||||
}
|
||||
|
||||
let path_to_new_symlink = at
|
||||
.subdir
|
||||
.join(TEST_COPY_TO_FOLDER_NEW)
|
||||
.join(TEST_HELLO_WORLD_SOURCE_SYMLINK);
|
||||
assert!(at.file_exists(
|
||||
&path_to_new_symlink
|
||||
.clone()
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.unwrap()
|
||||
));
|
||||
|
||||
let path_to_new = at.subdir.join(TEST_COPY_TO_FOLDER_NEW_FILE);
|
||||
|
||||
// Check the content of the destination file that was copied.
|
||||
let path_to_check = path_to_new.to_str().unwrap();
|
||||
assert_eq!(at.read(path_to_check), "Hello, World!\n");
|
||||
|
||||
// Check the content of the symlink
|
||||
let path_to_check = path_to_new_symlink.to_str().unwrap();
|
||||
assert_eq!(at.read(&path_to_check), "Hello, World!\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
// For now, disable the test on Windows. Symlinks aren't well support on Windows.
|
||||
// It works on Unix for now and it works locally when run from a powershell
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue