@@ -71,6 +71,134 @@ let rpc server =
7171 }
7272;;
7373
74+ let with_action_runner_worker ~(common : Common.t ) f =
75+ match Common. action_runner common with
76+ | None -> f ()
77+ | Some action_runner ->
78+ let open Fiber.O in
79+ let server =
80+ match Common. rpc common with
81+ | `Allow server -> server
82+ | `Forbid_builds -> Code_error. raise " action runners require the dune RPC server" []
83+ in
84+ let find_in_path_exn prog =
85+ match Bin. which ~path: (Env_path. path Env. initial) prog with
86+ | Some path -> path
87+ | None -> User_error. raise [ Pp. textf " unable to find %s in PATH" prog ]
88+ in
89+ let has_directory_component prog =
90+ String. exists prog ~f: (function
91+ | '/' | '\\' -> true
92+ | _ -> false )
93+ in
94+ let dune_prog =
95+ let prog = Sys. executable_name in
96+ if Filename. is_relative prog && not (has_directory_component prog)
97+ then find_in_path_exn prog
98+ else Path. of_filename_relative_to_initial_cwd prog
99+ in
100+ let jobs = Int. to_string ! Dune_rules.Clflags. concurrency in
101+ let env =
102+ Env. initial
103+ |> Env. add ~var: " DUNE_JOBS" ~value: jobs
104+ |> Env. add ~var: " DUNE_BUILD_DIR" ~value: (Path.Build. to_string Path.Build. root)
105+ |> Env. to_unix
106+ |> Spawn.Env. of_list
107+ in
108+ let where = Dune_rpc_impl.Server. listening_address server in
109+ let monitor_pool = Fiber.Pool. create () in
110+ let started_worker = ref (None : Pid.t option ) in
111+ let worker_command runner =
112+ let worker_argv =
113+ [ Path. to_string dune_prog
114+ ; " internal"
115+ ; " action-runner"
116+ ; " start"
117+ ; Dune_engine.Action_runner.Name. to_string (Dune_engine.Action_runner. name runner)
118+ ; Dune_rpc.Where. to_string where
119+ ]
120+ in
121+ if Common. sandbox_actions common
122+ then (
123+ let bwrap =
124+ match Platform.OS. value with
125+ | Linux -> find_in_path_exn " bwrap"
126+ | _ ->
127+ User_error. raise
128+ [ Pp. text " --sandbox-actions is currently only supported on Linux" ]
129+ in
130+ let cwd = Path. to_absolute_filename Path. root in
131+ let shared_cache_bindings =
132+ let build_cache_dir = Lazy. force Dune_cache.Layout. build_cache_dir in
133+ Path. mkdir_p build_cache_dir;
134+ let build_cache_dir = Path. to_string build_cache_dir in
135+ [ " --ro-bind" ; build_cache_dir; build_cache_dir ]
136+ in
137+ ( Path. to_string bwrap
138+ , [ Path. to_string bwrap; " --die-with-parent" ; " --bind" ; " /" ; " /" ]
139+ @ shared_cache_bindings
140+ @ [ " --proc" ; " /proc" ; " --dev" ; " /dev" ; " --chdir" ; cwd; " --" ]
141+ @ worker_argv ))
142+ else Path. to_string dune_prog, worker_argv
143+ in
144+ let close_trace_fd trace_fd = Option. iter trace_fd ~f: Fd. close in
145+ let start_worker ~runner =
146+ let * () = Root.Rpc.Global. ensure_ready () in
147+ let prog, argv = worker_command runner in
148+ let trace_fd = Dune_trace. duplicate_global_fd () in
149+ let argv =
150+ argv
151+ @
152+ match trace_fd with
153+ | None -> []
154+ | Some fd ->
155+ let fd_arg : int = Obj. magic (Fd. unsafe_to_unix_file_descr fd) in
156+ [ " --trace-fd" ; Int. to_string fd_arg ]
157+ in
158+ let pid =
159+ match Spawn. spawn ~env ~prog ~argv ~setpgid: Spawn.Pgid. new_process_group () with
160+ | pid ->
161+ close_trace_fd trace_fd;
162+ let pid = Pid. of_int pid in
163+ Dune_trace. emit Action (fun () ->
164+ Dune_trace.Event.Action. runner_spawn
165+ ~name:
166+ (Dune_engine.Action_runner.Name. to_string
167+ (Dune_engine.Action_runner. name runner))
168+ ~pid );
169+ pid
170+ | exception exn ->
171+ close_trace_fd trace_fd;
172+ raise exn
173+ in
174+ started_worker := Some pid;
175+ Fiber.Pool. task monitor_pool ~f: (fun () ->
176+ let * _status = Scheduler. wait_for_process pid ~is_process_group_leader: true in
177+ let * () = Dune_engine.Action_runner. disconnect runner in
178+ (match ! started_worker with
179+ | Some current_pid when Pid. equal current_pid pid -> started_worker := None
180+ | None | Some _ -> () );
181+ Fiber. return () )
182+ in
183+ let terminate_worker pid =
184+ match Unix. kill (- Pid. to_int pid) Sys. sigterm with
185+ | () -> Fiber. return ()
186+ | exception Unix. Unix_error (Unix. ESRCH, _ , _ ) -> Fiber. return ()
187+ in
188+ Dune_engine.Action_runner. set_start action_runner start_worker;
189+ Fiber. fork_and_join_unit
190+ (fun () -> Fiber.Pool. run monitor_pool)
191+ (fun () ->
192+ Fiber. finalize f ~finally: (fun () ->
193+ let worker = ! started_worker in
194+ let * () =
195+ match worker with
196+ | None -> Fiber. return ()
197+ | Some pid -> terminate_worker pid
198+ in
199+ Fiber.Pool. close monitor_pool))
200+ ;;
201+
74202let no_build_no_rpc ~config :dune_config f =
75203 let config =
76204 Dune_config. for_scheduler dune_config ~print_ctrl_c_warning: true ~watch_exclusions: []
@@ -92,7 +220,10 @@ let go_without_rpc_server ~(common : Common.t) ~config:dune_config f =
92220let go_with_rpc_server ~common ~config f =
93221 let f =
94222 match Common. rpc common with
95- | `Allow server -> fun () -> Root.Rpc.Global. with_background_rpc (rpc server) f
223+ | `Allow server ->
224+ fun () ->
225+ Root.Rpc.Global. with_background_rpc (rpc server) (fun () ->
226+ with_action_runner_worker ~common f)
96227 | `Forbid_builds -> f
97228 in
98229 go_without_rpc_server ~common ~config f
@@ -119,7 +250,7 @@ let go_with_rpc_server_and_console_status_reporting
119250 Root.Rpc.Global. with_background_rpc server
120251 @@ fun () ->
121252 let * () = Root.Rpc.Global. ensure_ready () in
122- run ()
253+ with_action_runner_worker ~common run
123254 in
124255 Run. go
125256 config
0 commit comments