Skip to content

Commit 39d2ece

Browse files
Handle directory-file and file-directory comparisons in the diff
GNU diff treats `diff DIRECTORY FILE` as `diff DIRECTORY/FILE FILE`
1 parent 46a26e8 commit 39d2ece

File tree

2 files changed

+46
-0
lines changed

2 files changed

+46
-0
lines changed

src/params.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::ffi::{OsStr, OsString};
2+
use std::path::PathBuf;
23

34
use regex::Regex;
45

@@ -178,6 +179,20 @@ pub fn parse_params<I: IntoIterator<Item = OsString>>(opts: I) -> Result<Params,
178179
} else {
179180
return Err(format!("Usage: {} <from> <to>", exe.to_string_lossy()));
180181
};
182+
183+
// diff DIRECTORY FILE => diff DIRECTORY/FILE FILE
184+
// diff FILE DIRECTORY => diff FILE DIRECTORY/FILE
185+
let mut from_path: PathBuf = PathBuf::from(&params.from);
186+
let mut to_path: PathBuf = PathBuf::from(&params.to);
187+
188+
if from_path.is_dir() && to_path.is_file() {
189+
from_path.push(to_path.file_name().unwrap());
190+
params.from = from_path.into_os_string();
191+
} else if from_path.is_file() && to_path.is_dir() {
192+
to_path.push(from_path.file_name().unwrap());
193+
params.to = to_path.into_os_string();
194+
}
195+
181196
params.format = format.unwrap_or(Format::default());
182197
Ok(params)
183198
}

tests/integration.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use assert_cmd::cmd::Command;
77
use diffutilslib::assert_diff_eq;
88
use predicates::prelude::*;
9+
use std::fs::File;
910
use std::io::Write;
1011
use tempfile::NamedTempFile;
1112

@@ -234,3 +235,33 @@ fn read_from_stdin() -> Result<(), Box<dyn std::error::Error>> {
234235

235236
Ok(())
236237
}
238+
239+
#[test]
240+
fn read_from_directory() -> Result<(), Box<dyn std::error::Error>> {
241+
let mut cmd = Command::cargo_bin("diffutils")?;
242+
243+
let target = "target/integration";
244+
let _ = std::fs::create_dir(target);
245+
let directory = &format!("{target}/d");
246+
let _ = std::fs::create_dir(directory);
247+
let mut a = File::create(&format!("{target}/a")).unwrap();
248+
a.write_all(b"a\n").unwrap();
249+
let mut da = File::create(&format!("{directory}/a")).unwrap();
250+
da.write_all(b"da\n").unwrap();
251+
252+
cmd.arg("-u")
253+
.arg(&format!("{target}/d"))
254+
.arg(&format!("{target}/a"));
255+
cmd.assert().code(predicate::eq(1)).failure();
256+
257+
let output = cmd.output().unwrap().stdout;
258+
assert_diff_eq!(
259+
output,
260+
format!(
261+
"--- {}/d/a\tTIMESTAMP\n+++ {}/a\tTIMESTAMP\n@@ -1 +1 @@\n-da\n+a\n",
262+
target, target
263+
)
264+
);
265+
266+
Ok(())
267+
}

0 commit comments

Comments
 (0)