Skip to content

Commit 20a9062

Browse files
committed
Address feedback plus some clean up
Signed-off-by: Andrey Mokhov <[email protected]>
1 parent af76741 commit 20a9062

File tree

10 files changed

+134
-68
lines changed

10 files changed

+134
-68
lines changed

bin/exec.ml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,11 @@ let term =
7272
let not_found () =
7373
let open Memo.Build.O in
7474
let+ hints =
75-
(* CR-someday amokhov: Currently we do not provide hints for directory
76-
targets but it would be nice to do that. *)
7775
(* Good candidates for the "./x.exe" instead of "x.exe" error are
78-
executables present in the current directory *)
76+
executables present in the current directory. Note: we do not check
77+
directory targets here; even if they do indeed include a matching
78+
executable, they would be located in a subdirectory of [dir], so
79+
it's unclear if that's what the user wanted. *)
7980
let+ candidates =
8081
Build_system.file_targets_of ~dir:(Path.build dir)
8182
>>| Path.Set.to_list

otherlibs/stdune-unstable/path.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,12 @@ module Build = struct
686686
| None ->
687687
Code_error.raise "Path.Build.drop_build_context_exn" [ ("t", to_dyn t) ]
688688

689+
let drop_build_context_maybe_sandboxed_exn t =
690+
match extract_build_context_dir_maybe_sandboxed t with
691+
| Some (_, t) -> t
692+
| None ->
693+
Code_error.raise "Path.Build.drop_build_context_maybe_sandboxed_exn" [ ("t", to_dyn t) ]
694+
689695
let build_dir = Fdecl.create Kind.to_dyn
690696

691697
let build_dir_prefix = Fdecl.create Dyn.Encoder.opaque

otherlibs/stdune-unstable/path.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ module Build : sig
156156

157157
val drop_build_context_exn : t -> Source.t
158158

159+
val drop_build_context_maybe_sandboxed_exn : t -> Source.t
160+
159161
(** [Source.t] here is a lie in some cases: consider when the context name
160162
happens to be ["install"] or [".alias"]. *)
161163
val extract_build_context : t -> (string * Source.t) option

otherlibs/stdune-unstable/user_error.ml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,13 @@ let has_embedded_location annots =
6868
List.exists annots ~f:(fun annot ->
6969
Annot.Has_embedded_location.check annot (fun () -> true) (fun () -> false))
7070

71+
let has_location (msg : User_message.t) annots =
72+
(not (is_loc_none msg.loc)) || has_embedded_location annots
73+
7174
let needs_stack_trace annots =
7275
List.exists annots ~f:(fun annot ->
7376
Annot.Needs_stack_trace.check annot (fun () -> true) (fun () -> false))
7477

