conch_runtime_pshaw/env/
cur_dir.rs1use crate::env::SubEnvironment;
2use crate::path::NormalizedPath;
3use std::borrow::Cow;
4use std::env;
5use std::io;
6use std::path::{Path, PathBuf};
7use std::sync::Arc;
8
9pub trait WorkingDirectoryEnvironment {
11 fn path_relative_to_working_dir<'a>(&self, path: Cow<'a, Path>) -> Cow<'a, Path>;
13
14 fn current_working_dir(&self) -> &Path;
16}
17
18impl<'b, T: ?Sized + WorkingDirectoryEnvironment> WorkingDirectoryEnvironment for &'b T {
19 fn path_relative_to_working_dir<'a>(&self, path: Cow<'a, Path>) -> Cow<'a, Path> {
20 (**self).path_relative_to_working_dir(path)
21 }
22
23 fn current_working_dir(&self) -> &Path {
24 (**self).current_working_dir()
25 }
26}
27
28impl<'b, T: ?Sized + WorkingDirectoryEnvironment> WorkingDirectoryEnvironment for &'b mut T {
29 fn path_relative_to_working_dir<'a>(&self, path: Cow<'a, Path>) -> Cow<'a, Path> {
30 (**self).path_relative_to_working_dir(path)
31 }
32
33 fn current_working_dir(&self) -> &Path {
34 (**self).current_working_dir()
35 }
36}
37
38pub trait ChangeWorkingDirectoryEnvironment: WorkingDirectoryEnvironment {
40 fn change_working_dir<'a>(&mut self, path: Cow<'a, Path>) -> io::Result<()>;
45}
46
47impl<'b, T: ?Sized> ChangeWorkingDirectoryEnvironment for &'b mut T
48where
49 T: ChangeWorkingDirectoryEnvironment,
50{
51 fn change_working_dir<'a>(&mut self, path: Cow<'a, Path>) -> io::Result<()> {
52 (**self).change_working_dir(path)
53 }
54}
55
56#[derive(Debug, Clone, PartialEq, Eq)]
62pub struct VirtualWorkingDirEnv {
63 cwd: Arc<NormalizedPath>,
64}
65
66impl VirtualWorkingDirEnv {
67 pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Self> {
71 Self::with_path_buf(path.as_ref().to_path_buf())
72 }
73
74 pub fn with_path_buf(path: PathBuf) -> io::Result<Self> {
78 if path.is_absolute() {
79 let normalized = NormalizedPath::new_normalized_logical(path);
80 if normalized.is_dir() {
81 Ok(Self {
82 cwd: Arc::new(normalized),
83 })
84 } else {
85 let msg = format!("not a directory: {}", normalized.display());
86 Err(io::Error::new(io::ErrorKind::NotFound, msg))
87 }
88 } else {
89 let msg = format!("specified path not absolute: {}", path.display());
90 Err(io::Error::new(io::ErrorKind::InvalidInput, msg))
91 }
92 }
93
94 pub fn with_process_working_dir() -> io::Result<Self> {
97 env::current_dir().and_then(Self::with_path_buf)
98 }
99}
100
101impl WorkingDirectoryEnvironment for VirtualWorkingDirEnv {
102 fn path_relative_to_working_dir<'a>(&self, path: Cow<'a, Path>) -> Cow<'a, Path> {
103 if path.is_absolute() {
104 path
105 } else {
106 let mut new_cwd = (*self.cwd).clone();
107 new_cwd.join_normalized_logial(&path);
108
109 Cow::Owned(new_cwd.into_inner())
110 }
111 }
112
113 fn current_working_dir(&self) -> &Path {
114 &*self.cwd
115 }
116}
117
118impl ChangeWorkingDirectoryEnvironment for VirtualWorkingDirEnv {
119 fn change_working_dir<'a>(&mut self, path: Cow<'a, Path>) -> io::Result<()> {
120 let mut new_cwd = (*self.cwd).clone();
121 new_cwd.join_normalized_logial(&path);
126
127 if new_cwd.is_dir() {
128 self.cwd = Arc::new(new_cwd);
129 Ok(())
130 } else {
131 let msg = format!("not a directory: {}", new_cwd.display());
132 Err(io::Error::new(io::ErrorKind::NotFound, msg))
133 }
134 }
135}
136
137impl SubEnvironment for VirtualWorkingDirEnv {
138 fn sub_env(&self) -> Self {
139 self.clone()
140 }
141}