Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib_eio/eio.ml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ end
module Buf_write = Buf_write
module Net = Net
module Process = Process
module Vars = Vars
module Domain_manager = Domain_manager
module Time = Time
module File = File
Expand All @@ -35,6 +36,7 @@ module Stdenv = struct
let stderr (t : <stderr : _ Flow.sink; ..>) = t#stderr
let net (t : <net : _ Net.t; ..>) = t#net
let process_mgr (t : <process_mgr : _ Process.mgr; ..>) = t#process_mgr
let vars (t : <vars : _ Vars.t; ..>) = t#vars
let domain_mgr (t : <domain_mgr : _ Domain_manager.t; ..>) = t#domain_mgr
let clock (t : <clock : _ Time.clock; ..>) = t#clock
let mono_clock (t : <mono_clock : _ Time.Mono.t; ..>) = t#mono_clock
Expand Down
6 changes: 6 additions & 0 deletions lib_eio/eio.mli
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ module Fs = Fs
(** Managing child processes. *)
module Process = Process

(** Accessing environment variables *)
module Vars = Vars

(** {2 Time} *)

(** Clocks, time, sleeping and timeouts. *)
Expand Down Expand Up @@ -244,6 +247,9 @@ module Stdenv : sig
val process_mgr : <process_mgr : _ Process.mgr as 'a; ..> -> 'a
(** [process_mgr t] allows you to manage child processes. *)

val vars : <vars : _ Vars.t as 'a; ..> -> 'a
(** [vars t] allows you to access environment variables. *)

(** {1 Domains (using multiple CPU cores)}

To use this, see {!Domain_manager}.
Expand Down
4 changes: 3 additions & 1 deletion lib_eio/unix/eio_unix.ml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ module Stdenv = struct
net : [`Unix | `Generic] Eio.Net.ty r;
domain_mgr : Eio.Domain_manager.ty r;
process_mgr : Process.mgr_ty r;
vars : Eio.Vars.ty r;
clock : float Eio.Time.clock_ty r;
mono_clock : Eio.Time.Mono.ty r;
fs : Eio.Fs.dir_ty Eio.Path.t;
Expand All @@ -45,7 +46,7 @@ module Stdenv = struct

let override
?stdin ?stdout ?stderr ?net ?domain_mgr
?process_mgr ?clock ?mono_clock ?fs ?cwd
?process_mgr ?vars ?clock ?mono_clock ?fs ?cwd
?secure_random ?debug ?backend_id (env : <base; ..>) : base
=
object
Expand All @@ -55,6 +56,7 @@ module Stdenv = struct
method net = Option.value ~default:env#net net
method domain_mgr = Option.value ~default:env#domain_mgr domain_mgr
method process_mgr = Option.value ~default:env#process_mgr process_mgr
method vars = Option.value ~default:env#vars vars
method clock = Option.value ~default:env#clock clock
method mono_clock = Option.value ~default:env#mono_clock mono_clock
method fs = Option.value ~default:env#fs fs
Expand Down
4 changes: 4 additions & 0 deletions lib_eio/unix/eio_unix.mli
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ module Stdenv : sig
net : [`Unix | `Generic] Eio.Net.ty r;
domain_mgr : Eio.Domain_manager.ty r;
process_mgr : Process.mgr_ty r;
vars : Eio.Vars.ty r;
clock : float Eio.Time.clock_ty r;
mono_clock : Eio.Time.Mono.ty r;
fs : Eio.Fs.dir_ty Eio.Path.t;
Expand All @@ -114,6 +115,7 @@ module Stdenv : sig
?net:[ `Generic | `Unix ] Eio.Net.ty r ->
?domain_mgr:Eio.Domain_manager.ty r ->
?process_mgr:Process.mgr_ty r ->
?vars:Eio.Vars.ty r ->
?clock:float Eio.Time.clock_ty r ->
?mono_clock:Eio.Time.Mono.ty r ->
?fs:Eio.Fs.dir_ty Eio.Path.t ->
Expand Down Expand Up @@ -156,6 +158,8 @@ module Private : sig

val setsockopt : Fd.t -> 'a Eio.Net.Sockopt.t -> 'a -> unit
val getsockopt : Fd.t -> 'a Eio.Net.Sockopt.t -> 'a

val vars : Eio.Vars.ty r
end

module Pi = Pi
11 changes: 11 additions & 0 deletions lib_eio/unix/private.ml
Original file line number Diff line number Diff line change
Expand Up @@ -295,3 +295,14 @@ let getsockopt : type a. Fd.t -> a Eio.Net.Sockopt.t -> a = fun fd opt ->
| Net.Sockopt_float bo -> Unix.getsockopt_float fd bo
| _ -> raise (Eio.Net.err Invalid_option)
with Unix.Unix_error (code, name, arg) -> raise (Err.v code name arg)

module Vars = struct
type t = unit
let get_all () = Unix.environment () |> Eio.Process.Env.of_array
let get_opt () name =
try Some (Unix.getenv name) with Not_found -> None
end

let vars =
let handler = Eio.Vars.Pi.vars (module Vars) in
Eio.Resource.T ((), handler)
30 changes: 30 additions & 0 deletions lib_eio/vars.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
open Std

type ty = [ `Vars ]
type 'a t = ([> ty] as 'a) r

module Pi = struct
module type VARS = sig
type t

val get_all : t -> Process.Env.t
val get_opt : t -> string -> string option
end

type (_, _, _) Resource.pi +=
| Vars : ('t, (module VARS with type t = 't), [> ty ]) Resource.pi

let vars (type t) (module X : VARS with type t = t) =
Resource.handler [ H (Vars, (module X)) ]
end

let get_all t =
let (Resource.T (t, ops)) = t in
let module X = (val (Resource.get ops Pi.Vars)) in
X.get_all t

let get_opt t name =
let (Resource.T (t, ops)) = t in
let module X = (val (Resource.get ops Pi.Vars)) in
X.get_opt t name

24 changes: 24 additions & 0 deletions lib_eio/vars.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
open Std

type ty = [ `Vars ]
type 'a t = ([> ty] as 'a) r