75-
let has_location (msg : User_message.t) annots =
76-
(not (is_loc_none msg.loc)) || has_embedded_location annots
77-
7878
let () =
7979
Printexc.register_printer (function
8080
| E (t, []) -> Some (Format.asprintf "%a@?" Pp.to_fmt (User_message.pp t))

src/dune_engine/action_builder.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,8 @@ module With_targets = struct
185185
| xs ->
186186
let build, targets =
187187
List.fold_left xs ~init:([], Targets.empty)
188-
~f:(fun (acc_build, acc_targets) x ->
189-
(x.build :: acc_build, Targets.combine acc_targets x.targets))
188+
~f:(fun (builds, targets) x ->
189+
(x.build :: builds, Targets.combine x.targets targets))
190190
in
191191
{ build = all (List.rev build); targets }
192192

src/dune_engine/build_system.ml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1543,7 +1543,7 @@ end = struct
15431543

15441544
module Exec_result = struct
15451545
type t =
1546-
{ paths_in_directory_targets : Path.Build.Set.t
1546+
{ files_in_directory_targets : Path.Build.Set.t
15471547
; action_exec_result : Action_exec.Exec_result.t
15481548
}
15491549
end
@@ -1601,13 +1601,13 @@ end = struct
16011601
Action_exec.exec ~root ~context ~env ~targets ~rule_loc:loc
16021602
~build_deps ~execution_parameters action
16031603
in
1604-
let paths_in_directory_targets =
1604+
let files_in_directory_targets =
16051605
match sandbox with
16061606
| None -> Path.Build.Set.empty
16071607
| Some sandbox ->
16081608
Sandbox.move_targets_to_build_dir sandbox ~loc ~targets
16091609
in
1610-
{ Exec_result.paths_in_directory_targets; action_exec_result })
1610+
{ Exec_result.files_in_directory_targets; action_exec_result })
16111611
in
16121612
Option.iter sandbox ~f:Sandbox.destroy;
16131613
(* All went well, these targets are no longer pending *)
@@ -1977,7 +1977,7 @@ end = struct
19771977
| _ ->
19781978
let targets =
19791979
Path.Build.Set.union file_targets
1980-
exec_result.paths_in_directory_targets
1980+
exec_result.files_in_directory_targets
19811981
in
19821982
Fiber.return
19831983
(compute_target_digests_or_raise_error

src/dune_engine/rule.ml

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -101,36 +101,39 @@ let make ?(sandbox = Sandbox_config.default) ?(mode = Mode.Standard) ~context
101101
(action, deps))
102102
})
103103
in
104-
match Targets.validate targets with
105-
| No_targets -> (
106-
match info with
107-
| From_dune_file loc ->
108-
User_error.raise ~loc [ Pp.text "Rule has no targets specified" ]
109-
| Internal
110-
| Source_file_copy _ ->
111-
Code_error.raise "Rule.Targets: An internal rule with no targets" [])
112-
| Inconsistent_parent_dir -> (
113-
match info with
114-
| From_dune_file loc ->
115-
User_error.raise ~loc
116-
[ Pp.text "Rule has targets in different directories.\nTargets:"
117-
; Targets.pp targets
118-
]
119-
| Internal
120-
| Source_file_copy _ ->
121-
Code_error.raise "Rule has targets in different directories"
122-
[ ("targets", Targets.to_dyn targets) ])
123-
| Valid { parent_dir = dir } ->
124-
let loc =
104+
let dir =
105+
match Targets.validate targets with
106+
| Valid { parent_dir } -> parent_dir
107+
| No_targets -> (
125108
match info with
126-
| From_dune_file loc -> loc
127-
| Internal ->
128-
Loc.in_file
129-
(Path.drop_optional_build_context
130-
(Path.build (Path.Build.relative dir "_unknown_")))
131-
| Source_file_copy p -> Loc.in_file (Path.source p)
132-
in
133-
{ id = Id.gen (); targets; context; action; mode; info; loc; dir }
109+
| From_dune_file loc ->
110+
User_error.raise ~loc [ Pp.text "Rule has no targets specified" ]
111+
| Internal
112+
| Source_file_copy _ ->
113+
Code_error.raise "Rule.Targets: An internal rule with no targets" [])
114+
| Inconsistent_parent_dir -> (
115+
match info with
116+
| From_dune_file loc ->
117+
User_error.raise ~loc
118+
[ Pp.text "Rule has targets in different directories.\nTargets:"
119+
; Targets.pp targets
120+
]
121+
| Internal
122+
| Source_file_copy _ ->
123+
Code_error.raise
124+
"Rule.Targets: An internal rule has targets in different directories"
125+
[ ("targets", Targets.to_dyn targets) ])
126+
in
127+
let loc =
128+
match info with
129+
| From_dune_file loc -> loc
130+
| Internal ->
131+
Loc.in_file
132+
(Path.drop_optional_build_context
133+
(Path.build (Path.Build.relative dir "_unknown_")))
134+
| Source_file_copy p -> Loc.in_file (Path.source p)
135+
in
136+
{ id = Id.gen (); targets; context; action; mode; info; loc; dir }
134137

135138
let set_action t action =
136139
let action = Action_builder.memoize "Rule.set_action" action in

