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