@@ -225,41 +225,67 @@ let register_snapshot_promotion t (targets : Targets.Validated.t) ~old_snapshot
225225 let in_source_tree p =
226226 Path. extract_build_context_dir_maybe_sandboxed p |> Option. value_exn |> snd
227227 in
228- let copy_file p =
229- let source_file = in_source_tree p in
230- let correction_file = Path. as_in_build_dir_exn p in
231- Diff_promotion. register_intermediate `Move ~source_file ~correction_file
232- in
233- let delete what file = in_source_tree file |> Diff_promotion. register_delete what in
228+ let diffs = ref [] in
229+ let add_copy_file p = diffs := p :: ! diffs in
230+ let deletes = ref [] in
231+ let add_delete what file = deletes := (what, in_source_tree file) :: ! deletes in
234232 let target_root_in_sandbox = map_path t targets.root in
235- Path.Map. iter2 old_snapshot new_snapshot ~f: (fun p before after ->
236- if
237- not
238- (let dir = Path. as_in_build_dir_exn (Path. parent_exn p) in
239- Path.Build. equal dir target_root_in_sandbox
240- &&
241- let basename = Path. basename p in
242- Filename.Set. mem targets.files basename || Filename.Set. mem targets.dirs basename)
243- then (
244- match before, after with
245- | None , None -> assert false
246- | None , Some (`File _ ) -> copy_file p
247- | Some (`File _ ), None -> delete `File p
248- | Some `Dir , None -> delete `Directory p
249- | Some `Dir , Some `Dir -> ()
250- | None , Some `Dir ->
251- (* We don't create empty dirs and rely on the traversal of this dir to
233+ let () =
234+ Path.Map. iter2 old_snapshot new_snapshot ~f: (fun p before after ->
235+ if
236+ not
237+ (let dir = Path. as_in_build_dir_exn (Path. parent_exn p) in
238+ Path.Build. equal dir target_root_in_sandbox
239+ &&
240+ let basename = Path. basename p in
241+ Filename.Set. mem targets.files basename
242+ || Filename.Set. mem targets.dirs basename)
243+ then (
244+ match before, after with
245+ | None , None -> assert false
246+ | None , Some (`File _ ) -> add_copy_file p
247+ | Some (`File _ ), None -> add_delete `File p
248+ | Some `Dir , None -> add_delete `Directory p
249+ | Some `Dir , Some `Dir -> ()
250+ | None , Some `Dir ->
251+ (* We don't create empty dirs and rely on the traversal of this dir to
252252 create the underlying files. Mayb e we should try harder *)
253- ()
254- | Some (`File _ ), Some `Dir ->
255- (* We are going to traverse the target directory here, but we should
253+ ()
254+ | Some (`File _ ), Some `Dir ->
255+ (* We are going to traverse the target directory here, but we should
256256 really treat this as a deletion *)
257- ()
258- | Some `Dir , Some (`File _ ) -> copy_file p
259- | Some (`File before ), Some (`File after ) ->
260- (match Cached_digest.Reduced_stats. compare before after with
261- | Eq -> ()
262- | Lt | Gt -> copy_file p)))
257+ ()
258+ | Some `Dir , Some (`File _ ) -> add_copy_file p
259+ | Some (`File before ), Some (`File after ) ->
260+ (match Cached_digest.Reduced_stats. compare before after with
261+ | Eq -> ()
262+ | Lt | Gt -> add_copy_file p)))
263+ in
264+ Fiber. fork_and_join_unit
265+ (fun () ->
266+ Fiber. parallel_iter ! diffs ~f: (fun path ->
267+ let source = Path. drop_optional_sandbox_root path in
268+ Diff_action. exec
269+ t.loc
270+ { Dune_util.Action.Diff. file1 = source
271+ ; file2 = Path. as_in_build_dir_exn path
272+ ; optional = true
273+ ; mode = Text
274+ }))
275+ (fun () ->
276+ Fiber. parallel_iter ! deletes ~f: (fun (what , path ) ->
277+ Diff_promotion. register_delete what path;
278+ let what =
279+ match what with
280+ | `File -> " File"
281+ | `Directory -> " Directory"
282+ in
283+ User_error. raise
284+ [ Pp. textf
285+ " %s %s should be deleted"
286+ what
287+ (Path.Source. to_string_maybe_quoted path)
288+ ]))
263289;;
264290
265291let hint_delete_dir =
@@ -273,42 +299,46 @@ let move_targets_to_build_dir t ~should_be_skipped ~(targets : Targets.Validated
273299 : unit Fiber. t
274300 =
275301 let open Fiber.O in
276- let + start, stop, queued =
277- maybe_async (fun () ->
278- Option. iter t.snapshot ~f: (fun old_snapshot ->
279- register_snapshot_promotion t targets ~old_snapshot );
280- Targets.Validated. iter
281- targets
282- ~file: (fun target ->
283- if not (should_be_skipped target)
284- then rename_optional_file ~src: (map_path t target) ~dst: target)
285- ~dir: (fun target ->
286- let src_dir = map_path t target in
287- (match Path.Untracked. stat (Path. build target) with
288- | Error (Unix. ENOENT, _ , _ ) -> ()
289- | Error e ->
290- User_error. raise
291- ~hints: hint_delete_dir
292- [ Pp. textf " unable to stat %s" (Path.Build. to_string_maybe_quoted target)
293- ; Pp. text " reason:"
294- ; Pp. text (Unix_error.Detailed. to_string_hum e)
295- ]
296- | Ok { Unix. st_kind; _ } ->
297- (* We clean up all targets (including directory targets) before
302+ let start = Time. now () in
303+ let + () =
304+ match t.snapshot with
305+ | None -> Fiber. return ()
306+ | Some old_snapshot -> register_snapshot_promotion t targets ~old_snapshot
307+ in
308+ let () =
309+ Targets.Validated. iter
310+ targets
311+ ~file: (fun target ->
312+ if not (should_be_skipped target)
313+ then rename_optional_file ~src: (map_path t target) ~dst: target)
314+ ~dir: (fun target ->
315+ let src_dir = map_path t target in
316+ (match Path.Untracked. stat (Path. build target) with
317+ | Error (Unix. ENOENT, _ , _ ) -> ()
318+ | Error e ->
319+ User_error. raise
320+ ~hints: hint_delete_dir
321+ [ Pp. textf " unable to stat %s" (Path.Build. to_string_maybe_quoted target)
322+ ; Pp. text " reason:"
323+ ; Pp. text (Unix_error.Detailed. to_string_hum e)
324+ ]
325+ | Ok { Unix. st_kind; _ } ->
326+ (* We clean up all targets (including directory targets) before
298327 running an action, so this branch should be unreachable unless
299328 the rule somehow escaped the sandbox *)
300- User_error. raise
301- ~hints: hint_delete_dir
302- [ Pp. textf
303- " Target %s of kind %S already exists in the build directory"
304- (Path.Build. to_string_maybe_quoted target)
305- (File_kind. to_string_hum st_kind)
306- ]);
307- if Fpath. exists (Path.Build. to_string src_dir)
308- then Unix. rename (Path.Build. to_string src_dir) (Path.Build. to_string target) ))
329+ User_error. raise
330+ ~hints: hint_delete_dir
331+ [ Pp. textf
332+ " Target %s of kind %S already exists in the build directory"
333+ (Path.Build. to_string_maybe_quoted target)
334+ (File_kind. to_string_hum st_kind)
335+ ]);
336+ if Fpath. exists (Path.Build. to_string src_dir)
337+ then Unix. rename (Path.Build. to_string src_dir) (Path.Build. to_string target))
309338 in
339+ let stop = Time. now () in
310340 Dune_trace. emit ~buffered: true Sandbox (fun () ->
311- Dune_trace.Event. sandbox `Extract ~start ~stop ~queued t.loc ~dir: t.dir)
341+ Dune_trace.Event. sandbox `Extract ~start ~stop ~queued: None t.loc ~dir: t.dir)
312342;;
313343
314344let failed_to_delete_sandbox dir reason =
0 commit comments