(** {1 Accessing environment variables} *)

val get_all : _ t -> Process.Env.t
(** [get_all vars] gets the full list of environment variables. *)

val get_opt : _ t -> string -> string option
(** [get_opt vars name] will get the environment variable called [name].
Returns [None] if [name] does not exist. *)

module Pi : sig
module type VARS = sig
type t

val get_all : t -> Process.Env.t
val get_opt : t -> string -> string option
end

val vars : (module VARS with type t = 't) -> ('t, ty) Resource.handler
end
1 change: 1 addition & 0 deletions lib_eio_linux/eio_linux.ml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ let stdenv ~run_event_loop =
method stderr = Flow.stderr
method net = Net.v
method process_mgr = Process.mgr
method vars = Eio_unix.Private.vars
method domain_mgr = domain_mgr ~run_event_loop
method clock = Time.clock
method mono_clock = Time.mono_clock
Expand Down
17 changes: 10 additions & 7 deletions lib_eio_linux/tests/spawn.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ open Eio.Std

module Env = Eio.Process.Env
module Process = Eio_linux.Low_level.Process

let default_env = Unix.environment () |> Env.of_array
```

## Spawning processes
Expand All @@ -31,7 +29,8 @@ FOO=bar
Changing directory:

```ocaml
# Eio_linux.run @@ fun _env ->
# Eio_linux.run @@ fun env ->
let default_env = Eio.Stdenv.vars env |> Eio.Vars.get_all in
Switch.run @@ fun sw ->
let child = Process.spawn ~sw Process.Fork_action.[
chdir "/";
Expand All @@ -47,7 +46,8 @@ Changing directory:
Changing directory using a file descriptor:

```ocaml
# Eio_linux.run @@ fun _env ->
# Eio_linux.run @@ fun env ->
let default_env = Eio.Stdenv.vars env |> Eio.Vars.get_all in
Switch.run @@ fun sw ->
let root =
Eio_linux.Low_level.openat2 ~sw "/"
Expand All @@ -71,7 +71,8 @@ Changing directory using a file descriptor:
Exit status:

```ocaml
# Eio_linux.run @@ fun _env ->
# Eio_linux.run @@ fun env ->
let default_env = Eio.Stdenv.vars env |> Eio.Vars.get_all in
Switch.run @@ fun sw ->
let child = Process.spawn ~sw Process.Fork_action.[
execve "/usr/bin/env"
Expand All @@ -85,7 +86,8 @@ Exit status:
Failure starting child:

```ocaml
# Eio_linux.run @@ fun _env ->
# Eio_linux.run @@ fun env ->
let default_env = Eio.Stdenv.vars env |> Eio.Vars.get_all in
Switch.run @@ fun sw ->
Process.spawn ~sw Process.Fork_action.[
chdir "/idontexist";
Expand All @@ -99,7 +101,8 @@ Exception: Unix.Unix_error(Unix.ENOENT, "chdir", "")
Signalling a running child:

```ocaml
# Eio_linux.run @@ fun _env ->
# Eio_linux.run @@ fun env ->
let default_env = Eio.Stdenv.vars env |> Eio.Vars.get_all in
Switch.run @@ fun sw ->
let child =
Process.spawn ~sw Process.Fork_action.[
Expand Down
1 change: 1 addition & 0 deletions lib_eio_posix/eio_posix.ml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ let run main =
method clock = Time.clock
method mono_clock = Time.mono_clock
method net = Net.v
method vars = Eio_unix.Private.vars
method process_mgr = Process.mgr
method domain_mgr = Domain_mgr.v
method cwd = (Fs.cwd :> Eio.Fs.dir_ty Eio.Path.t)
Expand Down
23 changes: 14 additions & 9 deletions lib_eio_posix/test/spawn.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ open Eio.Std

module Env = Eio.Process.Env
module Process = Eio_posix.Low_level.Process

let default_env = Unix.environment () |> Env.of_array
```

## Spawning processes
Expand All @@ -31,7 +29,8 @@ FOO=bar
Changing directory:

```ocaml
# Eio_posix.run @@ fun _env ->
# Eio_posix.run @@ fun env ->
let default_env = Eio.Stdenv.vars env |> Eio.Vars.get_all in
Switch.run @@ fun sw ->
let child = Process.spawn ~sw Process.Fork_action.[
chdir "/";
Expand All @@ -47,7 +46,8 @@ Changing directory:
Changing directory using a file descriptor:

```ocaml
# Eio_posix.run @@ fun _env ->
# Eio_posix.run @@ fun env ->
let default_env = Eio.Stdenv.vars env |> Eio.Vars.get_all in
Switch.run @@ fun sw ->
let root = Eio_posix.Low_level.openat ~sw ~mode:0 Fs "/" Eio_posix.Low_level.Open_flags.(rdonly + directory) in
let child = Process.spawn ~sw Process.Fork_action.[
Expand All @@ -64,7 +64,8 @@ Changing directory using a file descriptor:
Exit status:

```ocaml
# Eio_posix.run @@ fun _env ->
# Eio_posix.run @@ fun env ->
let default_env = Eio.Stdenv.vars env |> Eio.Vars.get_all in
Switch.run @@ fun sw ->
let child = Process.spawn ~sw Process.Fork_action.[
execve "/usr/bin/env"
Expand All @@ -78,7 +79,8 @@ Exit status:
Failure starting child:

```ocaml
# Eio_posix.run @@ fun _env ->
# Eio_posix.run @@ fun env ->
let default_env = Eio.Stdenv.vars env |> Eio.Vars.get_all in
Switch.run @@ fun sw ->
Process.spawn ~sw Process.Fork_action.[
chdir "/idontexist";
Expand All @@ -92,7 +94,8 @@ Exception: Unix.Unix_error(Unix.ENOENT, "chdir", "")
Signalling a running child:

```ocaml
# Eio_posix.run @@ fun _env ->
# Eio_posix.run @@ fun env ->
let default_env = Eio.Stdenv.vars env |> Eio.Vars.get_all in
Switch.run @@ fun sw ->
let child =
Process.spawn ~sw Process.Fork_action.[
Expand Down Expand Up @@ -163,7 +166,8 @@ let read_all pipe =
Swapping FDs (note: plain sh can't handle multi-digit FDs!):

```ocaml
# Eio_posix.run @@ fun _env ->
# Eio_posix.run @@ fun env ->
let default_env = Eio.Stdenv.vars env |> Eio.Vars.get_all in
Switch.run @@ fun sw ->
let pipe1_r, pipe1_w = Eio_unix.pipe sw in
let pipe2_r, pipe2_w = Eio_unix.pipe sw in
Expand Down Expand Up @@ -208,7 +212,8 @@ Swapping FDs (note: plain sh can't handle multi-digit FDs!):
Keeping an FD open:

```ocaml
# Eio_posix.run @@ fun _env ->
# Eio_posix.run @@ fun env ->
let default_env = Eio.Stdenv.vars env |> Eio.Vars.get_all in
Switch.run @@ fun sw ->
let pipe1_r, pipe1_w = Eio_unix.pipe sw in
let child =
Expand Down
1 change: 1 addition & 0 deletions lib_eio_windows/eio_windows.ml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ let run main =
method cwd = (Fs.cwd :> Eio.Fs.dir_ty Eio.Path.t)
method fs = (Fs.fs :> Eio.Fs.dir_ty Eio.Path.t)
method process_mgr = failwith "process operations not supported on Windows yet"
method vars = Eio_unix.Private.vars
method secure_random = Flow.secure_random
method backend_id = "windows"
end
35 changes: 35 additions & 0 deletions tests/process.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,16 @@ A custom environment:
- : string = ":2"
```

Using the parent's environment explicitly:

```ocaml
# run @@ fun mgr env ->
Unix.putenv "DISPLAY" ":1";
let env = Eio.Stdenv.vars env |> Eio.Vars.get_all in
Process.parse_out ~env mgr Eio.Buf_read.line ["sh"; "-c"; "echo $DISPLAY"];;
- : string = ":1"
```

Eio's child reaping code doesn't interfere with OCaml's process spawning:

```ocaml
Expand Down Expand Up @@ -320,3 +330,28 @@ val e : Env.t = [""
"c=5"
"c=6"]
```

Using the environment capability:

```ocaml
# run @@ fun _mgr env ->
Unix.putenv "DISPLAY" ":1";
let vars = Eio.Stdenv.vars env in
Eio.Vars.get_opt vars "DISPLAY";;
- : string option = Some ":1"
```

```ocaml
# run @@ fun _mgr env ->
let vars = Eio.Stdenv.vars env in
Eio.Vars.get_opt vars "THIS_VAR_PROBABLY_WILL_NOT_EXIST";;
- : string option = None
```

```ocaml
# run @@ fun _mgr env ->
Unix.putenv "DISPLAY" ":1";
let env = Eio.Stdenv.vars env |> Eio.Vars.get_all in
Eio.Process.Env.get_opt "DISPLAY" env;;
- : string option = Some ":1"
```
Loading