Skip to content

Commit a4a2703

Browse files
committed
Network caps to track network access
Adds a [Network_cap.t] type which must be passed to the low-level functions which require network access, and should only be created at the "edge", either in a command or a rule. This will make it harder to accidentally add a requirement on network access to a code path that previously did not require network access, which will become important for maintaining an offline mode for Dune where it avoids updating package repositories and downloading files where possible. Signed-off-by: Stephen Sherratt <[email protected]>
1 parent d8b90bb commit a4a2703

38 files changed

+292
-124
lines changed

bin/fmt.ml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ let man =
1313
]
1414
;;
1515

16-
let lock_ocamlformat () =
16+
let lock_ocamlformat network_cap =
1717
if Lazy.force Lock_dev_tool.is_enabled
1818
then
1919
(* Note that generating the ocamlformat lockdir here means
@@ -22,14 +22,19 @@ let lock_ocamlformat () =
2222
this logic remain outside of `dune build`, as `dune
2323
build` is intended to only build targets, and generating
2424
a lockdir is not building a target. *)
25-
Lock_dev_tool.lock_dev_tool Ocamlformat |> Memo.run
25+
Lock_dev_tool.lock_dev_tool Ocamlformat network_cap |> Memo.run
2626
else Fiber.return ()
2727
;;
2828

2929
let run_fmt_command ~common ~config ~preview builder =
3030
let open Fiber.O in
3131
let once () =
32-
let* () = lock_ocamlformat () in
32+
let network_cap =
33+
Dune_pkg.Network_cap.create
34+
~reason_for_network_access:
35+
"Need to download package repositories to solve dependecies of ocamlformat."
36+
in
37+
let* () = lock_ocamlformat network_cap in
3338
let request (setup : Import.Main.build_system) =
3439
let dir = Path.(relative root) (Common.prefix_target common ".") in
3540
Alias.in_dir ~name:Dune_rules.Alias.fmt ~recursive:true ~contexts:setup.contexts dir

bin/lock_dev_tool.ml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ let make_local_package_wrapping_dev_tool ~dev_tool ~dev_tool_version ~extra_depe
6666
}
6767
;;
6868

69-
let solve ~dev_tool ~local_packages =
69+
let solve ~dev_tool ~local_packages network_cap =
7070
let open Memo.O in
7171
let* solver_env_from_current_system =
7272
Pkg.Pkg_common.poll_solver_env_from_current_system ()
@@ -91,6 +91,7 @@ let solve ~dev_tool ~local_packages =
9191
~lock_dirs:[ lock_dir ]
9292
~print_perf_stats:false
9393
~portable_lock_dir:false
94+
network_cap
9495
;;
9596

9697
let compiler_package_name = Package_name.of_string "ocaml"
@@ -236,7 +237,7 @@ let lockdir_status dev_tool =
236237
dev tool [dev_tool]. If [version] is [Some v] then version [v] of the tool
237238
will be chosen by the solver. Otherwise the solver is free to choose the
238239
appropriate version of the tool to install. *)
239-
let lock_dev_tool_at_version dev_tool version =
240+
let lock_dev_tool_at_version dev_tool version network_cap =
240241
let open Memo.O in
241242
let* need_to_solve =
242243
lockdir_status dev_tool
@@ -289,7 +290,7 @@ let lock_dev_tool_at_version dev_tool version =
289290
~extra_dependencies
290291
in
291292
let local_packages = Package_name.Map.singleton local_pkg.name local_pkg in
292-
solve ~dev_tool ~local_packages
293+
solve ~dev_tool ~local_packages network_cap
293294
else Memo.return ()
294295
;;
295296

bin/lock_dev_tool.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
open Import
22

33
val is_enabled : bool Lazy.t
4-
val lock_dev_tool : Dune_pkg.Dev_tool.t -> unit Memo.t
4+
val lock_dev_tool : Dune_pkg.Dev_tool.t -> Dune_pkg.Network_cap.t -> unit Memo.t

bin/ocaml/doc.ml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ let man =
1313

1414
let info = Cmd.info "doc" ~doc ~man
1515

16-
let lock_odoc_if_dev_tool_enabled () =
16+
let lock_odoc_if_dev_tool_enabled network_cap =
1717
match Lazy.force Lock_dev_tool.is_enabled with
1818
| false -> Action_builder.return ()
19-
| true -> Action_builder.of_memo (Lock_dev_tool.lock_dev_tool Odoc)
19+
| true -> Action_builder.of_memo (Lock_dev_tool.lock_dev_tool Odoc network_cap)
2020
;;
2121

