Skip to content

Commit 8867591

Browse files
committed
mv: improve the verbose mode to make tests/mv/mv-special-1.sh pass
1 parent 909da50 commit 8867591

File tree

2 files changed

+135
-19
lines changed

2 files changed

+135
-19
lines changed

src/uu/mv/src/mv.rs

Lines changed: 80 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -603,12 +603,12 @@ fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, options: &Options)
603603
return Err(MvError::NotADirectory(target_dir.quote().to_string()).into());
604604
}
605605

606-
let multi_progress = options.progress_bar.then(MultiProgress::new);
606+
let display_manager = options.progress_bar.then(MultiProgress::new);
607607

608-
let count_progress = if let Some(ref multi_progress) = multi_progress {
608+
let count_progress = if let Some(ref display_manager) = display_manager {
609609
if files.len() > 1 {
610610
Some(
611-
multi_progress.add(
611+
display_manager.add(
612612
ProgressBar::new(files.len().try_into().unwrap()).with_style(
613613
ProgressStyle::with_template(&format!(
614614
"{} {{msg}} {{wide_bar}} {{pos}}/{{len}}",
@@ -669,7 +669,7 @@ fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, options: &Options)
669669
sourcepath,
670670
&targetpath,
671671
options,
672-
multi_progress.as_ref(),
672+
display_manager.as_ref(),
673673
hardlink_params.0,
674674
hardlink_params.1,
675675
) {
@@ -678,7 +678,7 @@ fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, options: &Options)
678678
let e = e.map_err_context(|| {
679679
translate!("mv-error-cannot-move", "source" => sourcepath.quote(), "target" => targetpath.quote())
680680
});
681-
match multi_progress {
681+
match display_manager {
682682
Some(ref pb) => pb.suspend(|| show!(e)),
683683
None => show!(e),
684684
}
@@ -697,7 +697,7 @@ fn rename(
697697
from: &Path,
698698
to: &Path,
699699
opts: &Options,
700-
multi_progress: Option<&MultiProgress>,
700+
display_manager: Option<&MultiProgress>,
701701
#[cfg(unix)] hardlink_tracker: Option<&mut HardlinkTracker>,
702702
#[cfg(unix)] hardlink_scanner: Option<&HardlinkGroupScanner>,
703703
#[cfg(not(unix))] _hardlink_tracker: Option<()>,
@@ -745,7 +745,7 @@ fn rename(
745745
backup_path = backup_control::get_backup_path(opts.backup, to, &opts.suffix);
746746
if let Some(ref backup_path) = backup_path {
747747
// For backup renames, we don't need to track hardlinks as we're just moving the existing file
748-
rename_with_fallback(to, backup_path, multi_progress, None, None)?;
748+
rename_with_fallback(to, backup_path, display_manager, false, None, None)?;
749749
}
750750
}
751751

@@ -763,11 +763,18 @@ fn rename(
763763

764764
#[cfg(unix)]
765765
{
766-
rename_with_fallback(from, to, multi_progress, hardlink_tracker, hardlink_scanner)?;
766+
rename_with_fallback(
767+
from,
768+
to,
769+
display_manager,
770+
opts.verbose,
771+
hardlink_tracker,
772+
hardlink_scanner,
773+
)?;
767774
}
768775
#[cfg(not(unix))]
769776
{
770-
rename_with_fallback(from, to, multi_progress, None, None)?;
777+
rename_with_fallback(from, to, display_manager, opts.verbose, None, None)?;
771778
}
772779

773780
#[cfg(feature = "selinux")]
@@ -784,7 +791,7 @@ fn rename(
784791
None => translate!("mv-verbose-renamed", "from" => from.quote(), "to" => to.quote()),
785792
};
786793

787-
match multi_progress {
794+
match display_manager {
788795
Some(pb) => pb.suspend(|| {
789796
println!("{message}");
790797
}),
@@ -809,7 +816,8 @@ fn is_fifo(_filetype: fs::FileType) -> bool {
809816
fn rename_with_fallback(
810817
from: &Path,
811818
to: &Path,
812-
multi_progress: Option<&MultiProgress>,
819+
display_manager: Option<&MultiProgress>,
820+
verbose: bool,
813821
#[cfg(unix)] hardlink_tracker: Option<&mut HardlinkTracker>,
814822
#[cfg(unix)] hardlink_scanner: Option<&HardlinkGroupScanner>,
815823
#[cfg(not(unix))] _hardlink_tracker: Option<()>,
@@ -842,13 +850,20 @@ fn rename_with_fallback(
842850
hardlink_tracker,
843851
hardlink_scanner,
844852
|tracker, scanner| {
845-
rename_dir_fallback(from, to, multi_progress, Some(tracker), Some(scanner))
853+
rename_dir_fallback(
854+
from,
855+
to,
856+
display_manager,
857+
verbose,
858+
Some(tracker),
859+
Some(scanner),
860+
)
846861
},
847862
)
848863
}
849864
#[cfg(not(unix))]
850865
{
851-
rename_dir_fallback(from, to, multi_progress)
866+
rename_dir_fallback(from, to, display_manager, verbose)
852867
}
853868
} else if is_fifo(file_type) {
854869
rename_fifo_fallback(from, to)
@@ -921,7 +936,8 @@ fn rename_symlink_fallback(from: &Path, to: &Path) -> io::Result<()> {
921936
fn rename_dir_fallback(
922937
from: &Path,
923938
to: &Path,
924-
multi_progress: Option<&MultiProgress>,
939+
display_manager: Option<&MultiProgress>,
940+
verbose: bool,
925941
#[cfg(unix)] hardlink_tracker: Option<&mut HardlinkTracker>,
926942
#[cfg(unix)] hardlink_scanner: Option<&HardlinkGroupScanner>,
927943
) -> io::Result<()> {
@@ -939,12 +955,12 @@ fn rename_dir_fallback(
939955
// (Move will probably fail due to permission error later?)
940956
let total_size = dir_get_size(from).ok();
941957

942-
let progress_bar = match (multi_progress, total_size) {
943-
(Some(multi_progress), Some(total_size)) => {
958+
let progress_bar = match (display_manager, total_size) {
959+
(Some(display_manager), Some(total_size)) => {
944960
let template = "{msg}: [{elapsed_precise}] {wide_bar} {bytes:>7}/{total_bytes:7}";
945961
let style = ProgressStyle::with_template(template).unwrap();
946962
let bar = ProgressBar::new(total_size).with_style(style);
947-
Some(multi_progress.add(bar))
963+
Some(display_manager.add(bar))
948964
}
949965
(_, _) => None,
950966
};
@@ -960,7 +976,9 @@ fn rename_dir_fallback(
960976
hardlink_tracker,
961977
#[cfg(unix)]
962978
hardlink_scanner,
979+
verbose,
963980
progress_bar.as_ref(),
981+
display_manager,
964982
);
965983

966984
#[cfg(all(unix, not(any(target_os = "macos", target_os = "redox"))))]
@@ -980,7 +998,9 @@ fn copy_dir_contents(
980998
to: &Path,
981999
#[cfg(unix)] hardlink_tracker: Option<&mut HardlinkTracker>,
9821000
#[cfg(unix)] hardlink_scanner: Option<&HardlinkGroupScanner>,
1001+
verbose: bool,
9831002
progress_bar: Option<&ProgressBar>,
1003+
display_manager: Option<&MultiProgress>,
9841004
) -> io::Result<()> {
9851005
// Create the destination directory
9861006
fs::create_dir_all(to)?;
@@ -989,12 +1009,20 @@ fn copy_dir_contents(
9891009
#[cfg(unix)]
9901010
{
9911011
if let (Some(tracker), Some(scanner)) = (hardlink_tracker, hardlink_scanner) {
992-
copy_dir_contents_recursive(from, to, tracker, scanner, progress_bar)?;
1012+
copy_dir_contents_recursive(
1013+
from,
1014+
to,
1015+
tracker,
1016+
scanner,
1017+
verbose,
1018+
progress_bar,
1019+
display_manager,
1020+
)?;
9931021
}
9941022
}
9951023
#[cfg(not(unix))]
9961024
{
997-
copy_dir_contents_recursive(from, to, progress_bar)?;
1025+
copy_dir_contents_recursive(from, to, None, None, verbose, progress_bar, display_manager)?;
9981026
}
9991027

10001028
Ok(())
@@ -1005,7 +1033,11 @@ fn copy_dir_contents_recursive(
10051033
to_dir: &Path,
10061034
#[cfg(unix)] hardlink_tracker: &mut HardlinkTracker,
10071035
#[cfg(unix)] hardlink_scanner: &HardlinkGroupScanner,
1036+
#[cfg(not(unix))] _hardlink_tracker: Option<()>,
1037+
#[cfg(not(unix))] _hardlink_scanner: Option<()>,
1038+
verbose: bool,
10081039
progress_bar: Option<&ProgressBar>,
1040+
display_manager: Option<&MultiProgress>,
10091041
) -> io::Result<()> {
10101042
let entries = fs::read_dir(from_dir)?;
10111043

@@ -1022,14 +1054,32 @@ fn copy_dir_contents_recursive(
10221054
if from_path.is_dir() {
10231055
// Recursively copy subdirectory
10241056
fs::create_dir_all(&to_path)?;
1057+
1058+
// Print verbose message for directory
1059+
if verbose {
1060+
let message = translate!("mv-verbose-renamed", "from" => from_path.quote(), "to" => to_path.quote());
1061+
match display_manager {
1062+
Some(pb) => pb.suspend(|| {
1063+
println!("{message}");
1064+
}),
1065+
None => println!("{message}"),
1066+
}
1067+
}
1068+
10251069
copy_dir_contents_recursive(
10261070
&from_path,
10271071
&to_path,
10281072
#[cfg(unix)]
10291073
hardlink_tracker,
10301074
#[cfg(unix)]
10311075
hardlink_scanner,
1076+
#[cfg(not(unix))]
1077+
_hardlink_tracker,
1078+
#[cfg(not(unix))]
1079+
_hardlink_scanner,
1080+
verbose,
10321081
progress_bar,
1082+
display_manager,
10331083
)?;
10341084
} else {
10351085
// Copy file with or without hardlink support based on platform
@@ -1046,6 +1096,17 @@ fn copy_dir_contents_recursive(
10461096
{
10471097
fs::copy(&from_path, &to_path)?;
10481098
}
1099+
1100+
// Print verbose message for file
1101+
if verbose {
1102+
let message = translate!("mv-verbose-renamed", "from" => from_path.quote(), "to" => to_path.quote());
1103+
match display_manager {
1104+
Some(pb) => pb.suspend(|| {
1105+
println!("{message}");
1106+
}),
1107+
None => println!("{message}"),
1108+
}
1109+
}
10491110
}
10501111

10511112
if let Some(pb) = progress_bar {

tests/by-util/test_mv.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2660,3 +2660,58 @@ fn test_mv_error_usage_display_too_few() {
26602660
.stderr_contains("Usage: mv [OPTION]... [-T] SOURCE DEST")
26612661
.stderr_contains("For more information, try '--help'.");
26622662
}
2663+
2664+
#[test]
2665+
#[cfg(target_os = "linux")]
2666+
fn test_mv_verbose_directory_recursive() {
2667+
use tempfile::TempDir;
2668+
2669+
let scene = TestScenario::new(util_name!());
2670+
let at = &scene.fixtures;
2671+
2672+
at.mkdir("mv-dir");
2673+
at.mkdir("mv-dir/a");
2674+
at.mkdir("mv-dir/a/b");
2675+
at.mkdir("mv-dir/a/b/c");
2676+
at.mkdir("mv-dir/d");
2677+
at.mkdir("mv-dir/d/e");
2678+
at.mkdir("mv-dir/d/e/f");
2679+
at.touch("mv-dir/a/b/c/file1");
2680+
at.touch("mv-dir/d/e/f/file2");
2681+
2682+
// Force cross-filesystem move using /dev/shm (tmpfs)
2683+
let target_dir =
2684+
TempDir::new_in("/dev/shm/").expect("Unable to create temp directory in /dev/shm");
2685+
let target_path = target_dir.path().to_str().unwrap();
2686+
2687+
let result = scene
2688+
.ucmd()
2689+
.arg("--verbose")
2690+
.arg("mv-dir")
2691+
.arg(target_path)
2692+
.succeeds();
2693+
2694+
// Check that the directory structure was moved
2695+
assert!(!at.dir_exists("mv-dir"));
2696+
assert!(target_dir.path().join("mv-dir").exists());
2697+
assert!(target_dir.path().join("mv-dir/a").exists());
2698+
assert!(target_dir.path().join("mv-dir/a/b").exists());
2699+
assert!(target_dir.path().join("mv-dir/a/b/c").exists());
2700+
assert!(target_dir.path().join("mv-dir/d").exists());
2701+
assert!(target_dir.path().join("mv-dir/d/e").exists());
2702+
assert!(target_dir.path().join("mv-dir/d/e/f").exists());
2703+
assert!(target_dir.path().join("mv-dir/a/b/c/file1").exists());
2704+
assert!(target_dir.path().join("mv-dir/d/e/f/file2").exists());
2705+
2706+
let stdout = result.stdout_str();
2707+
2708+
// With cross-filesystem move, we MUST see recursive verbose output
2709+
assert!(stdout.contains("'mv-dir/a' -> "));
2710+
assert!(stdout.contains("'mv-dir/a/b' -> "));
2711+
assert!(stdout.contains("'mv-dir/a/b/c' -> "));
2712+
assert!(stdout.contains("'mv-dir/a/b/c/file1' -> "));
2713+
assert!(stdout.contains("'mv-dir/d' -> "));
2714+
assert!(stdout.contains("'mv-dir/d/e' -> "));
2715+
assert!(stdout.contains("'mv-dir/d/e/f' -> "));
2716+
assert!(stdout.contains("'mv-dir/d/e/f/file2' -> "));
2717+
}

0 commit comments

Comments
 (0)