pub struct ProcessGroup { /* private fields */ }Expand description
A container that ties the lifetime of a child-process tree to its own.
Every process spawned into the group — and everything those processes
spawn — is killed when the group is dropped (kill-on-close), so an exiting or
panicking owner never leaks subprocesses. The containment mechanism is
platform-specific and observable via mechanism.
Dropping the group performs an immediate hard kill. For a graceful
SIGTERM → wait → SIGKILL teardown (Unix), call
shutdown instead — Drop cannot await, so the graceful
tier lives in that async method.
The drop guarantee covers every exit that runs destructors (returns,
panics with unwinding). If the owner dies abruptly — SIGKILL,
std::process::abort — Drop never runs: on Windows the kernel still
kills the tree (the job handle closes with the process), elsewhere that
hardening is the opt-in
Command::kill_on_parent_death
(Linux, direct child only; unavailable on macOS/BSD).
Implementations§
Source§impl ProcessGroup
impl ProcessGroup
Sourcepub fn new() -> Result<Self>
pub fn new() -> Result<Self>
Create an empty group with default options.
§Errors
Error::Io if the OS rejects creating the group’s containment primitive
(a Job Object on Windows, a cgroup on Linux). The default options set no
resource caps, so no limit-enforcement failure can arise.
Sourcepub fn with_options(options: ProcessGroupOptions) -> Result<Self>
pub fn with_options(options: ProcessGroupOptions) -> Result<Self>
Create an empty group with the given options.
§Errors
Error::Io if the OS rejects creating the group’s containment primitive.
With the limits feature, if options.limits sets any cap it is enforced
now. When the active mechanism can’t honor a requested limit (no
cgroup/Job Object, or a Linux cgroup whose controllers can’t be enabled —
see ResourceLimits for the cgroup-v2 real-root requirement) this
returns Error::ResourceLimit — rather than handing back an unbounded
group — and an invalid cap value returns it too, with
LimitReason::Invalid.
Sourcepub fn spawn(&self, cmd: Command) -> Result<Child>
pub fn spawn(&self, cmd: Command) -> Result<Child>
Spawn cmd as a member of this group.
The returned Child — and any process it later spawns — belongs to the
group and is reaped when the group is killed or dropped. The caller is
responsible for configuring cmd’s stdio; the group only handles
containment. To build a capture-wired tokio::process::Command from a
Command, use its to_tokio_command() bridge (a hidden
raw-tokio helper), or construct the tokio::process::Command directly.
Windows: to make containment race-free the child is created
CREATE_SUSPENDED, assigned to the job, then resumed. This overwrites
any process-creation flags the caller set on cmd (e.g.
CREATE_NO_WINDOW) — Win32 exposes no way to read them back and OR the
suspend bit in. The Command-driven launch paths (run helpers,
start, pipelines) don’t have this limitation: their
Command::create_no_window flag
travels alongside the OS command and is OR’d in. Only this raw escape
hatch forces CREATE_SUSPENDED alone.
Unix: the group likewise installs a pre_exec hook on cmd to join
the cgroup / process group.
These mutations make cmd single-use: the spawn appends a pre_exec
hook (Unix) and re-sets the creation flags (Windows), which would stack if
the same command were spawned twice. spawn takes cmd by value so
that reuse is a compile error rather than a silent hook-stacking footgun —
build a fresh Command per spawn. (The crate’s own run helpers
already rebuild the OS command per run, so this only ever concerned direct
spawn callers.)
§Errors
Error::Spawn if the OS refuses to start cmd — the working directory
is bad, permission is denied, and so on. (This raw path reports every
launch failure as Error::Spawn; the Command-driven run helpers, by
contrast, translate a not-found program into Error::NotFound.)
Sourcepub fn adopt(&self, child: &Child) -> Result<()>
Available on crate feature process-control only.
pub fn adopt(&self, child: &Child) -> Result<()>
process-control only.Attach an already-started Child to this group.
Only the child itself is moved into the group; processes it has already spawned keep their original containment (future forks are captured).
On the POSIX process-group mechanism, a child that has already exec’d
cannot be re-grouped (POSIX forbids it), so it is tracked
individually: the child itself is signalled/killed with the group,
but — unlike on Windows/cgroup — its future forks are not captured.
The caller keeps the Child handle and is responsible for reaping:
an adopted child that exited but was never awaited probes as alive, so
a graceful shutdown can wait out its full timeout
on the zombie before escalating.
Reap promptly (pid-reuse hazard). An individually-tracked adopted child is remembered by pid. If you let it exit and be reaped elsewhere without dropping/tearing down this group, that pid can be recycled by the OS to an unrelated process — and this group’s later teardown would then signal that stranger. The crate has no start-time identity to detect the reuse (and macOS’s small pid space makes it likelier). Reap an adopted child through this group’s lifetime, or tear the group down when done, so a stale pid is never carried across a reuse.
On the containment backends, adopting a child that has already exited
but not yet been reaped is a successful no-op (Ok) — there is nothing
left to contain — while an already-reaped child (one that was
waited, so its handle/pid is gone) errors, since there is no longer
anything to reference.
§Errors
Error::Io if child has already been reaped (awaited), leaving no
live handle/pid to reference. Adopting an exited-but-unreaped child is a
successful no-op.
Sourcepub fn kill_all(&self) -> Result<()>
pub fn kill_all(&self) -> Result<()>
Immediately hard-kill every process currently in the group. Idempotent; the group remains usable for further spawns afterwards.
This is an unconditional hard kill (SIGKILL / cgroup.kill /
TerminateJobObject), not a graceful SIGTERM — for a SIGTERM → grace →
SIGKILL teardown use shutdown /
shutdown_ref. The name mirrors the underlying
Job::kill_all it delegates to.
On the legacy per-pid kill fallback (a Linux kernel without cgroup.kill,
pre-5.14), a tree that won’t drain within the bounded sweep — a fork bomb
still out-spawning, or un-reapable D-state zombies — surfaces as an Err
rather than a false success; the atomic backends (cgroup.kill, Windows
Job Object) don’t need to.
Process-group mechanism (macOS/BSD, Linux process-group fallback). A
member that changed its real/saved uid (a sudo/setuid child) and rejects
SIGKILL with EPERM while still alive is surfaced as an Err — the
containment gap is reported, not hidden. The one EPERM that is not
surfaced is the harmless one: on those platforms killpg also returns
EPERM for a group whose only member is an unreaped zombie (dead), and
the two are indistinguishable from the errno alone, so the target’s actual
run state is checked after the EPERM (proc_pidinfo on macOS, the
/proc/<pid>/stat state field on the Linux fallback) and only a
genuinely-alive, non-zombie member fails the call. On the BSDs, where no
process-state reader is wired up, a delivery EPERM stays swallowed
(best-effort), so a privileged child can still outlive kill_all there — the
atomic mechanisms (cgroup.kill, Job Object) have no such gap.
§Errors
Error::Io in two cases, both on the non-atomic Unix backends: the legacy
per-pid kill fallback (a pre-5.14 Linux kernel without cgroup.kill) when
the tree won’t drain within the bounded sweep, and the process-group
mechanism (macOS/Linux fallback) when a live, non-zombie member rejects
SIGKILL with EPERM (a uid-changed child — see above). The atomic backends
(cgroup.kill, Windows Job Object) never fail here.
Sourcepub fn signal(&self, sig: Signal) -> Result<()>
Available on crate feature process-control only.
pub fn signal(&self, sig: Signal) -> Result<()>
process-control only.Broadcast sig to every process in the group.
Best-effort: a member that has already exited is skipped, and an empty group succeeds trivially.
§Platform support
- Linux (cgroup or process-group fallback), macOS/BSD — any signal, attempted for every live member of the tree.
- Windows — only
Signal::Kill; any other signal — includingSignal::Other— returnsError::Unsupported.
SIGKILL (Signal::Kill, or Other(libc::SIGKILL)) is routed through
the same whole-tree hard kill as kill_all
on every backend (cgroup.kill / killpg / Job Object terminate), so it
cannot miss a process forked mid-broadcast. Other signals are a per-member
broadcast.
Limitation (process-group mechanism only). On macOS/BSD and the Linux
process-group fallback, delivery failures such as EPERM are not surfaced:
this arbitrary-signal broadcast is best-effort and returns Ok. Unlike
kill_all — which checks the target’s run state to report
a live, non-zombie member that rejects SIGKILL — signal makes no such
live/zombie discrimination and always returns Ok on this mechanism, even
for Signal::Kill; reach for kill_all if you need a
rejected hard kill surfaced. The Linux cgroup mechanism does surface delivery
failures for signals other than SIGKILL.
§Errors
Error::Unsupported on Windows for any signal other than
Signal::Kill (Job Objects have no POSIX signals). On the Linux cgroup
mechanism, Error::Io if the OS rejects delivering the signal to a
member. Delivery errors are deliberately not reported by the process-group
mechanism (see above).
Sourcepub fn suspend(&self) -> Result<()>
Available on crate feature process-control only.
pub fn suspend(&self) -> Result<()>
process-control only.Suspend (freeze) every process in the group.
§Platform support
- Linux cgroup — one
cgroup.freezewrite covering the whole subtree (kernel ≥ 5.2; older kernels fall back to per-processSIGSTOP). The freeze is applied by the kernel shortly after the write returns, not instantaneously. - Linux process-group fallback, macOS/BSD —
SIGSTOPto every group; an individually-tracked adopted child (seeadopt) is frozen alone — its own descendants keep running. - Windows — suspends every thread of every member process. Best-effort
and not atomic: threads spawned mid-walk can be missed, and Windows keeps
per-thread suspend counts, so nested
suspendcalls stack — N suspends need Nresumes. On Unix suspend/resume are idempotent (level-triggered).
A suspended tree can still be hard-killed
(kill_all, or dropping the group) — SIGKILL,
cgroup.kill, and TerminateJobObject all act on frozen processes. The
graceful shutdown, however, starts with a SIGTERM
that a frozen tree cannot act on until thawed, so it waits out
shutdown_timeout and then escalates; call resume first
for a clean graceful shutdown.
Spawning into a suspended group is platform-divergent. Under the
Linux cgroup mechanism the freeze is group state: a child spawned (or
adopted) while the group is suspended joins the frozen cgroup and
starts frozen — it does not run until resume.
Worse, the spawn call itself can block until then: the child joins
the cgroup before exec, so it can freeze before the spawn handshake
completes and start never returns. The Windows and
POSIX process-group mechanisms freeze only the members present at the
call, so a later spawn runs normally. Don’t start new work in a
suspended group (e.g. a
Supervisor::with_runner(&group)
restarting into it) — resume first.
On Unix, a graceful shutdown of a suspended group
cannot drain (C7): frozen members don’t run their SIGTERM handlers (and a
SIGSTOP’d member keeps the signal pending), so the graceful phase burns
its full shutdown_timeout and then hard-kills — or, under
escalate_to_kill = false, spares the still-frozen survivors.
resume before a graceful shutdown if you want the members
to actually handle the signal. (On Windows the point is moot: a graceful
shutdown is a prompt hard kill regardless — there’s no soft-signal tier and
no grace wait — so a suspended group is torn down at once, not after the
timeout.)
§Errors
Error::Unsupported if the active mechanism cannot freeze the tree;
otherwise Error::Io if the OS rejects the freeze / SIGSTOP.
Sourcepub fn resume(&self) -> Result<()>
Available on crate feature process-control only.
pub fn resume(&self) -> Result<()>
process-control only.Resume a tree suspended by suspend.
See suspend for the platform matrix and the Windows
suspend-count nesting caveat.
§Errors
Error::Unsupported if the active mechanism cannot thaw the tree;
otherwise Error::Io if the OS rejects the resume / SIGCONT.
Sourcepub fn members(&self) -> Result<Vec<u32>>
Available on crate feature process-control only.
pub fn members(&self) -> Result<Vec<u32>>
process-control only.The pids of the processes currently in the group.
A point-in-time snapshot: a returned pid may belong to a process that exits (or is reaped) immediately afterwards, and a process spawned during the call may be missing. Useful for diagnostics, dashboards, and targeted per-pid action.
§Platform support
- Windows — every pid assigned to the Job Object (the whole tree).
- Linux cgroup — every pid in the cgroup (
cgroup.procs, whole tree). - Linux process-group fallback, macOS/BSD — the tracked group leaders, plus any individually-tracked adopted child (one pid per spawned/adopted child); descendants inside the groups are contained but not enumerated. An exited child still counts as a member until it is reaped (awaited): the liveness probe sees the not-yet-collected process.
§Errors
Error::Io if the group’s membership cannot be read (e.g. a failed
cgroup.procs read or Job Object query).
Sourcepub fn members_info(&self) -> Result<Vec<MemberInfo>>
Available on crate feature process-control only.
pub fn members_info(&self) -> Result<Vec<MemberInfo>>
process-control only.An enriched, point-in-time snapshot of the group’s members — the same set
as members, but each pid carried in a MemberInfo
alongside best-effort parent pid, image name, and start time.
The metadata-carrying companion to members: use it for
diagnostics that want more than bare pids (a members_snapshot event, a
process tree view). Which processes appear is identical to
members — see its platform matrix — and each enriching
field is None wherever the platform can’t report it, never a fabricated
value (full per-field matrix on MemberInfo).
§Platform support
- Windows — the whole tree (every pid in the Job Object); ppid and image
name from one
Toolhelp32process snapshot, start time (creationFILETIME) per pid. - Linux cgroup — the whole tree (
cgroup.procs); ppid,commimage name, and start time from one/proc/<pid>/statread each. - Linux process-group fallback — the tracked group leaders (as
members), enriched from/procthe same way. - macOS — the tracked leaders; ppid / image name / start time via
proc_pidinfo. - the BSDs — the tracked leaders with every enriching field
None(no wired-up per-process reader — seeMemberInfo::start_time); the pid is still reported, which is a correct result, not an error.
§Racing a member that exits
A point-in-time snapshot taken per pid: if a member exits between its
pid being enumerated and its metadata being read, that pid is skipped
(omitted from the Vec) rather than reported with fabricated fields — one
vanished member never fails the whole call. A member that is still present
but for which only some finer field can’t be read (e.g. its start-time
handle just closed) is kept, with that field None.
§No command line
The raw argv / environment is deliberately never included, on any platform — a command line routinely carries secrets, and redaction is the consumer’s policy to own (the crate’s standing “never argv/env” stance).
§Errors
Error::Io only if the group’s membership cannot be read (the same
failure as members — a failed cgroup.procs read or Job
Object query) or, on Windows, if the process-metadata snapshot cannot be
created at all. A single member vanishing is not an error (it is skipped).
Sourcepub async fn shutdown(self) -> Result<()>
pub async fn shutdown(self) -> Result<()>
Gracefully tear the group down, consuming it.
On Unix: SIGTERM the tree, wait up to shutdown_timeout, then SIGKILL
survivors when escalate_to_kill is set. On Windows the kill is atomic.
Dropping the group instead (without calling this) performs only the hard
kill.
Reap your children, or the grace is wasted (POSIX process-group
mechanism only). On the Mechanism::ProcessGroup
fallback (macOS/the BSDs, and Linux without a usable cgroup), liveness is
probed by signalling the group id, and an unreaped zombie still answers
— its process-group entry survives until the child is waited. So a child
that exits promptly on SIGTERM but whose RunningProcess
handle was dropped without being awaited (or is still held un-awaited) reads
as alive for the full shutdown_timeout, and shutdown then burns the
whole grace plus a pointless SIGKILL escalation. Await each child you
start into the group (any consuming verb, or wait) so its handle reaps it.
The Windows Job Object and Linux cgroup mechanisms are immune (a process
leaves cgroup.procs / the job on exit, before reaping).
When escalate_to_kill is set, the final hard kill can surface the same
errors as kill_all: the undrained-tree Err on the
legacy pre-5.14 per-pid fallback, and — on the process-group mechanism — a
live, non-zombie member that rejects SIGKILL with EPERM (a uid-changed
child). A harmless zombie-only group is not reported (see
kill_all).
Holding the group behind a shared handle (an Arc, a long-lived
supervisor) that can’t be moved out by value? Use the borrowing twin
shutdown_ref — same teardown, &self.
§Errors
Error::Io if the graceful teardown fails — including, when
escalate_to_kill performs the final hard kill, the same failures as
kill_all: the undrained-tree failure on the legacy
pre-5.14 per-pid fallback, and a process-group member that rejects SIGKILL
with EPERM while still alive.
Sourcepub async fn shutdown_ref(&self) -> Result<()>
pub async fn shutdown_ref(&self) -> Result<()>
Gracefully tear the group down without consuming it — the borrowing
twin of shutdown, for a group held behind a shared
handle (an Arc, a supervisor) that cannot be moved out by value to call
the consuming form.
Identical teardown to shutdown: on Unix, SIGTERM the
tree, wait up to the configured
shutdown_timeout, then SIGKILL
survivors when escalate_to_kill
is set; on Windows the kill is atomic and the timeout is ignored. The group
stays usable afterwards (a re-shutdown_ref on an already-drained tree is a
near no-op). Spawning or adopting a new child re-arms Drop’s kill
backstop for the whole group, so a straggler started after — or
concurrently with — this shutdown is still torn down on Drop: a
non-escalating shutdown that is still in flight when the child joins cannot
silently strip the newcomer of its backstop (its spare is keyed to a
generation the join bumps). A group left untouched keeps the survivors an
escalate_to_kill = false
shutdown chose to spare.
The same reaping caveat as shutdown applies on the
POSIX process-group mechanism: await each child you started into the group,
or an unreaped zombie reads as alive for the whole grace.
§Errors
Error::Io if the graceful teardown fails (see
shutdown — the same undrained-tree failure on the legacy
per-pid fallback and the process-group live-EPERM on the final hard kill
apply).
Sourcepub fn stats(&self) -> Result<ProcessGroupStats>
Available on crate feature stats only.
pub fn stats(&self) -> Result<ProcessGroupStats>
stats only.Snapshot the group’s resource usage (active process count and, where the
platform supports it, total CPU time and peak memory). See
ProcessGroupStats.
§Errors
Error::Io if the platform’s resource query fails.
Sourcepub fn sample_stats(&self, every: Duration) -> StatsSampler<'_>
Available on crate feature stats only.
pub fn sample_stats(&self, every: Duration) -> StatsSampler<'_>
stats only.Source§impl ProcessGroup
impl ProcessGroup
Sourcepub async fn start(&self, command: &Command) -> Result<RunningProcess>
pub async fn start(&self, command: &Command) -> Result<RunningProcess>
Start command as a member of this (shared) group and return a live
handle. The handle does not own the group, so dropping it leaves the
group and any sibling processes intact — the caller controls teardown.
§Errors
The launch surface: Error::NotFound /
Error::Spawn (locate/start failure),
Error::Unsupported (a POSIX-only primitive
unavailable on this platform),
Error::Cancelled (a pre-cancelled token), or
Error::Io (e.g. a one-shot stdin source already
consumed). Unlike JobRunner::start, no new group is created here — the
child joins this existing group.
Trait Implementations§
Source§impl Debug for ProcessGroup
impl Debug for ProcessGroup
Source§impl ProcessRunner for ProcessGroup
impl ProcessRunner for ProcessGroup
Source§fn output_string<'life0, 'life1, 'async_trait>(
&'life0 self,
command: &'life1 Command,
) -> Pin<Box<dyn Future<Output = Result<ProcessResult<String>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn output_string<'life0, 'life1, 'async_trait>(
&'life0 self,
command: &'life1 Command,
) -> Pin<Box<dyn Future<Output = Result<ProcessResult<String>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
command to completion, capturing stdout/stderr and the exit code.
A non-zero exit is reported in the result, not raised.Source§fn start<'life0, 'life1, 'async_trait>(
&'life0 self,
command: &'life1 Command,
) -> Pin<Box<dyn Future<Output = Result<RunningProcess>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn start<'life0, 'life1, 'async_trait>(
&'life0 self,
command: &'life1 Command,
) -> Pin<Box<dyn Future<Output = Result<RunningProcess>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
command and return a live RunningProcess for streaming,
readiness probes, or incremental consumption. Read moreSource§fn output_bytes<'life0, 'life1, 'async_trait>(
&'life0 self,
command: &'life1 Command,
) -> Pin<Box<dyn Future<Output = Result<ProcessResult<Vec<u8>>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn output_bytes<'life0, 'life1, 'async_trait>(
&'life0 self,
command: &'life1 Command,
) -> Pin<Box<dyn Future<Output = Result<ProcessResult<Vec<u8>>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
command to completion, capturing stdout as raw bytes (output_string
captures it as lossy-UTF-8 text); stderr is still text. For binary tools
— git cat-file, tar -c, an image transcoder — whose stdout is not
UTF-8. Read moreAuto Trait Implementations§
impl !Freeze for ProcessGroup
impl RefUnwindSafe for ProcessGroup
impl Send for ProcessGroup
impl Sync for ProcessGroup
impl Unpin for ProcessGroup
impl UnsafeUnpin for ProcessGroup
impl UnwindSafe for ProcessGroup
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> ProcessRunnerExt for Twhere
T: ProcessRunner + ?Sized,
impl<T> ProcessRunnerExt for Twhere
T: ProcessRunner + ?Sized,
Source§fn run<'life0, 'life1, 'async_trait>(
&'life0 self,
command: &'life1 Command,
) -> Pin<Box<dyn Future<Output = Result<String>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn run<'life0, 'life1, 'async_trait>(
&'life0 self,
command: &'life1 Command,
) -> Pin<Box<dyn Future<Output = Result<String>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
0 by default, widened by Command::ok_codes;
any other code is Error::Exit.Source§fn run_unit<'life0, 'life1, 'async_trait>(
&'life0 self,
command: &'life1 Command,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn run_unit<'life0, 'life1, 'async_trait>(
&'life0 self,
command: &'life1 Command,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
0, or any code in
Command::ok_codes), discard the output.Source§fn exit_code<'life0, 'life1, 'async_trait>(
&'life0 self,
command: &'life1 Command,
) -> Pin<Box<dyn Future<Output = Result<i32>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn exit_code<'life0, 'life1, 'async_trait>(
&'life0 self,
command: &'life1 Command,
) -> Pin<Box<dyn Future<Output = Result<i32>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Error::Timeout, a
signal-kill as Error::Signalled — rather than a
synthetic sentinel, mirroring
ensure_success.Source§fn probe<'life0, 'life1, 'async_trait>(
&'life0 self,
command: &'life1 Command,
) -> Pin<Box<dyn Future<Output = Result<bool>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn probe<'life0, 'life1, 'async_trait>(
&'life0 self,
command: &'life1 Command,
) -> Pin<Box<dyn Future<Output = Result<bool>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
0 →
Ok(true), exit 1 → Ok(false), anything else → Err (other code as
Error::Exit, timeout as
Error::Timeout, signal-kill as
Error::Signalled). For
commands whose exit code is the answer — git diff --quiet, grep -q, …Source§fn checked<'life0, 'life1, 'async_trait>(
&'life0 self,
command: &'life1 Command,
) -> Pin<Box<dyn Future<Output = Result<ProcessResult<String>>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn checked<'life0, 'life1, 'async_trait>(
&'life0 self,
command: &'life1 Command,
) -> Pin<Box<dyn Future<Output = Result<ProcessResult<String>>> + Send + 'async_trait>>where
Self: Sync + 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
0 by default, widened by
Command::ok_codes), and return the full
captured result (untrimmed stdout). The building block for the
parse/try_parse helpers — use it when you need the whole
ProcessResult after success-checking, rather than just trimmed stdout
(run) or the raw result (output_string). Read moreSource§fn parse<'life0, 'life1, 'async_trait, T, F>(
&'life0 self,
command: &'life1 Command,
parse: F,
) -> Pin<Box<dyn Future<Output = Result<T>> + Send + 'async_trait>>
fn parse<'life0, 'life1, 'async_trait, T, F>( &'life0 self, command: &'life1 Command, parse: F, ) -> Pin<Box<dyn Future<Output = Result<T>> + Send + 'async_trait>>
parse closure — the shape of struct-returning CLI
commands (git/jj --format output). Built on checked,
but unlike it, fails loud on a bounded-buffer truncation so the
parser never silently sees a clipped tail; returns the parsed value. Read moreSource§fn try_parse<'life0, 'life1, 'async_trait, T, F>(
&'life0 self,
command: &'life1 Command,
parse: F,
) -> Pin<Box<dyn Future<Output = Result<T>> + Send + 'async_trait>>
fn try_parse<'life0, 'life1, 'async_trait, T, F>( &'life0 self, command: &'life1 Command, parse: F, ) -> Pin<Box<dyn Future<Output = Result<T>> + Send + 'async_trait>>
parse closure — the shape of JSON deserialization, where a
parse failure becomes Error::Parse (or whatever
error the closure returns). Like parse it is built on
checked, fails loud on truncation, and — being generic
over F — cannot be dispatched through a dyn ProcessRunnerExt object
(the trait isn’t object-safe), though it is callable on a
&dyn ProcessRunner. The Command::try_parse /
CliClient::try_parse wrappers are the
ergonomic path.Source§fn first_line<'life0, 'life1, 'async_trait, F>(
&'life0 self,
command: &'life1 Command,
predicate: F,
) -> Pin<Box<dyn Future<Output = Result<Option<String>>> + Send + 'async_trait>>
fn first_line<'life0, 'life1, 'async_trait, F>( &'life0 self, command: &'life1 Command, predicate: F, ) -> Pin<Box<dyn Future<Output = Result<Option<String>>> + Send + 'async_trait>>
command’s stdout and return the first line matching predicate
(None if the stream ends first), bounded by the command’s
timeout: a Some deadline surfaces as
Error::Timeout and tears the process down. On an
own-group runner (JobRunner, the default) that teardown covers the
whole tree; on a shared ProcessGroup it reaches
the run’s direct child by pid — a forking child’s grandchildren (and, on the
Linux cgroup mechanism, a direct child that catches the graceful signal and
closes stdout but keeps running) may outlive the probe until the group is
dropped. Bound such a run with a whole-chain owner instead. Read more