Skip to main content

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}