cageforge_command/
request.rs1use std::path::{Path, PathBuf};
11use std::time::Duration;
12
13use crate::command::contains_nul;
14use crate::{CommandError, CommandSpec, EnvironmentSpec, StdioSpec, TimeoutPolicy};
15use cageforge_path::contains_parent_traversal;
16
17#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct CommandRequest {
25 command: CommandSpec,
26 working_directory: Option<PathBuf>,
27 environment: EnvironmentSpec,
28 stdio: StdioSpec,
29 timeout: TimeoutPolicy,
30}
31
32impl CommandRequest {
33 pub fn new(command: CommandSpec) -> Self {
36 Self {
37 command,
38 working_directory: None,
39 environment: EnvironmentSpec::default(),
40 stdio: StdioSpec::default(),
41 timeout: TimeoutPolicy::default(),
42 }
43 }
44
45 pub fn with_working_directory(
52 mut self,
53 path: impl Into<PathBuf>,
54 ) -> Result<Self, CommandError> {
55 let path = path.into();
56 if path.as_os_str().is_empty() {
57 return Err(CommandError::EmptyWorkingDirectory);
58 }
59 if contains_nul(path.as_os_str()) {
60 return Err(CommandError::WorkingDirectoryContainsNul);
61 }
62 if contains_parent_traversal(&path) {
63 return Err(CommandError::WorkingDirectoryParentTraversal { path });
64 }
65 self.working_directory = Some(path);
66 Ok(self)
67 }
68
69 pub fn without_working_directory(mut self) -> Self {
71 self.working_directory = None;
72 self
73 }
74
75 pub fn with_environment(mut self, environment: EnvironmentSpec) -> Self {
77 self.environment = environment;
78 self
79 }
80
81 pub fn with_stdio(mut self, stdio: StdioSpec) -> Self {
83 self.stdio = stdio;
84 self
85 }
86
87 pub fn with_timeout(mut self, timeout: Duration) -> Self {
89 self.timeout = TimeoutPolicy::Limit(timeout);
90 self
91 }
92
93 pub fn with_timeout_policy(mut self, timeout: TimeoutPolicy) -> Self {
95 self.timeout = timeout;
96 self
97 }
98
99 pub fn use_backend_timeout(mut self) -> Self {
101 self.timeout = TimeoutPolicy::BackendDefault;
102 self
103 }
104
105 pub fn disable_timeout(mut self) -> Self {
108 self.timeout = TimeoutPolicy::Disabled;
109 self
110 }
111
112 pub fn command(&self) -> &CommandSpec {
114 &self.command
115 }
116
117 pub fn working_directory(&self) -> Option<&Path> {
119 self.working_directory.as_deref()
120 }
121
122 pub fn environment(&self) -> &EnvironmentSpec {
124 &self.environment
125 }
126
127 pub fn stdio(&self) -> StdioSpec {
129 self.stdio
130 }
131
132 pub fn timeout_policy(&self) -> TimeoutPolicy {
134 self.timeout
135 }
136}