cageforge_policy/
context.rs1use crate::PathSelector;
10use crate::PolicyError;
11use cageforge_path::NativePathKey;
12use std::collections::HashSet;
13use std::path::Path;
14use std::path::PathBuf;
15
16#[derive(Debug, Clone, Default, PartialEq, Eq)]
21pub struct PathResolutionContext {
22 root_paths: Vec<PathBuf>,
23 root_keys: HashSet<NativePathKey>,
24 workspace_roots: Vec<PathBuf>,
25 workspace_root_keys: HashSet<NativePathKey>,
26 minimal_paths: Vec<PathBuf>,
27 minimal_path_keys: HashSet<NativePathKey>,
28 tmpdir: Option<PathBuf>,
29 slash_tmp: Option<PathBuf>,
30 current_directory: Option<PathBuf>,
31}
32
33impl PathResolutionContext {
34 pub fn new() -> Self {
36 Self {
37 root_paths: Vec::new(),
38 root_keys: HashSet::new(),
39 workspace_roots: Vec::new(),
40 workspace_root_keys: HashSet::new(),
41 minimal_paths: Vec::new(),
42 minimal_path_keys: HashSet::new(),
43 tmpdir: None,
44 slash_tmp: None,
45 current_directory: None,
46 }
47 }
48
49 pub fn with_root(mut self, path: impl Into<PathBuf>) -> Result<Self, PolicyError> {
55 let path = validated_absolute(path.into())?;
56 if self.root_keys.insert(NativePathKey::new(&path)) {
57 self.root_paths.push(path);
58 }
59 Ok(self)
60 }
61
62 pub fn with_workspace_root(mut self, path: impl Into<PathBuf>) -> Result<Self, PolicyError> {
64 let path = validated_absolute(path.into())?;
65 if self.workspace_root_keys.insert(NativePathKey::new(&path)) {
66 self.workspace_roots.push(path);
67 }
68 Ok(self)
69 }
70
71 pub fn with_minimal_path(mut self, path: impl Into<PathBuf>) -> Result<Self, PolicyError> {
73 let path = validated_absolute(path.into())?;
74 if self.minimal_path_keys.insert(NativePathKey::new(&path)) {
75 self.minimal_paths.push(path);
76 }
77 Ok(self)
78 }
79
80 pub fn with_tmpdir(mut self, path: impl Into<PathBuf>) -> Result<Self, PolicyError> {
82 self.tmpdir = Some(validated_absolute(path.into())?);
83 Ok(self)
84 }
85
86 pub fn with_slash_tmp(mut self, path: impl Into<PathBuf>) -> Result<Self, PolicyError> {
88 self.slash_tmp = Some(validated_absolute(path.into())?);
89 Ok(self)
90 }
91
92 pub fn with_current_directory(mut self, path: impl Into<PathBuf>) -> Result<Self, PolicyError> {
98 self.current_directory = Some(validated_absolute(path.into())?);
99 Ok(self)
100 }
101
102 pub fn workspace_roots(&self) -> &[PathBuf] {
104 &self.workspace_roots
105 }
106
107 pub fn root_paths(&self) -> &[PathBuf] {
109 &self.root_paths
110 }
111
112 pub fn minimal_paths(&self) -> &[PathBuf] {
114 &self.minimal_paths
115 }
116
117 pub fn tmpdir(&self) -> Option<&Path> {
119 self.tmpdir.as_deref()
120 }
121
122 pub fn slash_tmp(&self) -> Option<&Path> {
124 self.slash_tmp.as_deref()
125 }
126
127 pub fn current_directory(&self) -> Option<&Path> {
130 self.current_directory.as_deref()
131 }
132}
133
134fn validated_absolute(path: PathBuf) -> Result<PathBuf, PolicyError> {
135 PathSelector::absolute(path)?
136 .path()
137 .map(Path::to_path_buf)
138 .ok_or_else(|| PolicyError::InvalidContext {
139 message: "absolute path validation returned a non-absolute selector".to_string(),
140 })
141}