Implement -s/--report-identical-files option (fixes #23)

This commit is contained in:
Olivier Tilloy
2024-02-23 23:45:38 +01:00
committed by Sylvestre Ledru
parent a89f30afa0
commit c68d386170
5 changed files with 155 additions and 0 deletions
Generated
+41
View File
@@ -81,6 +81,7 @@ dependencies = [
"diff",
"predicates",
"pretty_assertions",
"same-file",
"tempfile",
]
@@ -248,6 +249,15 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "serde"
version = "1.0.197"
@@ -312,6 +322,37 @@ dependencies = [
"libc",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.52.0"
+1
View File
@@ -16,6 +16,7 @@ path = "src/main.rs"
[dependencies]
diff = "0.1.10"
same-file = "1.0.6"
[dev-dependencies]
pretty_assertions = "1"
+16
View File
@@ -28,10 +28,25 @@ fn main() -> ExitCode {
to,
context_count,
format,
report_identical_files,
} = parse_params(opts).unwrap_or_else(|error| {
eprintln!("{error}");
exit(2);
});
// if from and to are the same file, no need to perform any comparison
let maybe_report_identical_files = || {
if report_identical_files {
println!(
"Files {} and {} are identical",
from.to_string_lossy(),
to.to_string_lossy(),
)
}
};
if same_file::is_same_file(&from, &to).unwrap_or(false) {
maybe_report_identical_files();
return ExitCode::SUCCESS;
}
// read files
let from_content = match fs::read(&from) {
Ok(from_content) => from_content,
@@ -71,6 +86,7 @@ fn main() -> ExitCode {
};
io::stdout().write_all(&result).unwrap();
if result.is_empty() {
maybe_report_identical_files();
ExitCode::SUCCESS
} else {
ExitCode::from(1)
+56
View File
@@ -25,6 +25,7 @@ pub struct Params {
pub to: OsString,
pub format: Format,
pub context_count: usize,
pub report_identical_files: bool,
}
pub fn parse_params<I: IntoIterator<Item = OsString>>(opts: I) -> Result<Params, String> {
@@ -38,6 +39,7 @@ pub fn parse_params<I: IntoIterator<Item = OsString>>(opts: I) -> Result<Params,
let mut to = None;
let mut format = None;
let mut context_count = 3;
let mut report_identical_files = false;
while let Some(param) = opts.next() {
if param == "--" {
break;
@@ -52,6 +54,10 @@ pub fn parse_params<I: IntoIterator<Item = OsString>>(opts: I) -> Result<Params,
}
continue;
}
if param == "-s" || param == "--report-identical-files" {
report_identical_files = true;
continue;
}
let p = osstr_bytes(&param);
if p.first() == Some(&b'-') && p.get(1) != Some(&b'-') {
let mut bit = p[1..].iter().copied().peekable();
@@ -133,6 +139,7 @@ pub fn parse_params<I: IntoIterator<Item = OsString>>(opts: I) -> Result<Params,
to,
format,
context_count,
report_identical_files,
})
}
@@ -150,6 +157,7 @@ mod tests {
to: os("bar"),
format: Format::Normal,
context_count: 3,
report_identical_files: false,
}),
parse_params([os("diff"), os("foo"), os("bar")].iter().cloned())
);
@@ -162,6 +170,7 @@ mod tests {
to: os("bar"),
format: Format::Ed,
context_count: 3,
report_identical_files: false,
}),
parse_params([os("diff"), os("-e"), os("foo"), os("bar")].iter().cloned())
);
@@ -174,6 +183,7 @@ mod tests {
to: os("bar"),
format: Format::Unified,
context_count: 54,
report_identical_files: false,
}),
parse_params(
[os("diff"), os("-u54"), os("foo"), os("bar")]
@@ -187,6 +197,7 @@ mod tests {
to: os("bar"),
format: Format::Unified,
context_count: 54,
report_identical_files: false,
}),
parse_params(
[os("diff"), os("-U54"), os("foo"), os("bar")]
@@ -200,6 +211,7 @@ mod tests {
to: os("bar"),
format: Format::Unified,
context_count: 54,
report_identical_files: false,
}),
parse_params(
[os("diff"), os("-U"), os("54"), os("foo"), os("bar")]
@@ -213,6 +225,7 @@ mod tests {
to: os("bar"),
format: Format::Context,
context_count: 54,
report_identical_files: false,
}),
parse_params(
[os("diff"), os("-c54"), os("foo"), os("bar")]
@@ -222,6 +235,48 @@ mod tests {
);
}
#[test]
fn report_identical_files() {
assert_eq!(
Ok(Params {
from: os("foo"),
to: os("bar"),
format: Format::Normal,
context_count: 3,
report_identical_files: false,
}),
parse_params([os("diff"), os("foo"), os("bar")].iter().cloned())
);
assert_eq!(
Ok(Params {
from: os("foo"),
to: os("bar"),
format: Format::Normal,
context_count: 3,
report_identical_files: true,
}),
parse_params([os("diff"), os("-s"), os("foo"), os("bar")].iter().cloned())
);
assert_eq!(
Ok(Params {
from: os("foo"),
to: os("bar"),
format: Format::Normal,
context_count: 3,
report_identical_files: true,
}),
parse_params(
[
os("diff"),
os("--report-identical-files"),
os("foo"),
os("bar"),
]
.iter()
.cloned()
)
);
}
#[test]
fn double_dash() {
assert_eq!(
Ok(Params {
@@ -229,6 +284,7 @@ mod tests {
to: os("-h"),
format: Format::Normal,
context_count: 3,
report_identical_files: false,
}),
parse_params([os("diff"), os("--"), os("-g"), os("-h")].iter().cloned())
);
+41
View File
@@ -62,6 +62,47 @@ fn no_differences() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
#[test]
fn no_differences_report_identical_files() -> Result<(), Box<dyn std::error::Error>> {
// same file
let mut file1 = NamedTempFile::new()?;
file1.write_all("foo\n".as_bytes())?;
for option in ["", "-u", "-c", "-e"] {
let mut cmd = Command::cargo_bin("diffutils")?;
if !option.is_empty() {
cmd.arg(option);
}
cmd.arg("-s").arg(file1.path()).arg(file1.path());
cmd.assert()
.code(predicate::eq(0))
.success()
.stdout(predicate::eq(format!(
"Files {} and {} are identical\n",
file1.path().to_string_lossy(),
file1.path().to_string_lossy(),
)));
}
// two files with the same content
let mut file2 = NamedTempFile::new()?;
file2.write_all("foo\n".as_bytes())?;
for option in ["", "-u", "-c", "-e"] {
let mut cmd = Command::cargo_bin("diffutils")?;
if !option.is_empty() {
cmd.arg(option);
}
cmd.arg("-s").arg(file1.path()).arg(file2.path());
cmd.assert()
.code(predicate::eq(0))
.success()
.stdout(predicate::eq(format!(
"Files {} and {} are identical\n",
file1.path().to_string_lossy(),
file2.path().to_string_lossy(),
)));
}
Ok(())
}
#[test]
fn differences() -> Result<(), Box<dyn std::error::Error>> {
let mut file1 = NamedTempFile::new()?;