Skip to content

Commit

Permalink
Merge pull request #586 from SGrondin/process-exit-success
Browse files Browse the repository at this point in the history
Add `Process.run ?is_success` to control definition of success
  • Loading branch information
talex5 authored Jul 20, 2023
2 parents 3fe5755 + 7bb7c2b commit e10e176
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 8 deletions.
12 changes: 6 additions & 6 deletions lib_eio/process.ml
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ end
let pid proc = proc#pid
let await proc = proc#await

let await_exn proc =
let await_exn ?(is_success = Int.equal 0) proc =
match proc#await with
| `Exited 0 -> ()
| `Exited code when is_success code -> ()
| status -> raise (err (Child_error status))

let signal proc = proc#signal
Expand Down Expand Up @@ -84,26 +84,26 @@ let spawn ~sw (t:#mgr) ?cwd ?stdin ?stdout ?stderr ?env ?executable args =
?stdout:(stdout :> Flow.sink option)
?stderr:(stderr :> Flow.sink option)

let run (t:#mgr) ?cwd ?stdin ?stdout ?stderr ?env ?executable args =
let run (t:#mgr) ?cwd ?stdin ?stdout ?stderr ?(is_success = Int.equal 0) ?env ?executable args =
Switch.run @@ fun sw ->
let child = spawn ~sw t ?cwd ?stdin ?stdout ?stderr ?env ?executable args in
match await child with
| `Exited 0 -> ()
| `Exited code when is_success code -> ()
| status ->
let ex = err (Child_error status) in
raise (Exn.add_context ex "running command: %a" pp_args args)

let pipe ~sw (t:#mgr) = t#pipe ~sw

let parse_out (t:#mgr) parse ?cwd ?stdin ?stderr ?env ?executable args =
let parse_out (t:#mgr) parse ?cwd ?stdin ?stderr ?is_success ?env ?executable args =
Switch.run @@ fun sw ->
let r, w = pipe t ~sw in
try
let child = spawn ~sw t ?cwd ?stdin ~stdout:w ?stderr ?env ?executable args in
Flow.close w;
let output = Buf_read.parse_exn parse r ~max_size:max_int in
Flow.close r;
await_exn child;
await_exn ?is_success child;
output
with Exn.Io _ as ex ->
let bt = Printexc.get_raw_backtrace () in
Expand Down
13 changes: 11 additions & 2 deletions lib_eio/process.mli
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,12 @@ val pid : #t -> int
val await : #t -> exit_status
(** [await t] waits for process [t] to exit and then reports the status. *)

val await_exn : #t -> unit
(** Like {! await} except an exception is raised if the status is not [`Exited 0]. *)
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].
Expand Down Expand Up @@ -113,12 +117,16 @@ val run :
?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 :
Expand All @@ -127,6 +135,7 @@ val parse_out :
?cwd:#Fs.dir Path.t ->
?stdin:#Flow.source ->
?stderr:#Flow.sink ->
?is_success:(int -> bool) ->
?env:string array ->
?executable:string ->
string list -> 'a
Expand Down
22 changes: 22 additions & 0 deletions tests/process.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,28 @@ Eio.Io Process Child_error Exited (code 3),
running command: bash -c "exit 3" "" foo
```

Exit code success can be determined by is_success (Process.run):

```ocaml
# run @@ fun mgr env ->
Process.run ~is_success:(Int.equal 3) mgr ["bash"; "-c"; "exit 3"];;
- : unit = ()
# run @@ fun mgr env ->
Process.run ~is_success:(Int.equal 3) mgr ["bash"; "-c"; "exit 0"];;
Exception:
Eio.Io Process Child_error Exited (code 0),
running command: bash -c "exit 0"
```

Exit code success can be determined by is_success (Process.parse_out):

```ocaml
# run @@ fun mgr env ->
Process.parse_out ~is_success:(Int.equal 5) mgr Eio.Buf_read.line ["sh"; "-c"; "echo 123; exit 5"];;
- : string = "123"
```

The default environment:

```ocaml
Expand Down

0 comments on commit e10e176

Please sign in to comment.