Skip to content

Commit 251d3fb

Browse files
committed
cp: display symlink creation with --verbose
cp: display removed files with --verbose
1 parent 15ba6aa commit 251d3fb

File tree

5 files changed

+87
-21
lines changed

5 files changed

+87
-21
lines changed

src/uu/cp/locales/en-US.ftl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ cp-warning-source-specified-more-than-once = source { $file_type } { $source } s
108108
# Verbose and debug messages
109109
cp-verbose-copied = { $source } -> { $dest }
110110
cp-debug-skipped = skipped { $path }
111+
cp-verbose-removed = removed { $path }
111112
cp-verbose-created-directory = { $source } -> { $dest }
112113
cp-debug-copy-offload = copy offload: { $offload }, reflink: { $reflink }, sparse detection: { $sparse }
113114

src/uu/cp/locales/fr-FR.ftl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ cp-warning-source-specified-more-than-once = { $file_type } source { $source } s
108108
# Messages verbeux et de débogage
109109
cp-verbose-copied = { $source } -> { $dest }
110110
cp-debug-skipped = { $path } ignoré
111+
cp-verbose-removed = removed { $path }
111112
cp-verbose-created-directory = { $source } -> { $dest }
112113
cp-debug-copy-offload = copy offload : { $offload }, reflink : { $reflink }, sparse detection : { $sparse }
113114

src/uu/cp/src/copydir.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ use walkdir::{DirEntry, WalkDir};
2929

3030
use crate::{
3131
CopyResult, CpError, Options, aligned_ancestors, context_for, copy_attributes, copy_file,
32-
copy_link,
3332
};
3433

3534
/// Ensure a Windows path starts with a `\\?`.
@@ -259,17 +258,6 @@ fn copy_direntry(
259258
entry_is_dir_no_follow
260259
};
261260

