This commit is contained in:
ge
2025-12-28 20:42:30 +03:00
commit 7a67749f1f
20 changed files with 1130 additions and 0 deletions

44
examples/error_handling.v Normal file
View File

@@ -0,0 +1,44 @@
import os
import runcmd
fn main() {
// Prepare the command.
mut cmd := runcmd.new('sh', '-c', 'echo -n This command always fails! >&2; sleep 30; false')
// Run this example with `-d runcmd_trace` to see debug logs.
// Look for line like this: runcmd[pid=584015]: Process.wait: wait for pid 584016
// Try to `kill -9 ${pid_here}` while program runs and see whats happen.
// Run command with capturing its output.
out := cmd.output() or {
if err is runcmd.ExitError {
// Command exited with non-zero code. Handle it here.
eprintln(err)
// `err.state` can tell you the failure details.
eprintln(err.state)
// Let's check if the process was killed by someone...
status := runcmd.WaitStatus(err.state.sys())
if status.term_signal() == int(os.Signal.kill) {
eprintln('Oh, process is killed... ( x__x )')
} else {
// Not killed.
}
exit(err.code()) // `err.code()` here contains the command exit status.
} else {
// Another error occurred. Most likely, something went wrong while executing
// the process creation system calls. Check `err.code()` to get the concrete
// error, it contains the standard C errno value.
// See https://www.man7.org/linux/man-pages/man3/errno.3.html
// Replace 0 to actual errno value (real errno never be zero).
if err.code() == 0 {
// Do something here...
}
// Fallback to panic.
panic(err)
}
}
println(out)
}

View File

@@ -0,0 +1,59 @@
import io.string_reader
import rand
import runcmd
import time
fn main() {
// Prepare the command.
mut cmd := runcmd.new('cat')
// Setup I/O redirection.
cmd.redirect_stdio = true
// Start a process.
// Note: File descriptors will only become available after the process has started!
pid := cmd.start()!
println('Child process started with pid ${pid}')
// Get child file descriptors.
mut child_stdin := cmd.stdin()!
mut child_stdout := cmd.stdout()!
// Prepare reader to store command output.
mut output := string_reader.StringReader.new(reader: child_stdout)
// Start stdout reading in a coroutine.
//
// The reader will be block until the descriptor contains data.
// Therefore, to avoid blocking the main thread, we start the reader
// in a coroutine.
go fn [mut output] () {
println('STDOUT reader started!')
// Read stdout line by line until EOF.
for {
line := output.read_line() or { break }
println('Recv: ${line}')
}
}()
// Start sending data to child in a loop.
limit := 5
for _ in 0 .. limit {
// Generate some data.
data := rand.string(10) + '\n'
print('Send: ${data}')
// Write data to child stdin file descriptor.
_ := child_stdin.write(data.bytes())!
// Sleep a bit for demonstration.
time.sleep(500 * time.millisecond)
}
// Close stdin by hand so that the child process receives EOF.
// Without this child will hang for waiting for input.
child_stdin.close()!
// wait() will close the child stdout file desciptor by itself.
cmd.wait()!
}

28
examples/stream_output.v Normal file
View File

@@ -0,0 +1,28 @@
import io.string_reader
import runcmd
fn main() {
// Prepare command.
mut cmd := runcmd.new('sh', '-c', r'for i in {1..5}; do echo line $i; sleep .5; done; echo finish!')
// This is required to captute standart I/O streams.
cmd.redirect_stdio = true
// Start child process.
pid := cmd.start()!
println('Child process started with pid ${pid}')
// Setup StringReader with stdout input. Note the cmd.stdout()! call, it
// returns the io.Reader interface and reads child process stdout file descriptor.
mut reader := string_reader.StringReader.new(reader: cmd.stdout()!)
// Read sdtout line by line until EOF.
for {
line := reader.read_line() or { break }
println('Read: ${line}')
}
cmd.wait()! // Wait to child process completed.
println('Child state: ${cmd.state}')
}

View File

@@ -0,0 +1,38 @@
import io.string_reader
import strings
import runcmd
fn main() {
input := 'Hello from parent process!'
// Prepare reader and writer.
//
// * `reader` reads input from the parent process; it will be copied to the
// standard input of the child process.
// * `writer` accepts data from the child process; it will be copied from the
// standard output of the child process.
mut reader := string_reader.StringReader.new(reader: runcmd.buffer(input.bytes()), source: input)
mut writer := strings.new_builder(4096)
// Prepare the command.
mut cmd := runcmd.new('cat')
// Set redirect_stdio to perform I/O copying between parent and child processes.
cmd.redirect_stdio = true
// Setup reader and writer for child I/O streams.
cmd.stdin = reader
cmd.stdout = writer
// Start and wait for command.
cmd.run()!
// Get command output as string.
output := writer.str()
// Make sure that `cat` returned the same data that we sent to it as input.
assert input == output, 'output data differs from input!'
println('Child state: ${cmd.state}')
println('Child output: ${output}')
}