1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
|
(** Example:
{[
# Eio_main.run @@ fun env ->
let proc_mgr = Eio.Stdenv.process_mgr env in
Eio.Process.parse_out proc_mgr Eio.Buf_read.line ["echo"; "hello"]
]}
*)
open Std
(** {2 Status and error types} *)
type exit_status = [
| `Exited of int (** Process exited with the given return code. *)
| `Signaled of int (** Process was killed by the given signal. *)
]
type status = [
| exit_status
| `Stopped of int (** Process was stopped (paused) by the given signal. *)
]
val pp_status : [< status] Fmt.t
type error =
| Executable_not_found of string (** The requested executable does not exist. *)
| Child_error of exit_status (** The process exited with an error status. *)
type Exn.err += E of error
val err : error -> exn
(** [err e] is [Eio.Exn.create (E e)] *)
val pp_args : string list Fmt.t
(** Formats a list of arguments, quoting any that might cause confusion to the reader.
This is intended for use in error messages and logging.*)
(** {2 Types} *)
type 'tag ty = [ `Process | `Platform of 'tag ]
type 'a t = ([> [> `Generic] ty] as 'a) r
(** A process. *)
type 'tag mgr_ty = [ `Process_mgr | `Platform of 'tag ]
type 'a mgr = 'a r
constraint 'a = [> [> `Generic] mgr_ty]
(** A process manager capable of spawning new processes. *)
(** {2 Processes} *)
val pid : _ t -> int
(** [pid t] is the process ID of [t]. *)
val await : _ t -> exit_status
(** [await t] waits for process [t] to exit and then reports the status. *)
val await_exn : ?is_success:(int -> bool) -> _ t -> unit
(** Like {! await} except an exception is raised if does not return a successful
exit status.
@param is_success Used to determine if an exit code is successful.
Default is [Int.equal 0]. *)
val signal : _ t -> int -> unit
(** [signal t i] sends the signal [i] to process [t].
If the process has already exited then this does nothing
(it will not signal a different process, even if the PID has been reused).
See {!Sys} for the signal numbers. *)
val spawn :
sw:Switch.t ->
[> 'tag mgr_ty] r ->
?cwd:Fs.dir_ty Path.t ->
?stdin:_ Flow.source ->
?stdout:_ Flow.sink ->
?stderr:_ Flow.sink ->
?env:string array ->
?executable:string ->
string list -> 'tag ty r
(** [spawn ~sw mgr args] creates a new child process that is connected to the switch [sw].
The child process will be sent {! Sys.sigkill} when the switch is released.
If the flows [stdin], [stdout] and [stderr] are not backed by file descriptors then
this also creates pipes and spawns fibers to copy the data as necessary.
If you need more control over file descriptors, see {!Eio_unix.Process}.
@param cwd The current working directory of the process (default: same as parent process).
@param stdin The flow to attach to the process's standard input (default: same as parent process).
@param stdout A flow that the process's standard output goes to (default: same as parent process).
@param stderr A flow that the process's standard error goes to (default: same as parent process).
@param env The environment for the process (default: same as parent process).
@param executable The path of the executable to run.
If not given then the first item in [args] is used,
searching $PATH for it if necessary. *)
val run :
_ mgr ->
?cwd:_ Path.t ->
?stdin:_ Flow.source ->
?stdout:_ Flow.sink ->
?stderr:_ Flow.sink ->
?is_success:(int -> bool) ->
?env:string array ->
?executable:string ->
string list -> unit
(** [run] does {!spawn} followed by {!await_exn}, with the advantage that if the process fails then
the error message includes the command that failed.
When [is_success] is provided, it is called with the exit code to determine whether it indicates success or failure.
Without [is_success], success requires the process to return an exit code of 0.
Note: If [spawn] needed to create extra fibers to copy [stdin], etc, then it also waits for those to finish. *)
val parse_out :
_ mgr ->
'a Buf_read.parser ->
?cwd:_ Path.t ->
?stdin:_ Flow.source ->
?stderr:_ Flow.sink ->
?is_success:(int -> bool) ->
?env:string array ->
?executable:string ->
string list -> 'a
(** [parse_out mgr parser args] runs [args] and parses the child's stdout with [parser].
It also waits for the process to finish and checks its exit status is zero.
Note that [parser] must consume the entire output of the process (like {!Buf_read.parse}).
To return all the output as a string, use {!Buf_read.take_all} as the parser.
This is a convenience wrapper around {!run},
and the optional arguments have the same meanings. *)
(** {2 Pipes} *)
val pipe : sw:Switch.t -> _ mgr -> [Flow.source_ty | Resource.close_ty] r * [Flow.sink_ty | Resource.close_ty] r
(** [pipe ~sw mgr] creates a pipe backed by the OS.
The flows can be used by {!spawn} without the need for extra fibers to copy the data.
This can be used to connect multiple processes together. *)
(** {2 Provider Interface} *)
module Pi : sig
module type PROCESS = sig
type t
type tag
val pid : t -> int
val await : t -> exit_status
val signal : t -> int -> unit
end
type (_, _, _) Resource.pi +=
| Process : ('t, (module PROCESS with type t = 't and type tag = 'tag), [> 'tag ty]) Resource.pi
val process :
(module PROCESS with type t = 't and type tag = 'tag) ->
('t, 'tag ty) Resource.handler
module type MGR = sig
type tag
type t
val pipe :
t ->
sw:Switch.t ->
[Flow.source_ty | Resource.close_ty] r * [Flow.sink_ty | Resource.close_ty] r
val spawn :
t ->
sw:Switch.t ->
?cwd:Fs.dir_ty Path.t ->
?stdin:Flow.source_ty r ->
?stdout:Flow.sink_ty r ->
?stderr:Flow.sink_ty r ->
?env:string array ->
?executable:string ->
string list ->
tag ty r
end
type (_, _, _) Resource.pi +=
| Mgr : ('t, (module MGR with type t = 't and type tag = 'tag), [> 'tag mgr_ty]) Resource.pi
val mgr :
(module MGR with type t = 't and type tag = 'tag) ->
('t, 'tag mgr_ty) Resource.handler
end
|