use crate::PathSelector;
use crate::PolicyError;
use cageforge_path::NativePathKey;
use std::collections::HashSet;
use std::path::Path;
use std::path::PathBuf;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct PathResolutionContext {
root_paths: Vec<PathBuf>,
root_keys: HashSet<NativePathKey>,
workspace_roots: Vec<PathBuf>,
workspace_root_keys: HashSet<NativePathKey>,
minimal_paths: Vec<PathBuf>,
minimal_path_keys: HashSet<NativePathKey>,
executable_roots: Vec<PathBuf>,
executable_root_keys: HashSet<NativePathKey>,
tmpdir: Option<PathBuf>,
slash_tmp: Option<PathBuf>,
current_directory: Option<PathBuf>,
}
impl PathResolutionContext {
pub fn new() -> Self {
Self {
root_paths: Vec::new(),
root_keys: HashSet::new(),
workspace_roots: Vec::new(),
workspace_root_keys: HashSet::new(),
minimal_paths: Vec::new(),
minimal_path_keys: HashSet::new(),
executable_roots: Vec::new(),
executable_root_keys: HashSet::new(),
tmpdir: None,
slash_tmp: None,
current_directory: None,
}
}
pub fn with_root(mut self, path: impl Into<PathBuf>) -> Result<Self, PolicyError> {
let path = validated_absolute(path.into())?;
if self.root_keys.insert(NativePathKey::new(&path)) {
self.root_paths.push(path);
}
Ok(self)
}
pub fn with_workspace_root(mut self, path: impl Into<PathBuf>) -> Result<Self, PolicyError> {
let path = validated_absolute(path.into())?;
if self.workspace_root_keys.insert(NativePathKey::new(&path)) {
self.workspace_roots.push(path);
}
Ok(self)
}
pub fn with_minimal_path(mut self, path: impl Into<PathBuf>) -> Result<Self, PolicyError> {
let path = validated_absolute(path.into())?;
if self.minimal_path_keys.insert(NativePathKey::new(&path)) {
self.minimal_paths.push(path);
}
Ok(self)
}
pub fn with_executable_root(mut self, path: impl Into<PathBuf>) -> Result<Self, PolicyError> {
let path = validated_absolute(path.into())?;
if self.executable_root_keys.insert(NativePathKey::new(&path)) {
self.executable_roots.push(path);
}
Ok(self)
}
pub fn with_tmpdir(mut self, path: impl Into<PathBuf>) -> Result<Self, PolicyError> {
self.tmpdir = Some(validated_absolute(path.into())?);
Ok(self)
}
pub fn with_slash_tmp(mut self, path: impl Into<PathBuf>) -> Result<Self, PolicyError> {
self.slash_tmp = Some(validated_absolute(path.into())?);
Ok(self)
}
pub fn with_current_directory(mut self, path: impl Into<PathBuf>) -> Result<Self, PolicyError> {
self.current_directory = Some(validated_absolute(path.into())?);
Ok(self)
}
pub fn workspace_roots(&self) -> &[PathBuf] {
&self.workspace_roots
}
pub fn root_paths(&self) -> &[PathBuf] {
&self.root_paths
}
pub fn minimal_paths(&self) -> &[PathBuf] {
&self.minimal_paths
}
pub fn executable_roots(&self) -> &[PathBuf] {
&self.executable_roots
}
pub fn tmpdir(&self) -> Option<&Path> {
self.tmpdir.as_deref()
}
pub fn slash_tmp(&self) -> Option<&Path> {
self.slash_tmp.as_deref()
}
pub fn current_directory(&self) -> Option<&Path> {
self.current_directory.as_deref()
}
}
fn validated_absolute(path: PathBuf) -> Result<PathBuf, PolicyError> {
PathSelector::absolute(path)?
.path()
.map(Path::to_path_buf)
.ok_or_else(|| PolicyError::InvalidContext {
message: "absolute path validation returned a non-absolute selector".to_string(),
})
}