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.