du: deduplicate the input

Should fix:
tests/du/hard-link.sh
This commit is contained in:
Sylvestre Ledru 2024-11-24 13:12:55 +01:00
parent 79f991dd05
commit 95bd50e09a
2 changed files with 73 additions and 9 deletions

View file

@ -649,6 +649,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let summarize = matches.get_flag(options::SUMMARIZE); let summarize = matches.get_flag(options::SUMMARIZE);
let count_links = matches.get_flag(options::COUNT_LINKS);
let max_depth = parse_depth( let max_depth = parse_depth(
matches matches
.get_one::<String>(options::MAX_DEPTH) .get_one::<String>(options::MAX_DEPTH)
@ -669,15 +671,19 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
} }
read_files_from(file_from)? read_files_from(file_from)?
} else { } else if let Some(files) = matches.get_many::<String>(options::FILE) {
match matches.get_one::<String>(options::FILE) { let files = files.map(PathBuf::from);
Some(_) => matches if count_links {
.get_many::<String>(options::FILE) files.collect()
.unwrap() } else {
.map(PathBuf::from) // Deduplicate while preserving order
.collect(), let mut seen = std::collections::HashSet::new();
None => vec![PathBuf::from(".")], files
.filter(|path| seen.insert(path.clone()))
.collect::<Vec<_>>()
} }
} else {
vec![PathBuf::from(".")]
}; };
let time = matches.contains_id(options::TIME).then(|| { let time = matches.contains_id(options::TIME).then(|| {
@ -719,7 +725,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
} else { } else {
Deref::None Deref::None
}, },
count_links: matches.get_flag(options::COUNT_LINKS), count_links,
verbose: matches.get_flag(options::VERBOSE), verbose: matches.get_flag(options::VERBOSE),
excludes: build_exclude_patterns(&matches)?, excludes: build_exclude_patterns(&matches)?,
}; };

View file

@ -1194,3 +1194,61 @@ fn test_human_size() {
.succeeds() .succeeds()
.stdout_contains(format!("1.0K {dir}")); .stdout_contains(format!("1.0K {dir}"));
} }
#[cfg(not(target_os = "android"))]
#[test]
fn test_du_deduplicated_input_args() {
let ts = TestScenario::new(util_name!());
let at = &ts.fixtures;
at.mkdir("d");
at.mkdir("d/d");
at.touch("d/f");
at.hard_link("d/f", "d/h");
let result = ts
.ucmd()
.arg("--inodes")
.arg("d")
.arg("d")
.arg("d")
.succeeds();
result.no_stderr();
let result_seq: Vec<String> = result
.stdout_str()
.lines()
.map(|x| x.parse().unwrap())
.collect();
#[cfg(windows)]
assert_eq!(result_seq, ["1\td\\d", "3\td"]);
#[cfg(not(windows))]
assert_eq!(result_seq, ["1\td/d", "3\td"]);
}
#[cfg(not(target_os = "android"))]
#[test]
fn test_du_no_deduplicated_input_args() {
let ts = TestScenario::new(util_name!());
let at = &ts.fixtures;
at.mkdir("d");
at.touch("d/d");
let result = ts
.ucmd()
.arg("--inodes")
.arg("-l")
.arg("d")
.arg("d")
.arg("d")
.succeeds();
result.no_stderr();
let result_seq: Vec<String> = result
.stdout_str()
.lines()
.map(|x| x.parse().unwrap())
.collect();
assert_eq!(result_seq, ["2\td", "2\td", "2\td"]);
}