On this page
tecs.io.Process
Streaming child processes.
new starts the child immediately and returns its live standard-stream endpoints. Piped stdin is a Writer; piped stdout and stderr are Reader values. The process owns all three endpoints. Closing one endpoint closes only that pipe; closing the process closes every endpoint, terminates a live child, and reaps it. Buffers and byte views passed to an endpoint remain caller-owned.
Process:communicate is the complete-exchange form for tools and build steps. It feeds stdin while draining stdout and stderr concurrently, so neither output pipe can fill and deadlock the child:
tecs.scoped(
"read child output",
function(scope: tecs.Scope)
local child <const> = scope:own(tecs.io.Process.new({
args = {"git", "status", "--porcelain"},
timeoutMs = 2000,
}))
local result, communicateReason = child:communicate()
if result == nil then
error(communicateReason)
end
if result:succeeded() then
print(result.output)
else
io.stderr:write(result.errorOutput)
end
end
)Interactive children use the same reader and writer vocabulary as files, buffers, and transforms. Closing stdin sends EOF:
tecs.scoped(
"communicate with child",
function(scope: tecs.Scope)
local child <const> = scope:own(tecs.io.Process.new({
args = {"/bin/cat"}
}))
local written, writeReason = child.stdin:write("one request\n")
if written == nil then
error(writeReason)
end
child.stdin:close()
local reply, readReason = child.stdout:read(4096)
if reply == nil then
error(readReason)
end
print(reply)
end
)Process:wait, pipe reads and writes, and communicate all use contextual waiting. They suspend a normal system without blocking SDL and block when called outside an update. Buffer and byte-view variants avoid constructing Lua strings.
A pipe read waits at most the reader's timeout, thirty seconds by default and Reader:setTimeout to change it, and then returns nil and a reason. Reading one pipe at a time deadlocks against a child that writes to both: the pipe the caller ignores fills, the child stops, and the pipe the caller reads never produces another byte. communicate drains both and is the form to reach for whenever a child writes standard error at all.
Use "inherit" for a CLI that should share the terminal, "null" to discard a stream, and stderr = "stdout" for one ordered transcript. A nonzero child exit still returns an Exit; succeeded performs the separate exit-code check. Spawn failures return nil and a reason. Deadlines and explicit kills set the exit's killed fields.
Module contents
Constructors
| Constructor | Description |
|---|---|
new |
Starts a caller-owned child process with streaming standard I/O. |
Types
| Type | Kind | Description |
|---|---|---|
CommunicateOptions |
record | CommunicateOptions controls a complete duplex exchange. |
ErrorMode |
enum | ErrorMode selects where a child writes standard error. |
Exit |
record | Exit describes how a child stopped. |
InputMode |
enum | InputMode selects where a child reads standard input. |
Options |
record | Options configures a child and its standard streams. |
OutputMode |
enum | OutputMode selects where a child writes standard output. |
Reader |
interface | Reader reads one live child-process output pipe. |
Result |
record | Result contains a completed duplex exchange. |
Writer |
interface | Writer writes one live child-process input pipe. |
Functions
| Function | Kind | Description |
|---|---|---|
communicate |
Instance | Feeds stdin and captures stdout and stderr without pipe deadlock. |
isRunning |
Instance | Returns whether the child has not stopped yet. |
kill |
Instance | Requests that the child terminate. |
wait |
Instance | Waits for the child to stop and returns its exit description. |
Values
| Value | Type | Description |
|---|---|---|
pid |
integer |
Read-only. Reports the operating-system process identifier. |
stderr |
Reader |
Read-only. Provides standard error when its mode is "pipe", or nil when error output is inherited, discarded, or... |
stdin |
Writer |
Read-only. Provides standard input when its mode is "pipe", or nil when input is inherited or discarded. |
stdout |
Reader |
Read-only. Provides standard output when its mode is "pipe", or nil when output is inherited or discarded. |
Constructors
tecs.io.Process.new Static
Starts a caller-owned child process with streaming standard I/O.
Piped endpoints use contextual waiting through the ordinary Reader and Writer methods. The process owns them, while buffers and byte views passed to endpoint methods remain caller-owned.
Arguments
| Name | Type | Description |
|---|---|---|
options |
Options |
The caller supplies the program, arguments, environment, working directory, standard-stream modes, and optional deadline. |
Returns
| Type | Description |
|---|---|
Process |
Returns a caller-owned process when the platform starts it. |
string |
Returns the platform reason when the first return is nil. |
Examples
tecs.scoped(
"inspect repository",
function(scope: tecs.Scope)
local child <const> = scope:own(tecs.io.Process.new({
args = {"git", "status", "--porcelain"},
cwd = tecs.io.Path.new("workspace"),
}))
local result, communicateReason = child:communicate()
assert(result, communicateReason)
end
)tecs.scoped(
"read revision",
function(scope: tecs.Scope)
local child <const> = scope:own(tecs.io.Process.new({
args = {"git", "rev-parse", "HEAD"},
timeoutMs = 2000,
}))
local result, communicateReason = child:communicate()
assert(result, communicateReason)
assert(result:succeeded())
print(result.output)
end
)Types
tecs.io.Process.CommunicateOptions record
CommunicateOptions controls a complete duplex exchange.
record tecs.io.Process.CommunicateOptions
input: string | ByteView
maxOutputBytes: integer
endtecs.io.Process.CommunicateOptions.input field
Caller-writable. Supplies complete standard-input bytes as a string, open Buffer, or open ByteView. Omitted input sends EOF immediately.
tecs.io.Process.CommunicateOptions.input: string | ByteViewtecs.io.Process.CommunicateOptions.maxOutputBytes field
Caller-writable. Limits stdout and stderr together. Defaults to 268,435,456 bytes. Exceeding it forcibly terminates the child and returns a failure.
tecs.io.Process.CommunicateOptions.maxOutputBytes: integertecs.io.Process.ErrorMode enum
ErrorMode selects where a child writes standard error.
enum tecs.io.Process.ErrorMode
"inherit"
"null"
"pipe"
"stdout"
endtecs.io.Process.Exit record
Exit describes how a child stopped.
record tecs.io.Process.Exit
exitCode: integer
killed: boolean
timedOut: boolean
succeeded: function(self): boolean
endtecs.io.Process.Exit.exitCode field
Read-only. Reports the platform exit code, or the platform's best answer after termination.
tecs.io.Process.Exit.killed field
Read-only. Reports whether Tecs requested termination.
tecs.io.Process.Exit.timedOut field
Read-only. Reports whether the configured deadline requested that termination.
tecs.io.Process.Exit:succeeded Instance
Returns whether the child exited normally with code zero.
function tecs.io.Process.Exit.succeeded(self): booleanArguments
| Name | Type | Description |
|---|---|---|
self |
ProcessExit |
The completed exit to inspect. |
Returns
| Type | Description |
|---|---|
boolean |
Returns true only for a normal zero exit. |
tecs.io.Process.InputMode enum
InputMode selects where a child reads standard input.
enum tecs.io.Process.InputMode
"inherit"
"null"
"pipe"
endtecs.io.Process.Options record
Options configures a child and its standard streams.
record tecs.io.Process.Options
args: {string}
cwd: string | Path
env: {string: string}
clearEnv: boolean
stdin: ProcessInputMode
stdout: ProcessOutputMode
stderr: ProcessErrorMode
timeoutMs: integer
endtecs.io.Process.Options.args field
Caller-writable. Supplies the program in args[1] followed by its arguments. A program without a separator resolves through PATH.
tecs.io.Process.Options.cwd field
Caller-writable. Selects the child's working directory as a string or Path, or omits it to inherit the current directory.
tecs.io.Process.Options.env field
Caller-writable. Overlays environment variables on the inherited environment, or supplies the complete environment with clearEnv.
tecs.io.Process.Options.clearEnv field
Caller-writable. Starts with an empty environment when true. Defaults to false.
tecs.io.Process.Options.stdin field
Caller-writable. Selects "pipe", "inherit", or "null" for standard input. Defaults to "pipe".
tecs.io.Process.Options.stdin: ProcessInputModetecs.io.Process.Options.stdout field
Caller-writable. Selects "pipe", "inherit", or "null" for standard output. Defaults to "pipe".
tecs.io.Process.Options.stdout: ProcessOutputModetecs.io.Process.Options.stderr field
Caller-writable. Selects "pipe", "inherit", "null", or "stdout" for standard error. Defaults to "pipe".
tecs.io.Process.Options.stderr: ProcessErrorModetecs.io.Process.Options.timeoutMs field
Caller-writable. Forcibly terminates the child after this many milliseconds, or omits the deadline. The deadline begins when the process is created.
tecs.io.Process.OutputMode enum
OutputMode selects where a child writes standard output.
enum tecs.io.Process.OutputMode
"inherit"
"null"
"pipe"
endtecs.io.Process.Reader interface
Reader reads one live child-process output pipe.
interface tecs.io.Process.Reader is Reader
isClosed: function(self): boolean
isEOF: function(self): boolean
setTimeout: function(self, timeoutMs: integer)
endInterfaces
| Interface |
|---|
Reader |
tecs.io.Process.Reader:isClosed Instance
Returns whether this endpoint has been closed.
function tecs.io.Process.Reader.isClosed(self): booleanArguments
| Name | Type | Description |
|---|---|---|
self |
ProcessReader |
The process reader to inspect. |
Returns
| Type | Description |
|---|---|
boolean |
Returns true after close. |
tecs.io.Process.Reader:isEOF Instance
Returns whether the child closed its end and every byte was consumed.
function tecs.io.Process.Reader.isEOF(self): booleanArguments
| Name | Type | Description |
|---|---|---|
self |
ProcessReader |
The process reader to inspect. |
Returns
| Type | Description |
|---|---|
boolean |
Returns true after end of file. |
tecs.io.Process.Reader:setTimeout Instance
Bounds how long read and readInto wait for the child to send bytes.
The bound covers waiting only, so a read that already has bytes returns them however long the reader has been idle. It starts when a call first finds the pipe empty and ends that call with nil and a reason. The default is 30,000 milliseconds, and zero returns as soon as one attempt finds no bytes. The new bound applies to the next call rather than to one already waiting.
function tecs.io.Process.Reader.setTimeout(self, timeoutMs: integer)Arguments
| Name | Type | Description |
|---|---|---|
self |
ProcessReader |
The process reader to configure. |
timeoutMs |
integer |
The caller supplies 0 through 2147483647 milliseconds. Any other value raises. |
Returns
None.
tecs.io.Process.Result record
Result contains a completed duplex exchange.
record tecs.io.Process.Result
exit: ProcessExit
output: string
errorOutput: string
succeeded: function(self): boolean
endtecs.io.Process.Result.exit field
Read-only. Contains the child's exit description.
tecs.io.Process.Result.exit: ProcessExittecs.io.Process.Result.output field
Read-only. Contains every captured standard-output byte. It is empty when stdout was inherited or discarded.
tecs.io.Process.Result.errorOutput field
Read-only. Contains every captured standard-error byte. It is empty when stderr was inherited, discarded, or merged into stdout.
tecs.io.Process.Result.errorOutput: stringtecs.io.Process.Result:succeeded Instance
Returns whether the child exited normally with code zero.
function tecs.io.Process.Result.succeeded(self): booleanArguments
| Name | Type | Description |
|---|---|---|
self |
ProcessResult |
The completed exchange to inspect. |
Returns
| Type | Description |
|---|---|
boolean |
Returns true only for a normal zero exit. |
tecs.io.Process.Writer interface
Writer writes one live child-process input pipe.
interface tecs.io.Process.Writer is Writer
isClosed: function(self): boolean
setTimeout: function(self, timeoutMs: integer)
endInterfaces
| Interface |
|---|
Writer |
tecs.io.Process.Writer:isClosed Instance
Returns whether this endpoint has sent EOF or been closed.
function tecs.io.Process.Writer.isClosed(self): booleanArguments
| Name | Type | Description |
|---|---|---|
self |
ProcessWriter |
The process writer to inspect. |
Returns
| Type | Description |
|---|---|
boolean |
Returns true after close. |
tecs.io.Process.Writer:setTimeout Instance
Bounds how long write, writeFrom, and writeView wait for the child to take bytes.
The bound covers waiting only, so a write the pipe has room for returns however long the writer has been idle. It starts when a call first finds the pipe full and ends that call with its failure and a reason, and the child taking further bytes starts it again, so it bounds one stall rather than a whole long write. The default is 30,000 milliseconds, and zero returns as soon as one attempt finds no room. The new bound applies to the next call rather than to one already waiting.
function tecs.io.Process.Writer.setTimeout(self, timeoutMs: integer)Arguments
| Name | Type | Description |
|---|---|---|
self |
ProcessWriter |
The process writer to configure. |
timeoutMs |
integer |
The caller supplies 0 through 2147483647 milliseconds. Any other value raises. |
Returns
None.
Functions
tecs.io.Process:communicate Instance
Feeds stdin and captures stdout and stderr without pipe deadlock.
The call drains both output pipes while feeding input, closes stdin after the final byte, and returns after the child exits and both pipes reach EOF. It suspends a normal system or blocks an ordinary caller.
function tecs.io.Process.communicate(
self, options: CommunicateOptions
): Result, stringArguments
| Name | Type | Description |
|---|---|---|
self |
Process |
The open process whose piped endpoints are consumed. |
options |
CommunicateOptions |
The caller supplies complete input and an output limit, or omits both. |
Returns
| Type | Description |
|---|---|
Result |
Returns the complete exchange result. |
string |
Returns a reason when communication fails or exceeds its output limit. |
Examples
tecs.scoped(
"communicate with child",
function(scope: tecs.Scope)
local child <const> = scope:own(tecs.io.Process.new({
args = {"/bin/cat"}
}))
local result, communicateReason = child:communicate({
input = "request bytes\n",
maxOutputBytes = 1024 * 1024,
})
assert(result, communicateReason)
assert(result.output == "request bytes\n")
end
)tecs.io.Process:isRunning Instance
Returns whether the child has not stopped yet.
function tecs.io.Process.isRunning(self): booleanArguments
| Name | Type | Description |
|---|---|---|
self |
Process |
The process to inspect. |
Returns
| Type | Description |
|---|---|
boolean |
Returns true while the child remains live. |
tecs.io.Process:kill Instance
Requests that the child terminate.
function tecs.io.Process.kill(self, force: boolean): boolean, stringArguments
| Name | Type | Description |
|---|---|---|
self |
Process |
The process to terminate. |
force |
boolean |
The caller requests an unhandleable termination when true or a graceful request when false or omitted. |
Returns
| Type | Description |
|---|---|
boolean |
Returns whether the request was delivered or the child had already stopped. |
string |
Returns the platform reason when the first return is false. |
tecs.io.Process:wait Instance
Waits for the child to stop and returns its exit description.
Inside a system, the call suspends the logical world update without blocking the host thread. Outside a world update, it blocks.
function tecs.io.Process.wait(self): ExitArguments
| Name | Type | Description |
|---|---|---|
self |
Process |
The process to wait for. |
Returns
| Type | Description |
|---|---|
Exit |
Returns how the child stopped. |
Values
tecs.io.Process.pid variable
Read-only. Reports the operating-system process identifier.
tecs.io.Process.pid: integertecs.io.Process.stderr variable
Read-only. Provides standard error when its mode is "pipe", or nil when error output is inherited, discarded, or merged into stdout. The process owns it.
tecs.io.Process.stderr: Readertecs.io.Process.stdin variable
Read-only. Provides standard input when its mode is "pipe", or nil when input is inherited or discarded. The process owns it.
tecs.io.Process.stdin: Writertecs.io.Process.stdout variable
Read-only. Provides standard output when its mode is "pipe", or nil when output is inherited or discarded. The process owns it.
tecs.io.Process.stdout: Reader