Skip to content

Commit 57fbe13

Browse files
committed
fix: diff action missing files
(diff ..) should know to distinguish between empty and missing files Signed-off-by: Rudi Grinberg <me@rgrinberg.com>
1 parent 40248bd commit 57fbe13

5 files changed

Lines changed: 49 additions & 21 deletions

File tree

doc/changes/fixed/13696.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
- Improve handling of empty files in the `diff` action. These are now correctly
2+
distinguished from *empty* files. (#13696, @rgrinberg)
3+
4+
- Pass `/dev/null` to `--diff-command` instead of non-existent files (#13696,
5+
@rgrinberg)

src/dune_engine/diff_action.ml

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,19 @@ let compare_files = function
66
| Text -> Io.compare_text_files
77
;;
88

9-
let diff_eq_files { Diff.optional; mode; file1; file2 } =
10-
let file1 = if Fpath.exists (Path.to_string file1) then file1 else Dev_null.path in
11-
let file2 = Path.build file2 in
12-
(optional && not (Fpath.exists (Path.to_string file2)))
13-
|| compare_files mode file1 file2 = Eq
9+
let compare_files { Diff.optional; mode; file1; file2 } =
10+
let file2_exists = lazy (Fpath.exists (Path.Build.to_string file2)) in
11+
if optional && not (Lazy.force file2_exists)
12+
then
13+
(* Small optimization to avoid stat'ing file1 *)
14+
`Eq true
15+
else (
16+
let file1_exists = Fpath.exists (Path.to_string file1) in
17+
match file1_exists, Lazy.force file2_exists with
18+
| true, true -> `Eq (compare_files mode file1 (Path.build file2) = Eq)
19+
| false, false -> `Eq true
20+
| true, false -> if optional then `Eq true else `Delete
21+
| false, true -> `Create)
1422
;;
1523

1624
let exec loc ({ Diff.optional; file1; file2; mode } as diff) =
@@ -20,11 +28,11 @@ let exec loc ({ Diff.optional; file1; file2; mode } as diff) =
2028
try Fpath.unlink_exn (Path.Build.to_string file2) with
2129
| Unix.Unix_error (ENOENT, _, _) -> ())
2230
in
23-
if diff_eq_files diff
24-
then (
31+
match compare_files diff with
32+
| `Eq true ->
2533
remove_intermediate_file ();
26-
Fiber.return ())
27-
else (
34+
Fiber.return ()
35+
| `Eq false | `Create | `Delete ->
2836
let is_copied_from_source_tree file =
2937
match Path.extract_build_context_dir_maybe_sandboxed file with
3038
| None -> false
@@ -73,5 +81,5 @@ let exec loc ({ Diff.optional; file1; file2; mode } as diff) =
7381
then register `Copy
7482
| true ->
7583
if in_source_or_target then register `Move else remove_intermediate_file ());
76-
Fiber.return ()))
84+
Fiber.return ())
7785
;;

src/dune_engine/print_diff.ml

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -97,16 +97,14 @@ let make_metadata ~has_embedded_location promotion loc =
9797
module External = struct
9898
let which prog = Bin.which ~path:(Env_path.path Env.initial) prog
9999

100-
let diff ~skip_trailing_cr ~dir promotion loc file1 file2 =
100+
let diff ~skip_trailing_cr ~dir promotion loc (label1, file1) (label2, file2) =
101101
which "diff"
102102
|> Option.map ~f:(fun prog ->
103103
let relative = Path.reach ~from:dir in
104-
let file1 = relative file1 in
105-
let file2 = relative file2 in
106104
let args =
107-
[ "-u"; "--label"; file1; "--label"; file2 ]
105+
[ "-u"; "--label"; relative label1; "--label"; relative label2 ]
108106
@ (if skip_trailing_cr then [ "--strip-trailing-cr" ] else [])
109-
@ [ file1; file2 ]
107+
@ [ relative file1; relative file2 ]
110108
in
111109
{ dir
112110
; prog
@@ -158,6 +156,8 @@ module External = struct
158156
;;
159157
end
160158

159+
let noent_to_dev_null f = if Fpath.exists (Path.to_string f) then f else Dev_null.path
160+
161161
let prepare ~skip_trailing_cr promotion path1 path2 =
162162
let dir, loc =
163163
let dir, file1 =
@@ -170,15 +170,19 @@ let prepare ~skip_trailing_cr promotion path1 path2 =
170170
in
171171
dir, Loc.in_file file1
172172
in
173+
let label1 = Path.drop_optional_sandbox_root path1 in
174+
let label2 = Path.drop_optional_sandbox_root path2 in
175+
let path1 = noent_to_dev_null path1 in
176+
let path2 = noent_to_dev_null path2 in
173177
let fallback =
174178
With_fallback.fail
175179
(User_error.make
176180
~loc
177181
?promotion
178182
[ Pp.textf
179183
"Files %s and %s differ."
180-
(Path.to_string_maybe_quoted (Path.drop_optional_sandbox_root path1))
181-
(Path.to_string_maybe_quoted (Path.drop_optional_sandbox_root path2))
184+
(Path.to_string_maybe_quoted (Path.drop_optional_sandbox_root label1))
185+
(Path.to_string_maybe_quoted (Path.drop_optional_sandbox_root label2))
182186
])
183187
in
184188
match !Clflags.diff_command with
@@ -215,7 +219,9 @@ let prepare ~skip_trailing_cr promotion path1 path2 =
215219
| None -> fallback
216220
| Some diff -> With_fallback.run diff ~fallback
217221
in
218-
let diff = External.diff ~skip_trailing_cr ~dir promotion loc path1 path2 in
222+
let diff =
223+
External.diff ~skip_trailing_cr ~dir promotion loc (label1, path1) (label2, path2)
224+
in
219225
if Execution_env.inside_dune
220226
then or_fallback ~fallback diff
221227
else (

test/blackbox-tests/test-cases/promote/non-existent-dir.t

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ dune promote should be able to promote into directories that don't exist
1818

1919
$ dune build ./foo --diff-command "$SHELL $PWD/diff.sh"
2020
File "dir/foo", line 1, characters 0-0:
21-
a: dir/foo
21+
a: /dev/null
2222
b: foo
2323
[1]
2424

test/blackbox-tests/test-cases/promote/non-existent-empty.t/run.t

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,27 @@ Tests for promoting with non existent reference
66
x-non-existent-empty missing
77

88
$ dune build @blah-non-existent-empty
9+
File "x-non-existent-empty", line 1, characters 0-0:
10+
Error: Files _build/default/x-non-existent-empty and _build/default/x.gen
11+
differ.
12+
[1]
913

1014
$ dune promote
15+
Promoting _build/default/x.gen to x-non-existent-empty.
1116

1217
$ file_status x-non-existent-empty
13-
x-non-existent-empty missing
18+
x-non-existent-empty exists
1419

1520
$ file_status x-non-existent-non-empty
1621
x-non-existent-non-empty missing
1722

1823
$ dune build @blah-non-existent-non-empty 2>&1 | dune_cmd subst '^.+/diff:' 'diff:'
1924
File "x-non-existent-non-empty", line 1, characters 0-0:
20-
diff: x-non-existent-non-empty: No such file or directory
25+
--- x-non-existent-non-empty
26+
+++ y.gen
27+
@@ -0,0 +1 @@
28+
+foobar
29+
\ No newline at end of file
2130
[1]
2231

2332
$ dune promote

0 commit comments

Comments
 (0)