rskit_process/lib.rs
1//! Subprocess execution with explicit I/O modes, process-group isolation, and timeouts.
2//!
3//! This crate provides functionality to execute external processes with:
4//! - Timeout support with configurable grace period
5//! - SIGTERM → SIGKILL escalation for graceful shutdown
6//! - Process group isolation to ensure child processes are properly terminated
7//! - Explicit captured, observed, and inherited stdio modes
8//! - Environment variable control
9//! - Working directory configuration
10//!
11//! # I/O modes
12//!
13//! `ProcessIo::Captured` captures stdout and stderr separately through pipes.
14//! It is deterministic for non-interactive commands, but it is not a terminal
15//! and cannot guarantee exact ordering between stdout and stderr.
16//!
17//! `ProcessIo::Observed` also uses separate pipes and supports live raw-byte
18//! or line callbacks with optional capture. Line observers split deterministically on `\n`, `\r`,
19//! and `\r\n`; invalid UTF-8 is reported lossily.
20//!
21//! `ProcessIo::Inherited` gives the child the parent stdio handles.
22//! This is the right mode for normal terminal commands,
23//! but it does not provide structured output capture.
24//!
25//! # Example
26//!
27//! ```no_run
28//! use rskit_process::{ProcessConfig, ProcessSpec, run_with_cancel};
29//! use std::time::Duration;
30//! use tokio_util::sync::CancellationToken;
31//!
32//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
33//! let spec = ProcessSpec::new("echo")
34//! .arg("hello")
35//! .arg("world");
36//!
37//! let config = ProcessConfig::default().with_timeout(Some(Duration::from_secs(30)));
38//!
39//! let result = run_with_cancel(&spec, &config, CancellationToken::new()).await?;
40//! println!("stdout: {}", result.stdout);
41//! println!("exit code: {:?}", result.exit_code);
42//! # Ok(())
43//! # }
44//! ```
45
46#![warn(missing_docs)]
47
48mod capture;
49mod command;
50mod persistent;
51mod process_group;
52#[cfg(unix)]
53mod pty;
54mod result;
55mod runner;
56mod signal;
57mod sync;
58mod terminate;
59mod worker;
60
61pub use command::{
62 ArgRedaction, CapturedIo, DEFAULT_MAX_OUTPUT_BYTES, EnvPolicy, InheritedIo, InputPolicy,
63 ObservedIo, OutputPolicy, ProcessConfig, ProcessIo, ProcessSpec, SignalPolicy, command,
64};
65pub use persistent::{
66 PersistentConfig, PersistentOutput, PersistentOutputObserver, PersistentOutputStream,
67 PersistentProcess, PersistentReadiness, PersistentRun, PersistentStartErrorKind,
68 PersistentStartup, ShutdownOutcome, persistent_start_error_kind, start_persistent_with_cancel,
69};
70pub use process_group::{
71 interrupt as interrupt_process_group, isolate as isolate_process_group,
72 kill as kill_process_group, terminate as terminate_process_group,
73};
74#[cfg(unix)]
75pub use pty::{PtyIo, PtySize, terminal_size};
76pub use result::ProcessResult;
77pub use runner::{OutputObserver, run_with_cancel};
78pub use sync::run;
79
80/// Re-export error types
81pub use rskit_errors::{AppError, AppResult, ErrorCode};