262-
// If the source is a symbolic link and the options tell us not to
263-
// dereference the link, then copy the link object itself.
264-
if source_is_symlink && !options.dereference {
265-
return copy_link(
266-
&entry.source_absolute,
267-
&entry.local_to_target,
268-
symlinked_files,
269-
options,
270-
);
271-
}
272-
273261
// If the source is a directory and the destination does not
274262
// exist, ...
275263
if source_is_dir && !entry.local_to_target.exists() {

src/uu/cp/src/cp.rs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1936,7 +1936,6 @@ fn delete_dest_if_needed_and_allowed(
19361936
let delete_dest = match options.overwrite {
19371937
OverwriteMode::Clobber(cl) | OverwriteMode::Interactive(cl) => {
19381938
match cl {
1939-
// FIXME: print that the file was removed if --verbose is enabled
19401939
ClobberMode::Force => {
19411940
// TODO
19421941
// Using `readonly` here to check if `dest` needs to be deleted is not correct:
@@ -1975,13 +1974,23 @@ fn delete_dest_if_needed_and_allowed(
19751974
};
19761975

19771976
if delete_dest {
1978-
match fs::remove_file(dest) {
1979-
Ok(()) => {}
1980-
Err(err) if err.kind() == io::ErrorKind::NotFound => {
1981-
// target could have been deleted earlier (e.g. same-file with --remove-destination)
1977+
delete_path(dest, options)
1978+
} else {
1979+
Ok(())
1980+
}
1981+
}
1982+
1983+
fn delete_path(path: &Path, options: &Options) -> CopyResult<()> {
1984+
match fs::remove_file(path) {
1985+
Ok(()) => {
1986+
if options.verbose {
1987+
print_removed_path(path);
19821988
}
1983-
Err(err) => return Err(err.into()),
19841989
}
1990+
Err(err) if err.kind() == io::ErrorKind::NotFound => {
1991+
// target could have been deleted earlier (e.g. same-file with --remove-destination)
1992+
}
1993+
Err(err) => return Err(err.into()),
19851994
}
19861995

19871996
Ok(())
@@ -2063,6 +2072,13 @@ fn print_paths(parents: bool, source: &Path, dest: &Path) {
20632072
println!("{}", context_for(source, dest));
20642073
}
20652074

2075+
fn print_removed_path(path: &Path) {
2076+
println!(
2077+
"{}",
2078+
translate!("cp-verbose-removed", "path" => path.quote())
2079+
);
2080+
}
2081+
20662082
/// Handles the copy mode for a file copy operation.
20672083
///
20682084
/// This function determines how to copy a file based on the provided options.
@@ -2665,7 +2681,7 @@ fn copy_link(
26652681
// we always need to remove the file to be able to create a symlink,
26662682
// even if it is writeable.
26672683
if dest.is_symlink() || dest.is_file() {
2668-
fs::remove_file(dest)?;
2684+
delete_path(dest, options)?;
26692685
}
26702686
symlink_file(&link, dest, symlinked_files)?;
26712687
copy_attributes(source, dest, &options.attributes)

tests/by-util/test_cp.rs

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,6 @@ fn test_cp_arg_no_target_directory_with_recursive() {
385385
}
386386

387387
#[test]
388-
#[ignore = "disabled until https://github.com/uutils/coreutils/issues/7455 is fixed"]
389388
fn test_cp_arg_no_target_directory_with_recursive_target_does_not_exists() {
390389
let (at, mut ucmd) = at_and_ucmd!();
391390

@@ -768,7 +767,7 @@ fn test_cp_f_i_verbose_non_writeable_destination_y() {
768767
.pipe_in("y")
769768
.succeeds()
770769
.stderr_is("cp: replace 'b', overriding mode 0000 (---------)? ")
771-
.stdout_is("'a' -> 'b'\n");
770+
.stdout_is("removed 'b'\n'a' -> 'b'\n");
772771
}
773772

774773
#[test]
@@ -7163,3 +7162,64 @@ fn test_cp_recurse_verbose_output() {
71637162
.no_stderr()
71647163
.stdout_is(output);
71657164
}
7165+
7166+
#[test]
7167+
fn test_cp_recurse_verbose_output_with_symlink() {
7168+
let source_dir = "source_dir";
7169+
let target_dir = "target_dir";
7170+
let file = "file";
7171+
let symlink = "symlink";
7172+
#[cfg(not(windows))]
7173+
let output = format!(
7174+
"'{source_dir}' -> '{target_dir}/'\n'{source_dir}/{symlink}' -> '{target_dir}/{symlink}'\n"
7175+
);
7176+
#[cfg(windows)]
7177+
let output = format!(
7178+
"'{source_dir}' -> '{target_dir}\\'\n'{source_dir}\\{symlink}' -> '{target_dir}\\{symlink}'\n"
7179+
);
7180+
let (at, mut ucmd) = at_and_ucmd!();
7181+
7182+
at.mkdir(source_dir);
7183+
at.touch(file);
7184+
at.symlink_file(file, format!("{source_dir}/{symlink}").as_str());
7185+
7186+
ucmd.arg(source_dir)
7187+
.arg(target_dir)
7188+
.arg("-r")
7189+
.arg("--verbose")
7190+
.succeeds()
7191+
.no_stderr()
7192+
.stdout_is(output);
7193+
}
7194+
7195+
#[test]
7196+
fn test_cp_recurse_verbose_output_with_symlink_already_exists() {
7197+
let source_dir = "source_dir";
7198+
let target_dir = "target_dir";
7199+
let file = "file";
7200+
let symlink = "symlink";
7201+
#[cfg(not(windows))]
7202+
let output = format!(
7203+
"removed '{target_dir}/{symlink}'\n'{source_dir}/{symlink}' -> '{target_dir}/{symlink}'\n"
7204+
);
7205+
#[cfg(windows)]
7206+
let output = format!(
7207+
"removed '{target_dir}\\{symlink}'\n'{source_dir}\\{symlink}' -> '{target_dir}\\{symlink}'\n"
7208+
);
7209+
let (at, mut ucmd) = at_and_ucmd!();
7210+
7211+
at.mkdir(source_dir);
7212+
at.touch(file);
7213+
at.symlink_file(file, format!("{source_dir}/{symlink}").as_str());
7214+
at.mkdir(target_dir);
7215+
at.symlink_file(file, format!("{target_dir}/{symlink}").as_str());
7216+
7217+
ucmd.arg(source_dir)
7218+
.arg(target_dir)
7219+
.arg("-r")
7220+
.arg("--verbose")
7221+
.arg("-T")
7222+
.succeeds()
7223+
.no_stderr()
7224+
.stdout_is(output);
7225+
}

0 commit comments

Comments
 (0)