Skip to main content

BoxCommand

Command builder for running programs in a box.
use boxlite::BoxCommand;
use std::time::Duration;

let cmd = BoxCommand::new("python3")
    .args(["-c", "print('hello')"])
    .env("PYTHONPATH", "/app")
    .timeout(Duration::from_secs(30))
    .working_dir("/workspace")
    .tty(true);

Builder Methods

MethodSignatureDescription
newfn new(command: impl Into<String>) -> SelfCreate command
argfn arg(self, arg: impl Into<String>) -> SelfAdd single argument
argsfn args<I, S>(self, args: I) -> SelfAdd multiple arguments
envfn env(self, key: impl Into<String>, val: impl Into<String>) -> SelfSet env var
timeoutfn timeout(self, timeout: Duration) -> SelfSet run timeout
working_dirfn working_dir(self, dir: impl Into<String>) -> SelfSet working directory
ttyfn tty(self, enable: bool) -> SelfEnable pseudo-terminal

Execution

Handle to a running command.
use boxlite::BoxCommand;
use futures::StreamExt;

let mut run_handle = litebox.run(BoxCommand::new("ls").arg("-la")).await?;

// Read stdout as stream
let mut stdout = run_handle.stdout().unwrap();
while let Some(line) = stdout.next().await {
    println!("{}", line);
}

// Wait for completion
let status = run_handle.wait().await?;
println!("Exit code: {}", status.exit_code);

Methods

MethodSignatureDescription
idfn id(&self) -> &ExecutionIdGet run ID
stdinfn stdin(&mut self) -> Option<ExecStdin>Take stdin stream (once)
stdoutfn stdout(&mut self) -> Option<ExecStdout>Take stdout stream (once)
stderrfn stderr(&mut self) -> Option<ExecStderr>Take stderr stream (once)
waitasync fn wait(&mut self) -> BoxliteResult<ExecResult>Wait for completion
killasync fn kill(&mut self) -> BoxliteResult<()>Send SIGKILL
signalasync fn signal(&self, signal: i32) -> BoxliteResult<()>Send signal
resize_ttyasync fn resize_tty(&self, rows: u32, cols: u32) -> BoxliteResult<()>Resize PTY

ExecStdin

Standard input stream (write-only).
pub struct ExecStdin {
    // ...
}

impl ExecStdin {
    /// Write data to stdin
    pub async fn write(&mut self, data: &[u8]) -> BoxliteResult<()>;

    /// Write all data to stdin
    pub async fn write_all(&mut self, data: &[u8]) -> BoxliteResult<()>;
}

Example

let mut run_handle = litebox.run(BoxCommand::new("cat")).await?;

// Get stdin handle
let mut stdin = run_handle.stdin().unwrap();

// Write data
stdin.write(b"Hello from stdin!\n").await?;
stdin.write_all(b"More data\n").await?;

// Drop stdin to close (signals EOF to process)
drop(stdin);

let result = run_handle.wait().await?;

ExecStdout / ExecStderr

Standard output/error streams (read-only). Implements futures::Stream<Item = String>.
use futures::StreamExt;

let mut run_handle = litebox.run(BoxCommand::new("ls")).await?;

// Read stdout
let mut stdout = run_handle.stdout().unwrap();
while let Some(line) = stdout.next().await {
    println!("stdout: {}", line);
}

// Read stderr
let mut stderr = run_handle.stderr().unwrap();
while let Some(line) = stderr.next().await {
    eprintln!("stderr: {}", line);
}

Concurrent Reading

use futures::StreamExt;
use tokio::select;

let mut run_handle = litebox.run(BoxCommand::new("my-command")).await?;
let mut stdout = run_handle.stdout().unwrap();
let mut stderr = run_handle.stderr().unwrap();

loop {
    select! {
        Some(line) = stdout.next() => println!("stdout: {}", line),
        Some(line) = stderr.next() => eprintln!("stderr: {}", line),
        else => break,
    }
}

ExecResult

Exit status of a process.
pub struct ExecResult {
    /// Exit code (0 = success, negative = signal number)
    pub exit_code: i32,
}

impl ExecResult {
    /// Returns true if exit code was 0
    pub fn success(&self) -> bool;

    /// Get exit code
    pub fn code(&self) -> i32;
}

See Also