perl_subprocess_runtime/os_runtime/mod.rs
1//! OS-backed subprocess runtime.
2
3mod invocation;
4mod process;
5mod validation;
6#[cfg(windows)]
7mod windows;
8
9pub(crate) use invocation::resolve_command_invocation;
10use process::run_os_command;
11
12use crate::{SubprocessError, SubprocessOutput, SubprocessRuntime};
13
14#[cfg(all(windows, test))]
15pub(crate) use windows::{windows_program_priority, windows_quote_for_cmd};
16
17/// Default implementation using `std::process::Command`.
18pub struct OsSubprocessRuntime {
19 timeout_secs: Option<u64>,
20}
21
22impl OsSubprocessRuntime {
23 /// Create a new OS subprocess runtime with no timeout.
24 pub fn new() -> Self {
25 Self { timeout_secs: None }
26 }
27
28 /// Create a new OS subprocess runtime with the given wall-clock timeout.
29 ///
30 /// If the subprocess does not complete within `timeout_secs` seconds the
31 /// call returns a `SubprocessError` with a "timed out" message and attempts
32 /// to terminate the spawned process before returning.
33 ///
34 /// # Stdin size caveat
35 ///
36 /// Stdin data is written synchronously before the timeout poll loop begins.
37 /// If the subprocess hangs before consuming stdin and the data exceeds the
38 /// OS pipe buffer (~64 KiB on Linux), `run_command` will block in the write
39 /// phase and the timeout will not fire. For typical Perl source files this
40 /// is not a concern.
41 ///
42 /// # Panics
43 ///
44 /// Panics if `timeout_secs` is zero (a zero-second timeout would time out
45 /// every command immediately and is almost certainly a caller bug).
46 pub fn with_timeout(timeout_secs: u64) -> Self {
47 assert!(timeout_secs > 0, "timeout_secs must be greater than zero");
48 Self { timeout_secs: Some(timeout_secs) }
49 }
50}
51
52impl Default for OsSubprocessRuntime {
53 fn default() -> Self {
54 Self::new()
55 }
56}
57
58impl SubprocessRuntime for OsSubprocessRuntime {
59 fn run_command(
60 &self,
61 program: &str,
62 args: &[&str],
63 stdin: Option<&[u8]>,
64 ) -> Result<SubprocessOutput, SubprocessError> {
65 run_os_command(program, args, stdin, self.timeout_secs)
66 }
67}