The os
faculty contains various reflexes for interacting with the POSIX
environment within which an Escher program executes. It contains a few simple reflexes
for accessing things like command-line arguments, environment variables, standard file
descriptors, process execution and the like.
Most reflexes in os
are implemented in less than 10 lines of code
and in that sense their implementation is their best documentation. Here we detail
only the process execution reflex os.Process
.
The process reflex requires that three valves, named :Command
,
:IO
and :Exit
, be connected. When a command description
is sent to the :Command
valve, the reflex spawns an OS process, described
by the command value. Subsequent commands will block until the spawned process exits.
As soon as the process is executed, a circuit value is sent out to the valve :IO
,
containing the standard file descriptors of the executing process. When the process exits,
a circuit value, containing the exit code of the process, is sent out to the :Exit
valve.
An example of the command circuit value is as follows:
{ Env { "PATH=/abc:/bin" "LESS=less" } Dir "/home/petar" Path "/bin/ls" Args { "-l", "/" } }
The returned IO circuit value is of the following form:
{ Stdin (io.WriteCloser) Stdout (io.ReadCloser) Stderr (io.ReadCloser) }
Where the gate values' types, in brackets, are the Go types io.WriteCloser
,
io.ReadCloser
and io.ReadCloser
, respectively.
The exit circuit is of the form
{ Exit (int) }
The following example demonstrates invoking the /bin/ls
command
and forwarding its standard output and error to those of the Escher program itself.
{ proc *os.Process proc:Command = { Path "/bin/ls" Args { "/" } } yio *e.Fork proc:IO = yio: yio:Stdin = *e.Ignore yio:Stdout = *os.Stdout yio:Stderr = *os.Stderr yExit *e.Fork proc:Exit = yExit: exit *os.Exit yExit:Exit = exit: }
The standard file descriptors of the child process must always be handled.
In this example, standard output and error are forwarded while standard input is
“ignored”. The reflex *e.Ignore
is a “smart” reflex which
ignores primitive values (integers, floats, etc.), whereas it closes io.Closer
objects and it drains io.Reader
objects.