Skip to main content

rskit_process/command/
spec.rs

1//! What to execute as a subprocess and how to build it.
2
3use std::collections::HashMap;
4use std::ffi::OsString;
5use std::path::PathBuf;
6
7/// Command environment policy.
8#[derive(Debug, Clone, Copy, Eq, PartialEq)]
9#[non_exhaustive]
10pub enum EnvPolicy {
11    /// Inherit parent environment variables, then apply explicit overrides.
12    Inherit,
13    /// Start from an empty environment, then apply explicit variables.
14    Empty,
15}
16
17/// What to execute as a subprocess.
18#[derive(Debug, Clone, Eq, PartialEq)]
19pub struct ProcessSpec {
20    /// Program name or path to execute.
21    pub program: PathBuf,
22    /// Command-line arguments.
23    pub args: Vec<OsString>,
24    /// Working directory for the process.
25    pub dir: Option<PathBuf>,
26    /// Environment variables to set.
27    pub env: HashMap<String, String>,
28    /// Environment inheritance policy.
29    pub env_policy: EnvPolicy,
30}
31
32impl ProcessSpec {
33    /// Create a new process spec with just a program name.
34    #[must_use]
35    pub fn new<P: Into<PathBuf>>(program: P) -> Self {
36        Self {
37            program: program.into(),
38            args: Vec::new(),
39            dir: None,
40            env: HashMap::new(),
41            env_policy: EnvPolicy::Inherit,
42        }
43    }
44
45    /// Add a command-line argument.
46    #[must_use]
47    pub fn arg<S: Into<OsString>>(mut self, arg: S) -> Self {
48        self.args.push(arg.into());
49        self
50    }
51
52    /// Add multiple command-line arguments.
53    #[must_use]
54    pub fn args<I>(mut self, args: I) -> Self
55    where
56        I: IntoIterator,
57        I::Item: Into<OsString>,
58    {
59        self.args.extend(args.into_iter().map(Into::into));
60        self
61    }
62
63    /// Set the working directory.
64    #[must_use]
65    pub fn dir<P: Into<PathBuf>>(mut self, dir: P) -> Self {
66        self.dir = Some(dir.into());
67        self
68    }
69
70    /// Set an environment variable.
71    #[must_use]
72    pub fn env<K: Into<String>, V: Into<String>>(mut self, key: K, value: V) -> Self {
73        self.env.insert(key.into(), value.into());
74        self
75    }
76
77    /// Set multiple environment variables.
78    #[must_use]
79    pub fn envs<K: Into<String>, V: Into<String>, I: IntoIterator<Item = (K, V)>>(
80        mut self,
81        vars: I,
82    ) -> Self {
83        for (k, v) in vars {
84            self.env.insert(k.into(), v.into());
85        }
86        self
87    }
88
89    /// Set the environment policy.
90    #[must_use]
91    pub fn env_policy(mut self, policy: EnvPolicy) -> Self {
92        self.env_policy = policy;
93        self
94    }
95
96    /// Start the process with an empty environment.
97    #[must_use]
98    pub fn empty_env(mut self) -> Self {
99        self.env_policy = EnvPolicy::Empty;
100        self
101    }
102}
103
104/// Create a subprocess specification.
105#[must_use]
106pub fn command<P: Into<PathBuf>>(program: P) -> ProcessSpec {
107    ProcessSpec::new(program)
108}