Antra

Standardbibliothek

Antra::Process

import Antra::Process

Process helpers for Antra.

Process exposes a small child-process API around an opaque runtime value. The returned handle owns the child process plus its standard streams.

Use the API in these rough tiers:

  • spawn(...) when you want the raw Process handle and explicit control
  • capture(...) when you only need stdout plus exit_code
  • pipe_from(...) for the explicit cmd | shape with a readable stdout handle plus the owning process
  • with_output(...) when you want captured stdout, stderr, and exit_code in one callback
  • with_pipes(...) for interactive stdin/stdout/stderr work with real FileHandles

Use signal(...), terminate(...) or kill(...) when a process should not just be waited on but actively interrupted.

Überblick#

Für einfache Child-Processes mit stdin/stdout/stderr-Pipes und opakem Process-Wert.

Boundary-Fehler wie ungueltige Kommandos, falsche Argumente oder geschlossene Streams kommen bei den nicht-Bang-Varianten als %Err[%Error{...}] zurueck.

Der Einstieg ist bewusst klein gehalten:

  • Process.spawn(...)
  • Process.capture(...)
  • Process.pipe_from(...)
  • Process.with_spawn(...)
  • Process.pid(...)
  • Process.stdin/stdout/stderr(...)
  • Process.write(...)
  • Process.write_bytes(...)
  • Process.close_input(...)
  • Process.read_all(...)
  • Process.read_bytes(...)
  • Process.read_all_bytes(...)
  • Process.read_stderr_all(...)
  • Process.signal(...)
  • Process.terminate(...)
  • Process.kill(...)
  • Process.wait(...)
  • Process.close(...)

Beispiel:

import Antra::Process as Process
import Antra::Result as Result

my process = Process.spawn("perl", ["-e", 'print uc(do { local $/; <STDIN> })']).!
Result.unwrap!(Process.write(process, "hello"))
Result.unwrap!(Process.close_input(process))
println(Process.read_all(process).!)
println(Process.close(process).!)

Wenn ein Kindprozess nicht von selbst endet, kannst du ihn auch aktiv signalisieren:

import Antra::Process as Process
import Antra::Result as Result

my process = Process.spawn("perl", ["-e", 'select undef, undef, undef, 30;']).!
println(Result.unwrap!(Process.terminate(process)))
println(Process.close(process).!)

Fuer Process.signal(...) sind die gaengigen Signale auch direkt in der Antra-API sichtbar, zum Beispiel :term, :kill, :int, :hup, :quit, :usr1, :usr2, :stop und :cont.

Fuer Binärprotokolle gibt es ausserdem Process.write_bytes(...), Process.read_bytes(...) und Process.read_all_bytes(...) auf ByteString-Basis. Das ist praktisch für komprimierte Daten, Bilder, verschlüsselte Payloads oder eigene kleine Binärformate.

Wenn du lieber scoped arbeiten willst, kannst du den Process auch nur fuer den Callback oeffnen:

import Antra::IO::File as File
import Antra::Process as Process
import Antra::Result as Result

println(Process.with_spawn("perl", ["-e", 'exit 0']) |process| -> {
    %Ok[Process.pid(process).!]
})

println(Process.with_spawn!("perl", ["-e", 'print uc(do { local $/; <STDIN> })']) |process| -> {
    my stdin = Process.stdin(process).!
    my stdout = Process.stdout(process).!
    Result.unwrap!(File.write(stdin, "hello"))
    Result.unwrap!(File.close(stdin))
    File.read_all(stdout).!
})

Fuer haeufige Einbahnstrassen-Faelle gibt es ausserdem zwei kleine Helfer:

import Antra::Process as Process

my capture = Process.capture("perl", ["-e", 'print qq[out]; exit 7;']).!
println(capture.stdout)
println(capture.exit_code)

my out = Process.pipe_from("perl", ["-e", 'print qq[first\nsecond];']).!
println(out.stdout)
println(Process.read_all(out.process).!)
println(Process.wait(out.process).!)

capture(...) ist die kleine Surface fuer "stdout plus Exit-Code" und verwirft stderr im MVP intern. pipe_from(...) ist die explizite Form des klassischen cmd |-Falls, gibt aber bewusst sowohl den stdout-Handle als auch den owning process zurueck.

Ein ausfuehrliches Einsteiger-Tutorial zu Process und System.fork(...) steht in 28-process-und-fork-fuer-einsteiger.md.

Funktionen#

fn capture(command)
fn capture(command, args)

Spawns a process, reads its stdout as text, waits for exit, and returns %{stdout, exit_code}.

In the current MVP, stderr is only drained internally so the helper stays focused on the common "stdout plus exit code" case.

Example:

my result = Process.capture("perl", ["-e", 'print qq[out]; exit 7;']).!
println(result.stdout)
println(result.exit_code)
fn close(process)

Closes all streams, waits for the child, and returns the exit status.

close(...) does not send a signal. It only closes handles and then waits for the process to finish on its own.

fn close_input(process)

Closes the child's stdin.

Call this when the child is waiting for EOF before it can finish.

fn kill(process)

