use std::path::{Path, PathBuf};
use std::time::Duration;
use crate::command::contains_nul;
use crate::{CommandError, CommandSpec, EnvironmentSpec, StdioSpec, TimeoutPolicy};
use cageforge_path::contains_parent_traversal;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CommandRequest {
command: CommandSpec,
working_directory: Option<PathBuf>,
environment: EnvironmentSpec,
stdio: StdioSpec,
timeout: TimeoutPolicy,
}
impl CommandRequest {
pub fn new(command: CommandSpec) -> Self {
Self {
command,
working_directory: None,
environment: EnvironmentSpec::default(),
stdio: StdioSpec::default(),
timeout: TimeoutPolicy::default(),
}
}
pub fn with_working_directory(
mut self,
path: impl Into<PathBuf>,
) -> Result<Self, CommandError> {
let path = path.into();
if path.as_os_str().is_empty() {
return Err(CommandError::EmptyWorkingDirectory);
}
if contains_nul(path.as_os_str()) {
return Err(CommandError::WorkingDirectoryContainsNul);
}
if contains_parent_traversal(&path) {
return Err(CommandError::WorkingDirectoryParentTraversal { path });
}
self.working_directory = Some(path);
Ok(self)
}
pub fn without_working_directory(mut self) -> Self {
self.working_directory = None;
self
}
pub fn with_environment(mut self, environment: EnvironmentSpec) -> Self {
self.environment = environment;
self
}
pub fn with_stdio(mut self, stdio: StdioSpec) -> Self {
self.stdio = stdio;
self
}
pub fn with_timeout(mut self, timeout: Duration) -> Self {
self.timeout = TimeoutPolicy::Limit(timeout);
self
}
pub fn with_timeout_policy(mut self, timeout: TimeoutPolicy) -> Self {
self.timeout = timeout;
self
}
pub fn use_backend_timeout(mut self) -> Self {
self.timeout = TimeoutPolicy::BackendDefault;
self
}
pub fn disable_timeout(mut self) -> Self {
self.timeout = TimeoutPolicy::Disabled;
self
}
pub fn command(&self) -> &CommandSpec {
&self.command
}
pub fn working_directory(&self) -> Option<&Path> {
self.working_directory.as_deref()
}
pub fn environment(&self) -> &EnvironmentSpec {
&self.environment
}
pub fn stdio(&self) -> StdioSpec {
self.stdio
}
pub fn timeout_policy(&self) -> TimeoutPolicy {
self.timeout
}
}