src/dune_engine/sandbox.ml

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -115,22 +115,35 @@ let rename_optional_file ~src ~dst =
115115
(* Recursively move regular files from [src] to [dst] and return the set of
116116
moved files. *)
117117
let rename_dir_recursively ~loc ~src_dir ~dst_dir =
118-
let rec loop ~src ~dst ~dst_parent =
119-
(match Fpath.mkdir dst with
118+
let rec loop ~src_dir ~dst_dir =
119+
(match Fpath.mkdir (Path.Build.to_string dst_dir) with
120120
| Created -> ()
121-
| Already_exists -> (* CR-someday amokhov: Should we clear it? *) ()
121+
| Already_exists ->
122+
User_error.raise ~loc
123+
~annots:[ User_error.Annot.Needs_stack_trace.make () ]
124+
[ Pp.textf
125+
"This rule defines a directory target %S whose name conflicts with \
126+
an internal directory used by Dune. Please use a different name."
127+
(Path.Build.drop_build_context_exn dst_dir
128+
|> Path.Source.to_string_maybe_quoted)
129+
]
122130
| Missing_parent_directory -> assert false);
123-
match Dune_filesystem_stubs.read_directory_with_kinds src with
131+
match
132+
Dune_filesystem_stubs.read_directory_with_kinds
133+
(Path.Build.to_string src_dir)
134+
with
124135
| Ok files ->
125136
List.concat_map files ~f:(fun (file, kind) ->
126-
let src = Filename.concat src file in
127-
let dst = Filename.concat dst file in
128137
match (kind : Dune_filesystem_stubs.File_kind.t) with
129138
| S_REG ->
130-
Unix.rename src dst;
131-
[ Path.Build.relative dst_parent file ]
139+
let src = Path.Build.relative src_dir file in
140+
let dst = Path.Build.relative dst_dir file in
141+
Unix.rename (Path.Build.to_string src) (Path.Build.to_string dst);
142+
[ dst ]
132143
| S_DIR ->
133-
loop ~src ~dst ~dst_parent:(Path.Build.relative dst_parent file)
144+
loop
145+
~src_dir:(Path.Build.relative src_dir file)
146+
~dst_dir:(Path.Build.relative dst_dir file)
134147
| _ ->
135148
User_error.raise ~loc
136149
[ Pp.textf "Rule produced a file with unrecognised kind %S"
@@ -139,31 +152,27 @@ let rename_dir_recursively ~loc ~src_dir ~dst_dir =
139152
| Error (ENOENT, _, _) ->
140153
User_error.raise ~loc
141154
[ Pp.textf "Rule failed to produce directory %S"
142-
(Path.of_string src
143-
|> Path.drop_optional_build_context_maybe_sandboxed
144-
|> Path.to_string_maybe_quoted)
155+
(Path.Build.drop_build_context_maybe_sandboxed_exn src_dir
156+
|> Path.Source.to_string_maybe_quoted)
145157
]
146158
| Error (unix_error, _, _) ->
147159
User_error.raise ~loc
148160
[ Pp.textf "Rule produced unreadable directory %S"
149-
(Path.of_string src
150-
|> Path.drop_optional_build_context_maybe_sandboxed
151-
|> Path.to_string_maybe_quoted)
161+
(Path.Build.drop_build_context_maybe_sandboxed_exn src_dir
162+
|> Path.Source.to_string_maybe_quoted)
152163
; Pp.verbatim (Unix.error_message unix_error)
153164
]
154165
in
155-
loop
156-
~src:(Path.Build.to_string src_dir)
157-
~dst:(Path.Build.to_string dst_dir)
158-
~dst_parent:dst_dir
159-
|> Path.Build.Set.of_list
166+
loop ~src_dir ~dst_dir |> Path.Build.Set.of_list
160167

161168
let move_targets_to_build_dir t ~loc ~targets =
162-
Targets.to_list_map targets
163-
~file:(fun target ->
164-
rename_optional_file ~src:(map_path t target) ~dst:target)
165-
~dir:(fun target ->
166-
rename_dir_recursively ~loc ~src_dir:(map_path t target) ~dst_dir:target)
167-
|> snd |> Path.Build.Set.union_all
169+
let (_file_targets_renamed : unit list), files_moved_in_directory_targets =
170+
Targets.to_list_map targets
171+
~file:(fun target ->
172+
rename_optional_file ~src:(map_path t target) ~dst:target)
173+
~dir:(fun target ->
174+
rename_dir_recursively ~loc ~src_dir:(map_path t target) ~dst_dir:target)
175+
in
176+
Path.Build.Set.union_all files_moved_in_directory_targets
168177

169178
let destroy t = Path.rm_rf (Path.build t.dir)

src/dune_engine/sandbox.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ val create :
2020
-> t
2121

2222
(** Move the targets created by the action from the sandbox to the build
23-
directory. Returns the set of paths discovered in directory targets. *)
23+
directory. Returns the set of files discovered in directory targets. *)
2424
val move_targets_to_build_dir :
2525
t -> loc:Loc.t -> targets:Targets.t -> Path.Build.Set.t
2626

test/blackbox-tests/test-cases/directory-targets.t/run.t

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,3 +315,48 @@ and the second one because of the lack of early cutoff.
315315
running
316316
bash contents
317317
running
318+
319+
Check that Dune clears stale files from directory targets.
320+
321+
$ cat > dune <<EOF
322+
> (rule
323+
> (deps src_a src_b src_c (sandbox always))
324+
> (targets output/*)
325+
> (action (bash "echo running; mkdir -p output/subdir; cat src_a > output/new-a; cat src_b > output/subdir/b")))
326+
> (rule
327+
> (deps output)
328+
> (target contents)
329+
> (action (bash "echo running; echo 'new-a:' > contents; cat output/new-a >> contents; echo 'b:' >> contents; cat output/subdir/b >> contents")))
330+
> EOF
331+
332+
$ dune build contents
333+
bash output
334+
running
335+
bash contents
336+
running
337+
338+
Note that the stale "output/a" file got removed.
339+
340+
$ ls _build/default/output | sort
341+
new-a
342+
subdir
343+
344+
Directory target whose name conflicts with an internal directory used by Dune.
345+
346+
$ cat > dune <<EOF
347+
> (rule
348+
> (deps (sandbox always))
349+
> (targets .dune/*)
350+
> (action (bash "mkdir .dune; echo hello > .dune/hello")))
351+
> EOF
352+
353+
$ dune build .dune/hello
354+
File "dune", line 1, characters 0-110:
355+
1 | (rule
356+
2 | (deps (sandbox always))
357+
3 | (targets .dune/*)
358+
4 | (action (bash "mkdir .dune; echo hello > .dune/hello")))
359+
Error: This rule defines a directory target ".dune" whose name conflicts with
360+
an internal directory used by Dune. Please use a different name.
361+
-> required by _build/default/.dune/hello
362+
[1]

0 commit comments

Comments
 (0)