Sends SIGKILL to the child process.

Use this only when softer shutdown paths are not enough.

fn pid(process)

Returns the child PID.

fn pipe_from(command)
fn pipe_from(command, args)

Spawns a process with only stdout piped back to the caller.

This is the explicit Antra form of the common one-way cmd | pattern. The return value keeps both the readable stdout handle and the owning process visible so the lifecycle stays explicit.

Example:

my out = Process.pipe_from("perl", ["-e", 'print qq[first\nsecond]']).!
println(File.read_line(out.stdout).!)
println(Process.wait(out.process).!)
fn read_all(process)

Reads the remaining stdout of the child as text.

Returns %Ok[text] or %Err[%Error{...}].

fn read_all_bytes(process)

Reads the remaining stdout of the child as raw ByteString data.

Returns %Ok[bytes] or %Err[%Error{...}].

fn read_bytes(process, n)

Reads up to n bytes from the child's stdout as ByteString.

Returns %Ok[bytes] or %Err[%Error{...}].

fn read_stderr_all(process)

Reads the remaining stderr of the child as text.

Returns %Ok[text] or %Err[%Error{...}].

fn read_stderr_all_bytes(process)

Reads the remaining stderr of the child as raw ByteString data.

Returns %Ok[bytes] or %Err[%Error{...}].

fn read_stderr_bytes(process, n)

Reads up to n bytes from the child's stderr as ByteString.

Returns %Ok[bytes] or %Err[%Error{...}].

fn signal(process, :term)
fn signal(process, :kill)
fn signal(process, :int)
fn signal(process, :hup)
fn signal(process, :quit)
# … 5 weitere Klauseln

Sends an explicit signal to the child process.

Common keyword shorthands are visible directly in this API: :term, :kill, :int, :hup, :quit, :usr1, :usr2, :stop and :cont.

Strings like "TERM", "SIGTERM" and positive signal numbers are still accepted through the generic fallback clause.

Example:

Result.unwrap!(Process.signal(process, :term))
fn spawn(command)
fn spawn(command, args)

Spawns a child process without extra arguments.

Returns %Ok[#Process<...>] or %Err[%Error{...}].

fn stderr(process)

Returns the readable stderr handle as FileHandle.

fn stdin(process)

Returns the writable stdin handle as FileHandle.

Useful when you want lower-level stream control instead of the convenience helpers like write(...).

fn stdout(process)

Returns the readable stdout handle as FileHandle.

fn terminate(process)

Sends SIGTERM to the child process.

This is the polite "please stop" variant.

fn try_wait(process)

Probes whether the process has already exited without blocking.

Returns %Ok[%Some[exit_code]] once the process is reaped, otherwise %Ok[%None[]] while it is still running.

fn wait(process)

Waits for process exit and returns the exit status.

Returns %Ok[exit_code] or %Err[%Error{...}].

A signaled process is reported in shell style as 128 + signal, e.g. 143 for SIGTERM and 137 for SIGKILL.

fn with_output(process, f)

Reads remaining stdout/stderr, waits for process exit and calls f with stdout, stderr and exit_code.

This is useful for use ... <- style code when a command should be fully captured before branching on its exit status.

Example:

my process = Process.spawn("perl", ["-e", 'print qq[out]; print STDERR qq[warn]; exit 3;']).!
use stdout, stderr, exit_code <- Process.with_output(process)
println(stdout <> ":" <> stderr <> ":" <> str(exit_code))
fn with_output!(process, f)

Bang/raw counterpart of with_output.

fn with_pipes(command, f)
fn with_pipes(command, args, f)

Spawns a process and exposes stdin, stdout, stderr, and the raw process handle to f.

This is the interactive pipe-oriented counterpart to with_output(...). The stream handles are regular FileHandles and can be used with Antra::IO::File.

Example:

Process.with_pipes!("perl", ["-e", 'my $line = <STDIN>; print uc($line)'], |stdin, stdout, stderr, process| -> {
    Result.unwrap!(File.write(stdin, "hello\n"))
    println(Result.unwrap!(File.close(stdin)))
    File.read_all(stdout).!
})
fn with_pipes!(command, f)
fn with_pipes!(command, args, f)

Bang/raw counterpart of with_pipes.

fn with_spawn(command, f)
fn with_spawn(command, args, f)

Spawns a child process, passes it to f, and closes it afterwards.

The callback must return %Ok[...] or %Err[...].

Example:

println(Process.with_spawn("perl", ["-e", 'print qq[ok]; exit 0;']) |process| -> {
    %Ok[Process.read_all(process).!]
})
fn with_spawn!(command, f)
fn with_spawn!(command, args, f)

Bang/raw counterpart for callbacks using bang-style process operations.

This variant throws directly on errors instead of returning Result.

fn write(process, data)

Writes text to the child's stdin.

This is raw text I/O. For structured values over fork-based channels, prefer Antra::System.send(...).

fn write_bytes(process, bytes)

Writes binary ByteString data to the child's stdin.

Use this for raw byte protocols, compressed data, image payloads, or any other non-text transport.

Quelle dieser Seite