2222
let term =
@@ -25,7 +25,12 @@ let term =
2525
let request (setup : Main.build_system) =
2626
let dir = Path.(relative root) (Common.prefix_target common ".") in
2727
let open Action_builder.O in
28-
let* () = lock_odoc_if_dev_tool_enabled () in
28+
let network_cap =
29+
Dune_pkg.Network_cap.create
30+
~reason_for_network_access:
31+
"Need to download package repositories to solve dependecies of odoc."
32+
in
33+
let* () = lock_odoc_if_dev_tool_enabled network_cap in
2934
let+ () =
3035
Alias.in_dir ~name:Dune_rules.Alias.doc ~recursive:true ~contexts:setup.contexts dir
3136
|> Alias.request

bin/ocaml/utop.ml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ let man =
1313
let man_xrefs = [ `Cmd "top" ]
1414
let info = Cmd.info "utop" ~man_xrefs ~doc ~man
1515

16-
let lock_utop_if_dev_tool_enabled () =
16+
let lock_utop_if_dev_tool_enabled network_cap =
1717
match Lazy.force Lock_dev_tool.is_enabled with
1818
| false -> Memo.return ()
19-
| true -> Lock_dev_tool.lock_dev_tool Utop
19+
| true -> Lock_dev_tool.lock_dev_tool Utop network_cap
2020
;;
2121

2222
let term =
@@ -47,12 +47,17 @@ let term =
4747
in
4848
let utop_exe = utop_target_path Utop.utop_exe in
4949
let utop_findlib_conf = utop_target_path Utop.utop_findlib_conf in
50+
let network_cap =
51+
Dune_pkg.Network_cap.create
52+
~reason_for_network_access:
53+
"Need to download package repositories to solve dependecies of utop."
54+
in
5055
let* () =
5156
(* Calling [Build_system.file_exists] has the side effect of checking
5257
and memoizing whether or not the utop dev tool lockdir exists.
5358
thus if we generate the lockdir any later than this point, dune
5459
will not observe the fact that it now exists. *)
55-
lock_utop_if_dev_tool_enabled ()
60+
lock_utop_if_dev_tool_enabled network_cap
5661
in
5762
Build_system.file_exists utop_exe
5863
>>= function

bin/pkg/lock.ml

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ let solve_lock_dir
302302
solver_env_from_current_system
303303
lock_dir_path
304304
progress_state
305+
network_cap
305306
=
306307
let open Fiber.O in
307308
let lock_dir = Workspace.find_lock_dir workspace lock_dir_path in
@@ -347,8 +348,9 @@ let solve_lock_dir
347348
Dune_pkg.Opam_repo.resolve_repositories
348349
~available_repos:repo_map
349350
~repositories:(repositories_of_lock_dir workspace ~lock_dir_path)
351+
network_cap
350352
in
351-
let* pins = resolve_project_pins project_pins in
353+
let* pins = resolve_project_pins project_pins network_cap in
352354
let time_solve_start = Unix.gettimeofday () in
353355
progress_state := Some Progress_indicator.Per_lockdir.State.Solving;
354356
let* result =
@@ -428,7 +430,9 @@ let solve_lock_dir
428430
~maybe_unsolved_platforms_message)
429431
in
430432
progress_state := None;
431-
let+ lock_dir = Lock_dir.compute_missing_checksums ~pinned_packages lock_dir in
433+
let+ lock_dir =
434+
Lock_dir.compute_missing_checksums ~pinned_packages lock_dir network_cap
435+
in
432436
Ok
433437
( Lock_dir.Write_disk.prepare ~portable_lock_dir ~lock_dir_path ~files lock_dir
434438
, summary_message )
@@ -443,6 +447,7 @@ let solve
443447
~lock_dirs
444448
~print_perf_stats
445449
~portable_lock_dir
450+
network_cap
446451
=
447452
let open Fiber.O in
448453
(* a list of thunks that will perform all the file IO side
@@ -469,7 +474,8 @@ let solve
469474
version_preference
470475
solver_env_from_current_system
471476
lockdir_path
472-
state))
477+
state
478+
network_cap))
473479
in
474480
List.partition_map result ~f:Result.to_either
475481
in
@@ -511,7 +517,13 @@ let project_pins =
511517
Pin.DB.combine_exn acc pins)
512518
;;
513519

514-
let lock ~version_preference ~lock_dirs_arg ~print_perf_stats ~portable_lock_dir =
520+
let lock
521+
~version_preference
522+
~lock_dirs_arg
523+
~print_perf_stats
524+
~portable_lock_dir
525+
network_cap
526+
=
515527
let open Fiber.O in
516528
let* solver_env_from_current_system =
517529
poll_solver_env_from_current_system () >>| Option.some
@@ -537,6 +549,7 @@ let lock ~version_preference ~lock_dirs_arg ~print_perf_stats ~portable_lock_dir
537549
~lock_dirs
538550
~print_perf_stats
539551
~portable_lock_dir
552+
network_cap
540553
;;
541554

542555
let term =
@@ -547,6 +560,12 @@ let term =
547560
and+ print_perf_stats = Arg.(value & flag & info [ "print-perf-stats" ] ~doc:None) in
548561
let builder = Common.Builder.forbid_builds builder in
549562
let common, config = Common.init builder in
563+
let network_cap =
564+
Dune_pkg.Network_cap.create
565+
~reason_for_network_access:
566+
"Locking dependencies requires network access because it needs to download \
567+
package repositories containing metadata in order to solve dependencies."
568+
in
550569
Scheduler.go_with_rpc_server ~common ~config (fun () ->
551570
let open Fiber.O in
552571
Pkg_common.check_pkg_management_enabled ()
@@ -556,7 +575,12 @@ let term =
556575
| `Enabled -> true
557576
| `Disabled -> false
558577
in
559-
lock ~version_preference ~lock_dirs_arg ~print_perf_stats ~portable_lock_dir)
578+
lock
579+
~version_preference
580+
~lock_dirs_arg
581+
~print_perf_stats
582+
~portable_lock_dir
583+
network_cap)
560584
;;
561585

562586
let info =

bin/pkg/lock.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ val solve
99
-> lock_dirs:Path.t list
1010
-> print_perf_stats:bool
1111
-> portable_lock_dir:bool
12+
-> Dune_pkg.Network_cap.t
1213
-> unit Fiber.t
1314

1415
(** Command to create lock directory *)

bin/pkg/outdated.ml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
open Import
22
open Pkg_common
33

4-
let find_outdated_packages ~transitive ~lock_dirs_arg () =
4+
let find_outdated_packages ~transitive ~lock_dirs_arg network_cap () =
55
let open Fiber.O in
66
let+ pps, not_founds =
77
let* workspace = Memo.run (Workspace.workspace ()) in
@@ -13,6 +13,7 @@ let find_outdated_packages ~transitive ~lock_dirs_arg () =
1313
Dune_pkg.Opam_repo.resolve_repositories
1414
~available_repos:(repositories_of_workspace workspace)
1515
~repositories:(repositories_of_lock_dir workspace ~lock_dir_path)
16+
network_cap
1617
and+ local_packages = Memo.run find_local_packages
1718
and+ platform = solver_env_from_system_and_context ~lock_dir_path in
1819
let lock_dir = Dune_pkg.Lock_dir.read_disk_exn lock_dir_path in
@@ -76,10 +77,16 @@ let term =
7677
and+ lock_dirs_arg = Pkg_common.Lock_dirs_arg.term in
7778
let builder = Common.Builder.forbid_builds builder in
7879
let common, config = Common.init builder in
80+
let network_cap =
81+
Dune_pkg.Network_cap.create
82+
~reason_for_network_access:
83+
"Need to download package repositories to check whether the current package \
84+
solution is out of date."
85+
in
7986
Scheduler.go_with_rpc_server ~common ~config (fun () ->
8087
let open Fiber.O in
8188
Pkg_common.check_pkg_management_enabled ()
82-
>>> find_outdated_packages ~transitive ~lock_dirs_arg ())
89+
>>> find_outdated_packages ~transitive ~lock_dirs_arg network_cap ())
8390
;;
8491

8592
let info =

bin/pkg/search.ml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ let packages_in_repo ~query repo =
2626
Fiber.return (name, OpamPackage.Version.Map.max_binding_opt versions))
2727
;;
2828

29-
let search_packages ~query () =
29+
let search_packages ~query network_cap () =
3030
let open Fiber.O in
3131
let* workspace = Memo.run (Workspace.workspace ()) in
3232
let* lock_dir_path = Dune_rules.Lock_dir.get_path Context_name.default |> Memo.run in
@@ -39,6 +39,7 @@ let search_packages ~query () =
3939
Dune_pkg.Opam_repo.resolve_repositories
4040
~available_repos:(Pkg_common.repositories_of_workspace workspace)
4141
~repositories:(Pkg_common.repositories_of_lock_dir workspace ~lock_dir_path)
42+
network_cap
4243
in
4344
let re = Option.map ~f:(fun q -> Re.str q |> Re.no_case |> Re.compile) query in
4445
let* filtered = Fiber.parallel_map ~f:(packages_in_repo ~query:re) repos in
@@ -111,9 +112,14 @@ let term =
111112
and+ query = Arg.(value & pos 0 (some string) None & info [] ~docv:"QUERY" ~doc:None) in
112113
let builder = Common.Builder.forbid_builds builder in
113114
let common, config = Common.init builder in
115+
let network_cap =
116+
Dune_pkg.Network_cap.create
117+
~reason_for_network_access:
118+
"Package repositories need to be downloaded in order to search them."
119+
in
114120
Scheduler.go_with_rpc_server ~common ~config (fun () ->
115121
let open Fiber.O in
116-
Pkg_common.check_pkg_management_enabled () >>> search_packages ~query ())
122+
Pkg_common.check_pkg_management_enabled () >>> search_packages ~query network_cap ())
117123
;;
118124

119125
let info =

bin/tools/tools_common.ml

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@ let dev_tool_build_target dev_tool =
1919
(Path.to_string (dev_tool_exe_path dev_tool)))
2020
;;
2121

22-
let build_dev_tool_directly common dev_tool =
22+
let build_dev_tool_directly common dev_tool network_cap =
2323
let open Fiber.O in
2424
let+ result =
2525
Build.run_build_system ~common ~request:(fun _build_system ->
2626
let open Action_builder.O in
27-
let* () = dev_tool |> Lock_dev_tool.lock_dev_tool |> Action_builder.of_memo in
27+
let* () =
28+
Lock_dev_tool.lock_dev_tool dev_tool network_cap |> Action_builder.of_memo
29+
in
2830
(* Make sure the tool's lockdir is generated before building the tool. *)
2931
Action_builder.path (dev_tool_exe_path dev_tool))
3032
in
@@ -47,16 +49,16 @@ let build_dev_tool_via_rpc builder lock_held_by dev_tool =
4749
>>| Rpc.Rpc_common.wrap_build_outcome_exn ~print_on_success:false
4850
;;
4951

50-
let lock_and_build_dev_tool ~common ~config builder dev_tool =
52+
let lock_and_build_dev_tool ~common ~config builder dev_tool network_cap =
5153
let open Fiber.O in
5254
match Dune_util.Global_lock.lock ~timeout:None with
5355
| Error lock_held_by ->
5456
Scheduler.go_without_rpc_server ~common ~config (fun () ->
55-
let* () = Lock_dev_tool.lock_dev_tool dev_tool |> Memo.run in
57+
let* () = Lock_dev_tool.lock_dev_tool dev_tool network_cap |> Memo.run in
5658
build_dev_tool_via_rpc builder lock_held_by dev_tool)
5759
| Ok () ->
5860
Scheduler.go_with_rpc_server ~common ~config (fun () ->
59-
build_dev_tool_directly common dev_tool)
61+
build_dev_tool_directly common dev_tool network_cap)
6062
;;
6163

6264
let run_dev_tool workspace_root dev_tool ~args =
@@ -71,8 +73,8 @@ let run_dev_tool workspace_root dev_tool ~args =
7173
restore_cwd_and_execve workspace_root exe_path_string args env
7274
;;
7375

74-
let lock_build_and_run_dev_tool ~common ~config builder dev_tool ~args =
75-
lock_and_build_dev_tool ~common ~config builder dev_tool;
76+
let lock_build_and_run_dev_tool ~common ~config builder dev_tool ~args network_cap =
77+
lock_and_build_dev_tool ~common ~config builder dev_tool network_cap;
7678
run_dev_tool (Common.root common) dev_tool ~args
7779
;;
7880

@@ -113,10 +115,18 @@ let which_command dev_tool =
113115

114116
let install_command dev_tool =
115117
let exe_name = Pkg_dev_tool.exe_name dev_tool in
118+
let network_cap =
119+
Dune_pkg.Network_cap.create
120+
~reason_for_network_access:
121+
(sprintf
122+
"Fetching package metadata to solve dependencies and downloading dependencies \
123+
of %s."
124+
exe_name)
125+
in
116126
let term =
117127
let+ builder = Common.Builder.term in
118128
let common, config = Common.init builder in
119-
lock_and_build_dev_tool ~common ~config builder dev_tool
129+
lock_and_build_dev_tool ~common ~config builder dev_tool network_cap
120130
in
121131
let info =
122132
let doc = sprintf "Install %s as a dev tool" exe_name in
@@ -127,12 +137,20 @@ let install_command dev_tool =
127137

128138
let exec_command dev_tool =
129139
let exe_name = Pkg_dev_tool.exe_name dev_tool in
140+
let network_cap =
141+
Dune_pkg.Network_cap.create
142+
~reason_for_network_access:
143+
(sprintf
144+
"Fetching package metadata to solve dependencies and downloading dependencies \
145+
of %s."
146+
exe_name)
147+
in
130148
let term =
131149
let+ builder = Common.Builder.term
132150
(* CR-someday Alizter: document this option *)
133151
and+ args = Arg.(value & pos_all string [] (info [] ~docv:"ARGS" ~doc:None)) in
134152
let common, config = Common.init builder in
135-
lock_build_and_run_dev_tool ~common ~config builder dev_tool ~args
153+
lock_build_and_run_dev_tool ~common ~config builder dev_tool ~args network_cap
136154
in
137155
let info =
138156
let doc =

0 commit comments

Comments
 (0)