Skip to content

Commit 1a5eaa9

Browse files
Move dev-tool lock dirs into hidden folder (#12671)
* Move dev-tool lock dirs from source into into build folder Signed-off-by: Marek Kubica <[email protected]> * Use `Path` type Signed-off-by: Marek Kubica <[email protected]> * Turn the dev-tool path to a `Path.External.t` Signed-off-by: Marek Kubica <[email protected]> * Fix after rebase Signed-off-by: Marek Kubica <[email protected]> * Remove unused indirection Signed-off-by: Marek Kubica <[email protected]> * Rewrite absolute external paths into relative paths Signed-off-by: Marek Kubica <[email protected]> * Bring back `Fs_memo` Signed-off-by: Marek Kubica <[email protected]> * Improve implementation of external to source mapping Signed-off-by: Marek Kubica <[email protected]> * Closer to style of `main` Signed-off-by: Marek Kubica <[email protected]> * Add validation that path to be deleted is in fact managed Signed-off-by: Marek Kubica <[email protected]> * Use `try_localize` instead of rolling my own version of it Signed-off-by: Marek Kubica <[email protected]> * Do not assume build dir name Signed-off-by: Marek Kubica <[email protected]> * Add cram test to show that custom build dirs work Signed-off-by: Marek Kubica <[email protected]> * use fs_memo to scan lock directories Signed-off-by: Ali Caglayan <[email protected]> * Switch from untracked path checking to compile-time flag Signed-off-by: Marek Kubica <[email protected]> --------- Signed-off-by: Marek Kubica <[email protected]> Signed-off-by: Ali Caglayan <[email protected]> Co-authored-by: Ali Caglayan <[email protected]>
1 parent 9543184 commit 1a5eaa9

39 files changed

+240
-107
lines changed

bin/lock_dev_tool.ml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,9 @@ let solve ~dev_tool ~local_packages =
8080
| `Disabled -> workspace
8181
in
8282
(* as we want to write to the source, we're using the source lock dir here *)
83-
let lock_dir = Dune_rules.Lock_dir.dev_tool_source_lock_dir dev_tool |> Path.source in
83+
let lock_dir =
84+
Dune_rules.Lock_dir.dev_tool_external_lock_dir dev_tool |> Path.external_
85+
in
8486
Memo.of_reproducible_fiber
8587
@@ Pkg.Lock.solve
8688
workspace
@@ -174,14 +176,14 @@ let extra_dependencies dev_tool =
174176

175177
let lockdir_status dev_tool =
176178
let open Memo.O in
177-
let dev_tool_lock_dir = Dune_rules.Lock_dir.dev_tool_source_lock_dir dev_tool in
179+
let dev_tool_lock_dir = Dune_rules.Lock_dir.dev_tool_external_lock_dir dev_tool in
178180
let* lock_dir_exists =
179-
Dune_engine.Fs_memo.dir_exists (In_source_dir dev_tool_lock_dir)
181+
Dune_engine.Fs_memo.dir_exists (Path.Outside_build_dir.External dev_tool_lock_dir)
180182
in
181183
match lock_dir_exists with
182184
| false -> Memo.return `No_lockdir
183185
| true ->
184-
let dev_tool_lock_dir = Path.source dev_tool_lock_dir in
186+
let dev_tool_lock_dir = Path.external_ dev_tool_lock_dir in
185187
(match Lock_dir.read_disk dev_tool_lock_dir with
186188
| Error _ -> Memo.return `No_lockdir
187189
| Ok { packages; _ } ->

bin/pkg/lock.ml

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,13 @@ let solve_multiple_platforms
197197
|> Platforms_by_message.all_solver_errors_raising_if_any_manifest_errors )
198198
;;
199199

200+
let user_lock_dir_path path =
201+
match (path : Path.t) with
202+
| In_source_tree _ -> path
203+
| In_build_dir _ -> path
204+
| External e -> Dune_pkg.Pkg_workspace.dev_tool_path_to_source_dir e |> Path.source
205+
;;
206+
200207
let summary_message
201208
~portable_lock_dir
202209
~lock_dir_path
@@ -259,7 +266,9 @@ let summary_message
259266
in
260267
(Pp.tag
261268
User_message.Style.Success
262-
(Pp.textf "Solution for %s" (Path.to_string_maybe_quoted lock_dir_path))
269+
(Pp.textf
270+
"Solution for %s"
271+
(Path.to_string_maybe_quoted (user_lock_dir_path lock_dir_path)))
263272
:: Pp.nop
264273
:: Pp.text "Dependencies common to all supported platforms:"
265274
:: pp_package_set common_packages
@@ -268,7 +277,9 @@ let summary_message
268277
else
269278
(Pp.tag
270279
User_message.Style.Success
271-
(Pp.textf "Solution for %s:" (Path.to_string_maybe_quoted lock_dir_path))
280+
(Pp.textf
281+
"Solution for %s:"
282+
(Path.to_string_maybe_quoted (user_lock_dir_path lock_dir_path)))
272283
:: (match Lock_dir.Packages.to_pkg_list lock_dir.packages with
273284
| [] -> Pp.tag User_message.Style.Warning @@ Pp.text "(no dependencies to lock)"
274285
| packages -> pp_packages packages)
@@ -493,7 +504,9 @@ let solve
493504
([ Pp.text "Unable to solve dependencies for the following lock directories:" ]
494505
@ List.concat_map errors ~f:(fun (path, errors) ->
495506
let messages = List.map errors ~f:fst in
496-
[ Pp.textf "Lock directory %s:" (Path.to_string_maybe_quoted path)
507+
[ Pp.textf
508+
"Lock directory %s:"
509+
(Path.to_string_maybe_quoted (user_lock_dir_path path))
497510
; Pp.vbox (Pp.concat ~sep:Pp.cut messages)
498511
]))
499512
| Ok write_disks_with_summaries ->

src/dune_pkg/lock_dir.ml

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -524,14 +524,22 @@ let in_source_tree path =
524524
(match Path.Source.explode in_source with
525525
| "default" :: ".lock" :: components ->
526526
Path.Source.L.relative Path.Source.root components
527-
| _otherwise ->
528-
Code_error.raise
529-
"Unexpected location of lock directory in build directory"
530-
[ "path", Path.Build.to_dyn b; "in_source", Path.Source.to_dyn in_source ])
531-
| External e ->
532-
Code_error.raise
533-
"External path returned when loading a lock dir"
534-
[ "path", Path.External.to_dyn e ]
527+
| source_components ->
528+
(match Path.Build.explode b with
529+
| (".dev-tools.locks" as prefix) :: dev_tool :: components ->
530+
let build_as_source =
531+
Path.build_dir |> Path.to_string |> Path.Source.of_string
532+
in
533+
Path.Source.L.relative build_as_source (prefix :: dev_tool :: components)
534+
| build_components ->
535+
Code_error.raise
536+
"Unexpected location of lock directory in build directory"
537+
[ "path", Path.Build.to_dyn b
538+
; "in_source", Path.Source.to_dyn in_source
539+
; "source_components", Dyn.(list string) source_components
540+
; "build_components", Dyn.(list string) build_components
541+
]))
542+
| External e -> Workspace.dev_tool_path_to_source_dir e
535543
;;
536544

537545
module Pkg = struct
@@ -862,7 +870,7 @@ module Pkg = struct
862870
;;
863871

864872
(* More general version of [files_dir] which works on generic paths *)
865-
let files_dir_generic package_name maybe_package_version ~lock_dir =
873+
let files_dir package_name maybe_package_version ~lock_dir =
866874
(* TODO(steve): Once portable lockdirs are enabled by default, make the
867875
package version non-optional *)
868876
let extension = ".files" in
@@ -877,16 +885,6 @@ module Pkg = struct
877885
^ extension)
878886
;;
879887

880-
let files_dir package_name maybe_package_version ~lock_dir =
881-
match files_dir_generic package_name maybe_package_version ~lock_dir with
882-
| In_source_tree _ as path -> path
883-
| In_build_dir _ as path -> path
884-
| External e ->
885-
Code_error.raise
886-
"file_dir is an external path, this is unsupported"
887-
[ "path", Path.External.to_dyn e ]
888-
;;
889-
890888
let source_files_dir package_name maybe_package_version ~lock_dir =
891889
let source = in_source_tree lock_dir in
892890
let package_name = Package_name.to_string package_name in
@@ -1392,7 +1390,16 @@ module Write_disk = struct
13921390
let safely_remove_lock_dir_if_exists_thunk path =
13931391
match check_existing_lock_dir path with
13941392
| Ok `Non_existant -> Fun.const ()
1395-
| Ok `Is_existing_lock_dir -> fun () -> Path.rm_rf path
1393+
| Ok `Is_existing_lock_dir ->
1394+
fun () ->
1395+
let path =
1396+
match path with
1397+
| In_source_tree _ | In_build_dir _ -> path
1398+
| External e ->
1399+
(* it might be a dev-tool path, try to convert *)
1400+
Workspace.dev_tool_path_to_source_dir e |> Path.source
1401+
in
1402+
Path.rm_rf path
13961403
| Error e -> raise_user_error_on_check_existance path e
13971404
;;
13981405

@@ -1488,10 +1495,7 @@ module Write_disk = struct
14881495
let maybe_package_version =
14891496
if portable_lock_dir then Some package_version else None
14901497
in
1491-
Pkg.files_dir_generic
1492-
package_name
1493-
maybe_package_version
1494-
~lock_dir:lock_dir_path
1498+
Pkg.files_dir package_name maybe_package_version ~lock_dir:lock_dir_path
14951499
in
14961500
Path.mkdir_p files_dir;
14971501
List.iter files ~f:(fun { File_entry.original; local_file } ->

src/dune_pkg/workspace.ml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,20 @@ module Repository = struct
7070

7171
let opam_url { name = _; url } = url
7272
end
73+
74+
let dev_tool_path_to_source_dir path =
75+
match Path.Expert.try_localize_external (Path.external_ path) with
76+
| External _ | In_source_tree _ ->
77+
Code_error.raise
78+
"External path is not pointing to lock dir location"
79+
[ "external", Path.External.to_dyn path ]
80+
| In_build_dir b ->
81+
(match Path.Build.explode b with
82+
| (".dev-tools.locks" as prefix) :: dev_tool_name :: components ->
83+
let build_as_source = Path.build_dir |> Path.to_string |> Path.Source.of_string in
84+
Path.Source.L.relative build_as_source (prefix :: dev_tool_name :: components)
85+
| components ->
86+
Code_error.raise
87+
"Unexpected external path"
88+
[ "dir", Path.External.to_dyn path; "components", Dyn.(list string) components ])
89+
;;

src/dune_pkg/workspace.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,5 @@ module Repository : sig
2525

2626
val name : t -> Name.t
2727
end
28+
29+
val dev_tool_path_to_source_dir : Path.External.t -> Path.Source.t

src/dune_rules/fetch_rules.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,11 +189,11 @@ let find_checksum, find_url =
189189
Dune_pkg.Dev_tool.all
190190
~init:(Checksum.Map.empty, Digest.Map.empty)
191191
~f:(fun acc dev_tool ->
192-
let dir = Lock_dir.dev_tool_source_lock_dir dev_tool in
192+
let dir = Lock_dir.dev_tool_external_lock_dir dev_tool in
193193
let exists =
194194
(* Note we use [Path.Untracked] here rather than [Fs_memo] because a tool's
195195
lockdir may be generated part way through a build. *)
196-
Path.Untracked.exists (Path.source dir)
196+
Path.Untracked.exists (Path.external_ dir)
197197
in
198198
match exists with
199199
| false -> Memo.return acc

src/dune_rules/format_rules.ml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,12 @@ end
3333

3434
module Ocamlformat = struct
3535
let dev_tool_lock_dir_exists () =
36-
let path = Lock_dir.dev_tool_source_lock_dir Ocamlformat in
37-
Source_tree.find_dir path >>| Option.is_some
36+
(* we assume that if lock_dev_tools is set, then the lock dir was created
37+
via locking and can expect it to exist. If it doesn't, it's a bug
38+
*)
39+
match Config.get Compile_time.lock_dev_tools with
40+
| `Enabled -> true
41+
| `Disabled -> false
3842
;;
3943

4044
(* Config files for ocamlformat. When these are changed, running
@@ -129,7 +133,7 @@ let gen_rules_output
129133
let loc = Format_config.loc config in
130134
let dir = Path.Build.parent_exn output_dir in
131135
let alias_formatted = Alias.fmt ~dir:output_dir in
132-
let* ocamlformat_is_locked = Ocamlformat.dev_tool_lock_dir_exists () in
136+
let ocamlformat_is_locked = Ocamlformat.dev_tool_lock_dir_exists () in
133137
let setup_formatting file =
134138
(let input_basename = Path.Source.basename file in
135139
let input = Path.Build.relative dir input_basename in

src/dune_rules/lock_dir.ml

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -147,12 +147,19 @@ let dev_tool_to_path_segment dev_tool =
147147
dev_tool |> Dev_tool.package_name |> Package_name.to_string |> Path.Local.of_string
148148
;;
149149

150-
let dev_tool_source_lock_dir dev_tool =
151-
let dev_tools_path = Path.Source.(relative root "dev-tools.locks") in
150+
(* This function returns the lock dir that is created outside the build system. *)
151+
let dev_tool_external_lock_dir dev_tool =
152+
let external_root =
153+
Path.Build.root |> Path.build |> Path.to_absolute_filename |> Path.External.of_string
154+
in
155+
let dev_tools_path = Path.External.relative external_root ".dev-tools.locks" in
152156
let dev_tool_segment = dev_tool_to_path_segment dev_tool in
153-
Path.Source.append_local dev_tools_path dev_tool_segment
157+
Path.External.append_local dev_tools_path dev_tool_segment
154158
;;
155159

160+
(* This function returns the lock dir location where the build system can create
161+
the lock directory. This is where lock files should be loaded from and it
162+
is populated either by copy rules or the solver running. *)
156163
let dev_tool_lock_dir dev_tool =
157164
(* dev tools always live in default *)
158165
let ctx_name = Context_name.default |> Context_name.to_string in
@@ -239,20 +246,20 @@ let get ctx = get_with_path ctx >>| Result.map ~f:snd
239246
let get_exn ctx = get ctx >>| User_error.ok_exn
240247

241248
let of_dev_tool dev_tool =
242-
let source_path = dev_tool_source_lock_dir dev_tool in
243-
Load.load_exn (Path.source source_path)
249+
let path = dev_tool |> dev_tool_external_lock_dir |> Path.external_ in
250+
Load.load_exn path
244251
;;
245252

246253
let of_dev_tool_if_lock_dir_exists dev_tool =
247-
let source_path = dev_tool_source_lock_dir dev_tool in
254+
let path = dev_tool |> dev_tool_external_lock_dir |> Path.external_ in
248255
let exists =
249256
(* Note we use [Path.Untracked] here rather than [Fs_memo] because a tool's
250257
lockdir may be generated part way through a build. *)
251-
Path.Untracked.exists (Path.source source_path)
258+
Path.Untracked.exists path
252259
in
253260
if exists
254261
then
255-
let+ t = Load.load_exn (Path.source source_path) in
262+
let+ t = Load.load_exn path in
256263
Some t
257264
else Memo.return None
258265
;;

src/dune_rules/lock_dir.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ val default_path : Path.t
2121
val default_source_path : Path.Source.t
2222

2323
(** The location in the source tree where a dev tool lock dir is expected *)
24-
val dev_tool_source_lock_dir : Dune_pkg.Dev_tool.t -> Path.Source.t
24+
val dev_tool_external_lock_dir : Dune_pkg.Dev_tool.t -> Path.External.t
2525

2626
(** Returns the path to the lock_dir that will be used to lock the
2727
given dev tool *)

src/dune_rules/lock_rules.ml

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -411,8 +411,7 @@ let copy_lock_dir ~target ~lock_dir ~deps ~files =
411411
Action_builder.deps deps
412412
>>> (Path.Set.to_list_map files ~f:(fun src ->
413413
let dst =
414-
Path.drop_prefix_exn src ~prefix:(Path.source lock_dir)
415-
|> Path.Build.append_local target
414+
Path.drop_prefix_exn src ~prefix:lock_dir |> Path.Build.append_local target
416415
in
417416
Action.progn [ Action.mkdir (Path.Build.parent_exn dst); Action.copy src dst ])
418417
|> Action.concurrent
@@ -425,8 +424,40 @@ let copy_lock_dir ~target ~lock_dir ~deps ~files =
425424
~dirs:(Path.Build.Set.singleton target))
426425
;;
427426

427+
let scan_lock_directory =
428+
let rec scan dir =
429+
let open Memo.O in
430+
Fs_memo.dir_contents (Path.as_outside_build_dir_exn dir)
431+
>>= function
432+
| Error (ENOENT, _, _) -> Memo.return Path.Set.empty
433+
| Error unix_error ->
434+
User_error.raise
435+
[ Pp.textf "Failed to read directory %s:" (Path.to_string_maybe_quoted dir)
436+
; Unix_error.Detailed.pp unix_error
437+
]
438+
| Ok entries ->
439+
Fs_cache.Dir_contents.to_list entries
440+
|> Memo.parallel_map ~f:(fun (entry, kind) ->
441+
let path = Path.relative dir entry in
442+
match (kind : File_kind.t) with
443+
| S_REG -> Memo.return (Path.Set.singleton path)
444+
| S_DIR -> scan path
445+
| kind ->
446+
User_error.raise
447+
[ Pp.textf
448+
"Lock directory contains file %S with unsupported kind %S"
449+
(Path.to_string_maybe_quoted path)
450+
(File_kind.to_string kind)
451+
])
452+
>>| Path.Set.union_all
453+
in
454+
fun lock_dir_path ->
455+
let+ files = scan lock_dir_path in
456+
Dep.Set.of_source_files ~files ~empty_directories:Path.Set.empty, files
457+
;;
458+
428459
let setup_copy_rules ~dir:target ~lock_dir =
429-
let+ deps, files = Source_deps.files (Path.source lock_dir) in
460+
let+ deps, files = scan_lock_directory lock_dir in
430461
let directory_targets, rules =
431462
match Path.Set.is_empty files with
432463
| true -> Path.Build.Map.empty, Rules.empty
@@ -452,15 +483,15 @@ let setup_lock_rules_with_source (workspace : Workspace.t) ~dir ~lock_dir =
452483
match source with
453484
| `Source_tree lock_dir ->
454485
let dir = Path.Build.append_source dir lock_dir in
455-
setup_copy_rules ~dir ~lock_dir
486+
setup_copy_rules ~dir ~lock_dir:(Path.source lock_dir)
456487
| `Generated -> Memo.return (setup_lock_rules ~dir ~lock_dir)
457488
;;
458489

459490
let setup_dev_tool_lock_rules ~dir dev_tool =
460491
let package_name = Dev_tool.package_name dev_tool in
461492
let dev_tool_name = Dune_lang.Package_name.to_string package_name in
462493
let dir = Path.Build.relative dir dev_tool_name in
463-
let lock_dir = Lock_dir.dev_tool_source_lock_dir dev_tool in
494+
let lock_dir = dev_tool |> Lock_dir.dev_tool_external_lock_dir |> Path.external_ in
464495
setup_copy_rules ~dir ~lock_dir
465496
;;
466497

0 commit comments

Comments
 (0)