1use crate::env::builtin::{BuiltinEnv, BuiltinEnvironment};
5use crate::env::{
6 ArgsEnv, ArgumentsEnvironment, AsyncIoEnvironment, ChangeWorkingDirectoryEnvironment,
7 ExecutableData, ExecutableEnvironment, ExportedVariableEnvironment, FileDescEnvironment,
8 FileDescOpener, FnEnv, FnFrameEnv, FunctionEnvironment, FunctionFrameEnvironment,
9 IsInteractiveEnvironment, LastStatusEnv, LastStatusEnvironment, Pipe, ReportErrorEnvironment,
10 SetArgumentsEnvironment, ShiftArgumentsEnvironment, StringWrapper, SubEnvironment,
11 TokioExecEnv, TokioFileDescManagerEnv, UnsetFunctionEnvironment, UnsetVariableEnvironment,
12 VarEnv, VariableEnvironment, VirtualWorkingDirEnv, WorkingDirectoryEnvironment,
13};
14use crate::error::{CommandError, RuntimeError};
15use crate::io::Permissions;
16use crate::{ExitStatus, Fd, Spawn, IFS_DEFAULT, STDERR_FILENO};
17use futures_core::future::BoxFuture;
18use std::borrow::{Borrow, Cow};
19use std::convert::From;
20use std::error::Error;
21use std::fmt;
22use std::fs::OpenOptions;
23use std::hash::Hash;
24use std::io;
25use std::marker::PhantomData;
26use std::path::Path;
27use std::sync::Arc;
28
29#[derive(Default, Debug, PartialEq, Eq, Clone)]
46pub struct EnvConfig<A, FM, L, V, EX, WD, B, N, ERR> {
47 pub interactive: bool,
49 pub args_env: A,
51 pub file_desc_manager_env: FM,
53 pub last_status_env: L,
55 pub var_env: V,
58 pub exec_env: EX,
60 pub working_dir_env: WD,
62 pub builtin_env: B,
64 pub fn_name: PhantomData<N>,
66 pub fn_error: PhantomData<ERR>,
68}
69
70impl<A, FM, L, V, EX, WD, B, N, ERR> EnvConfig<A, FM, L, V, EX, WD, B, N, ERR> {
71 pub fn change_args_env<T>(self, args_env: T) -> EnvConfig<T, FM, L, V, EX, WD, B, N, ERR> {
73 EnvConfig {
74 interactive: self.interactive,
75 args_env,
76 file_desc_manager_env: self.file_desc_manager_env,
77 last_status_env: self.last_status_env,
78 var_env: self.var_env,
79 exec_env: self.exec_env,
80 working_dir_env: self.working_dir_env,
81 builtin_env: self.builtin_env,
82 fn_name: self.fn_name,
83 fn_error: self.fn_error,
84 }
85 }
86
87 pub fn change_file_desc_manager_env<T>(
89 self,
90 file_desc_manager_env: T,
91 ) -> EnvConfig<A, T, L, V, EX, WD, B, N, ERR> {
92 EnvConfig {
93 interactive: self.interactive,
94 args_env: self.args_env,
95 file_desc_manager_env,
96 last_status_env: self.last_status_env,
97 var_env: self.var_env,
98 exec_env: self.exec_env,
99 working_dir_env: self.working_dir_env,
100 builtin_env: self.builtin_env,
101 fn_name: self.fn_name,
102 fn_error: self.fn_error,
103 }
104 }
105
106 pub fn change_last_status_env<T>(
108 self,
109 last_status_env: T,
110 ) -> EnvConfig<A, FM, T, V, EX, WD, B, N, ERR> {
111 EnvConfig {
112 interactive: self.interactive,
113 args_env: self.args_env,
114 file_desc_manager_env: self.file_desc_manager_env,
115 last_status_env,
116 var_env: self.var_env,
117 exec_env: self.exec_env,
118 working_dir_env: self.working_dir_env,
119 builtin_env: self.builtin_env,
120 fn_name: self.fn_name,
121 fn_error: self.fn_error,
122 }
123 }
124
125 pub fn change_var_env<T>(self, var_env: T) -> EnvConfig<A, FM, L, T, EX, WD, B, N, ERR> {
127 EnvConfig {
128 interactive: self.interactive,
129 args_env: self.args_env,
130 file_desc_manager_env: self.file_desc_manager_env,
131 last_status_env: self.last_status_env,
132 var_env,
133 exec_env: self.exec_env,
134 working_dir_env: self.working_dir_env,
135 builtin_env: self.builtin_env,
136 fn_name: self.fn_name,
137 fn_error: self.fn_error,
138 }
139 }
140
141 pub fn change_exec_env<T>(self, exec_env: T) -> EnvConfig<A, FM, L, V, T, WD, B, N, ERR> {
143 EnvConfig {
144 interactive: self.interactive,
145 args_env: self.args_env,
146 file_desc_manager_env: self.file_desc_manager_env,
147 last_status_env: self.last_status_env,
148 var_env: self.var_env,
149 exec_env,
150 working_dir_env: self.working_dir_env,
151 builtin_env: self.builtin_env,
152 fn_name: self.fn_name,
153 fn_error: self.fn_error,
154 }
155 }
156
157 pub fn change_working_dir_env<T>(
159 self,
160 working_dir_env: T,
161 ) -> EnvConfig<A, FM, L, V, EX, T, B, N, ERR> {
162 EnvConfig {
163 interactive: self.interactive,
164 args_env: self.args_env,
165 file_desc_manager_env: self.file_desc_manager_env,
166 last_status_env: self.last_status_env,
167 var_env: self.var_env,
168 exec_env: self.exec_env,
169 working_dir_env,
170 builtin_env: self.builtin_env,
171 fn_name: self.fn_name,
172 fn_error: self.fn_error,
173 }
174 }
175
176 pub fn change_builtin_env<T>(
178 self,
179 builtin_env: T,
180 ) -> EnvConfig<A, FM, L, V, EX, WD, T, N, ERR> {
181 EnvConfig {
182 interactive: self.interactive,
183 args_env: self.args_env,
184 file_desc_manager_env: self.file_desc_manager_env,
185 last_status_env: self.last_status_env,
186 var_env: self.var_env,
187 exec_env: self.exec_env,
188 working_dir_env: self.working_dir_env,
189 builtin_env,
190 fn_name: self.fn_name,
191 fn_error: self.fn_error,
192 }
193 }
194
195 pub fn change_fn_name<T>(self) -> EnvConfig<A, FM, L, V, EX, WD, B, T, ERR> {
197 EnvConfig {
198 interactive: self.interactive,
199 args_env: self.args_env,
200 file_desc_manager_env: self.file_desc_manager_env,
201 last_status_env: self.last_status_env,
202 var_env: self.var_env,
203 exec_env: self.exec_env,
204 working_dir_env: self.working_dir_env,
205 builtin_env: self.builtin_env,
206 fn_name: PhantomData,
207 fn_error: self.fn_error,
208 }
209 }
210
211 pub fn change_fn_error<T>(self) -> EnvConfig<A, FM, L, V, EX, WD, B, N, T> {
213 EnvConfig {
214 interactive: self.interactive,
215 args_env: self.args_env,
216 file_desc_manager_env: self.file_desc_manager_env,
217 last_status_env: self.last_status_env,
218 var_env: self.var_env,
219 exec_env: self.exec_env,
220 working_dir_env: self.working_dir_env,
221 builtin_env: self.builtin_env,
222 fn_name: self.fn_name,
223 fn_error: PhantomData,
224 }
225 }
226}
227
228pub type DefaultEnvConfig<T> = EnvConfig<
233 ArgsEnv<T>,
234 TokioFileDescManagerEnv,
235 LastStatusEnv,
236 VarEnv<T, T>,
237 TokioExecEnv,
238 VirtualWorkingDirEnv,
239 BuiltinEnv<T>,
240 T,
241 RuntimeError,
242>;
243
244pub type DefaultEnvConfigArc = DefaultEnvConfig<Arc<String>>;
247
248impl<T> DefaultEnvConfig<T>
249where
250 T: Eq + Hash + From<String>,
251{
252 pub fn new() -> io::Result<Self> {
254 let file_desc_manager_env = TokioFileDescManagerEnv::with_process_stdio()?;
255
256 Ok(DefaultEnvConfig {
257 interactive: false,
258 args_env: ArgsEnv::new(),
259 file_desc_manager_env,
260 last_status_env: LastStatusEnv::new(),
261 var_env: VarEnv::with_process_env_vars(),
262 exec_env: TokioExecEnv::new(),
263 working_dir_env: VirtualWorkingDirEnv::with_process_working_dir()?,
264 builtin_env: BuiltinEnv::new(),
265 fn_name: PhantomData,
266 fn_error: PhantomData,
267 })
268 }
269}
270
271pub struct Env<A, FM, L, V, EX, WD, B, N: Eq + Hash, ERR> {
274 interactive: bool,
276 args_env: A,
277 file_desc_manager_env: FM,
278 #[allow(clippy::type_complexity)]
279 fn_env:
280 FnEnv<N, Arc<dyn Spawn<Env<A, FM, L, V, EX, WD, B, N, ERR>, Error = ERR> + Send + Sync>>,
281 fn_frame_env: FnFrameEnv,
282 last_status_env: L,
283 var_env: V,
284 exec_env: EX,
285 working_dir_env: WD,
286 builtin_env: B,
287}
288
289impl<A, FM, L, V, EX, WD, B, N, ERR> Env<A, FM, L, V, EX, WD, B, N, ERR>
290where
291 N: Hash + Eq,
292{
293 pub fn with_config(cfg: EnvConfig<A, FM, L, V, EX, WD, B, N, ERR>) -> Self
309 where
310 V: ExportedVariableEnvironment,
311 V::VarName: From<String>,
312 V::Var: Borrow<String> + From<String> + Clone,
313 WD: WorkingDirectoryEnvironment,
314 {
315 let mut env = Env {
316 interactive: cfg.interactive,
317 args_env: cfg.args_env,
318 fn_env: FnEnv::new(),
319 fn_frame_env: FnFrameEnv::new(),
320 file_desc_manager_env: cfg.file_desc_manager_env,
321 last_status_env: cfg.last_status_env,
322 var_env: cfg.var_env,
323 exec_env: cfg.exec_env,
324 working_dir_env: cfg.working_dir_env,
325 builtin_env: cfg.builtin_env,
326 };
327
328 let sh_lvl = "SHLVL".to_owned().into();
329 let level = env
330 .var(&sh_lvl)
331 .and_then(|lvl| lvl.borrow().parse::<isize>().ok().map(|l| l + 1))
332 .unwrap_or(1)
333 .to_string()
334 .into();
335
336 let cwd: V::Var = env
337 .current_working_dir()
338 .to_string_lossy()
339 .into_owned()
340 .into();
341
342 env.set_exported_var(sh_lvl, level, true);
343 env.set_exported_var("PWD".to_owned().into(), cwd.clone(), true);
344 env.set_exported_var("OLDPWD".to_owned().into(), cwd, true);
345 env.set_var("IFS".to_owned().into(), IFS_DEFAULT.to_owned().into());
346 env
347 }
348}
349
350impl<A, FM, L, V, EX, WD, B, N, ERR> Clone for Env<A, FM, L, V, EX, WD, B, N, ERR>
351where
352 A: Clone,
353 FM: Clone,
354 L: Clone,
355 V: Clone,
356 B: Clone,
357 N: Hash + Eq,
358 EX: Clone,
359 WD: Clone,
360{
361 fn clone(&self) -> Self {
362 Env {
363 interactive: self.interactive,
364 args_env: self.args_env.clone(),
365 file_desc_manager_env: self.file_desc_manager_env.clone(),
366 fn_env: self.fn_env.clone(),
367 fn_frame_env: self.fn_frame_env,
368 last_status_env: self.last_status_env.clone(),
369 var_env: self.var_env.clone(),
370 exec_env: self.exec_env.clone(),
371 working_dir_env: self.working_dir_env.clone(),
372 builtin_env: self.builtin_env.clone(),
373 }
374 }
375}
376
377impl<A, FM, L, V, EX, WD, B, N, ERR> fmt::Debug for Env<A, FM, L, V, EX, WD, B, N, ERR>
378where
379 A: fmt::Debug,
380 FM: fmt::Debug,
381 L: fmt::Debug,
382 V: fmt::Debug,
383 B: fmt::Debug,
384 N: Hash + Eq + Ord + fmt::Debug,
385 EX: fmt::Debug,
386 WD: fmt::Debug,
387{
388 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
389 use std::collections::BTreeSet;
390 let fn_names: BTreeSet<_> = self.fn_env.fn_names().collect();
391
392 fmt.debug_struct(stringify!(Env))
393 .field("interactive", &self.interactive)
394 .field("args_env", &self.args_env)
395 .field("file_desc_manager_env", &self.file_desc_manager_env)
396 .field("functions", &fn_names)
397 .field("fn_frame_env", &self.fn_frame_env)
398 .field("last_status_env", &self.last_status_env)
399 .field("var_env", &self.var_env)
400 .field("exec_env", &self.exec_env)
401 .field("working_dir_env", &self.working_dir_env)
402 .field("builtin_env", &self.builtin_env)
403 .finish()
404 }
405}
406
407impl<A, FM, L, V, EX, WD, B, N, ERR> From<EnvConfig<A, FM, L, V, EX, WD, B, N, ERR>>
408 for Env<A, FM, L, V, EX, WD, B, N, ERR>
409where
410 N: Hash + Eq,
411 V: ExportedVariableEnvironment,
412 V::VarName: From<String>,
413 V::Var: Borrow<String> + From<String> + Clone,
414 WD: WorkingDirectoryEnvironment,
415{
416 fn from(cfg: EnvConfig<A, FM, L, V, EX, WD, B, N, ERR>) -> Self {
417 Self::with_config(cfg)
418 }
419}
420
421impl<A, FM, L, V, EX, WD, B, N, ERR> IsInteractiveEnvironment
422 for Env<A, FM, L, V, EX, WD, B, N, ERR>
423where
424 N: Hash + Eq,
425{
426 fn is_interactive(&self) -> bool {
427 self.interactive
428 }
429}
430
431impl<A, FM, L, V, EX, WD, B, N, ERR> SubEnvironment for Env<A, FM, L, V, EX, WD, B, N, ERR>
432where
433 A: SubEnvironment,
434 FM: SubEnvironment,
435 L: SubEnvironment,
436 V: SubEnvironment,
437 B: SubEnvironment,
438 N: Hash + Eq,
439 EX: SubEnvironment,
440 WD: SubEnvironment,
441{
442 fn sub_env(&self) -> Self {
443 Env {
444 interactive: self.is_interactive(),
445 args_env: self.args_env.sub_env(),
446 file_desc_manager_env: self.file_desc_manager_env.sub_env(),
447 fn_env: self.fn_env.sub_env(),
448 fn_frame_env: self.fn_frame_env.sub_env(),
449 last_status_env: self.last_status_env.sub_env(),
450 var_env: self.var_env.sub_env(),
451 exec_env: self.exec_env.sub_env(),
452 working_dir_env: self.working_dir_env.sub_env(),
453 builtin_env: self.builtin_env.sub_env(),
454 }
455 }
456}
457
458impl<A, FM, L, V, EX, WD, B, N, ERR> ArgumentsEnvironment for Env<A, FM, L, V, EX, WD, B, N, ERR>
459where
460 A: ArgumentsEnvironment,
461 A::Arg: Clone,
462 N: Hash + Eq,
463{
464 type Arg = A::Arg;
465
466 fn name(&self) -> &Self::Arg {
467 self.args_env.name()
468 }
469
470 fn arg(&self, idx: usize) -> Option<&Self::Arg> {
471 self.args_env.arg(idx)
472 }
473
474 fn args_len(&self) -> usize {
475 self.args_env.args_len()
476 }
477
478 fn args(&self) -> Cow<'_, [Self::Arg]> {
479 self.args_env.args()
480 }
481}
482
483impl<A, FM, L, V, EX, WD, B, N, ERR> SetArgumentsEnvironment for Env<A, FM, L, V, EX, WD, B, N, ERR>
484where
485 A: SetArgumentsEnvironment,
486 N: Hash + Eq,
487{
488 type Args = A::Args;
489
490 fn set_args(&mut self, new_args: Self::Args) -> Self::Args {
491 self.args_env.set_args(new_args)
492 }
493}
494
495impl<A, FM, L, V, EX, WD, B, N, ERR> ShiftArgumentsEnvironment
496 for Env<A, FM, L, V, EX, WD, B, N, ERR>
497where
498 A: ShiftArgumentsEnvironment,
499 N: Hash + Eq,
500{
501 fn shift_args(&mut self, amt: usize) {
502 self.args_env.shift_args(amt)
503 }
504}
505
506impl<A, FM, L, V, EX, WD, B, N, ERR> AsyncIoEnvironment for Env<A, FM, L, V, EX, WD, B, N, ERR>
507where
508 FM: AsyncIoEnvironment,
509 N: Hash + Eq,
510{
511 type IoHandle = FM::IoHandle;
512
513 fn read_all(&mut self, fd: Self::IoHandle) -> BoxFuture<'static, io::Result<Vec<u8>>> {
514 self.file_desc_manager_env.read_all(fd)
515 }
516
517 fn write_all<'a>(
518 &mut self,
519 fd: Self::IoHandle,
520 data: Cow<'a, [u8]>,
521 ) -> BoxFuture<'a, io::Result<()>> {
522 self.file_desc_manager_env.write_all(fd, data)
523 }
524
525 fn write_all_best_effort(&mut self, fd: Self::IoHandle, data: Vec<u8>) {
526 self.file_desc_manager_env.write_all_best_effort(fd, data);
527 }
528}
529
530impl<A, FM, L, V, EX, WD, B, N, ERR> FileDescEnvironment for Env<A, FM, L, V, EX, WD, B, N, ERR>
531where
532 FM: FileDescEnvironment,
533 N: Hash + Eq,
534{
535 type FileHandle = FM::FileHandle;
536
537 fn file_desc(&self, fd: Fd) -> Option<(&Self::FileHandle, Permissions)> {
538 self.file_desc_manager_env.file_desc(fd)
539 }
540
541 fn set_file_desc(&mut self, fd: Fd, fdes: Self::FileHandle, perms: Permissions) {
542 self.file_desc_manager_env.set_file_desc(fd, fdes, perms)
543 }
544
545 fn close_file_desc(&mut self, fd: Fd) {
546 self.file_desc_manager_env.close_file_desc(fd)
547 }
548}
549
550impl<A, FM, L, V, EX, WD, B, N, ERR> FileDescOpener for Env<A, FM, L, V, EX, WD, B, N, ERR>
551where
552 FM: FileDescOpener,
553 N: Hash + Eq,
554{
555 type OpenedFileHandle = FM::OpenedFileHandle;
556
557 fn open_path(&mut self, path: &Path, opts: &OpenOptions) -> io::Result<Self::OpenedFileHandle> {
558 self.file_desc_manager_env.open_path(path, opts)
559 }
560
561 fn open_pipe(&mut self) -> io::Result<Pipe<Self::OpenedFileHandle>> {
562 self.file_desc_manager_env.open_pipe()
563 }
564}
565
566impl<A, FM, L, V, EX, WD, B, N, ERR> ReportErrorEnvironment for Env<A, FM, L, V, EX, WD, B, N, ERR>
567where
568 A: ArgumentsEnvironment,
569 A::Arg: fmt::Display,
570 FM: AsyncIoEnvironment + FileDescEnvironment,
571 FM::FileHandle: Clone,
572 FM::IoHandle: From<FM::FileHandle>,
573 N: Hash + Eq,
574{
575 fn report_error<'a>(
576 &mut self,
577 fail: &'a (dyn Error + Sync + Send + 'static),
578 ) -> BoxFuture<'a, ()> {
579 let fd = match self.file_desc(STDERR_FILENO) {
580 Some((fdes, perms)) if perms.writable() => fdes.clone(),
581 _ => return Box::pin(async {}),
582 };
583
584 let data = format!("{}: {}\n", self.name(), fail).into_bytes();
585 let future = self.write_all(fd.into(), Cow::Owned(data));
586
587 Box::pin(async move {
588 let _ = future.await;
589 })
590 }
591}
592
593impl<A, FM, L, V, EX, WD, B, N, ERR> FunctionEnvironment for Env<A, FM, L, V, EX, WD, B, N, ERR>
594where
595 N: Hash + Eq + Clone,
596{
597 type FnName = N;
598 type Fn = Arc<dyn Spawn<Self, Error = ERR> + Send + Sync>;
599
600 fn function(&self, name: &Self::FnName) -> Option<&Self::Fn> {
601 self.fn_env.function(name)
602 }
603
604 fn set_function(&mut self, name: Self::FnName, func: Self::Fn) {
605 self.fn_env.set_function(name, func);
606 }
607
608 fn has_function(&self, name: &Self::FnName) -> bool {
609 self.fn_env.has_function(name)
610 }
611}
612
613impl<A, FM, L, V, EX, WD, B, N, ERR> UnsetFunctionEnvironment
614 for Env<A, FM, L, V, EX, WD, B, N, ERR>
615where
616 N: Hash + Eq + Clone,
617{
618 fn unset_function(&mut self, name: &Self::FnName) {
619 self.fn_env.unset_function(name);
620 }
621}
622
623impl<A, FM, L, V, EX, WD, B, N, ERR> FunctionFrameEnvironment
624 for Env<A, FM, L, V, EX, WD, B, N, ERR>
625where
626 N: Hash + Eq + Clone,
627{
628 fn push_fn_frame(&mut self) {
629 self.fn_frame_env.push_fn_frame()
630 }
631
632 fn pop_fn_frame(&mut self) {
633 self.fn_frame_env.pop_fn_frame()
634 }
635
636 fn is_fn_running(&self) -> bool {
637 self.fn_frame_env.is_fn_running()
638 }
639}
640
641impl<A, FM, L, V, EX, WD, B, N, ERR> LastStatusEnvironment for Env<A, FM, L, V, EX, WD, B, N, ERR>
642where
643 L: LastStatusEnvironment,
644 N: Hash + Eq,
645{
646 fn last_status(&self) -> ExitStatus {
647 self.last_status_env.last_status()
648 }
649
650 fn set_last_status(&mut self, status: ExitStatus) {
651 self.last_status_env.set_last_status(status);
652 }
653}
654
655impl<A, FM, L, V, EX, WD, B, N, ERR> VariableEnvironment for Env<A, FM, L, V, EX, WD, B, N, ERR>
656where
657 V: VariableEnvironment,
658 N: Hash + Eq,
659{
660 type VarName = V::VarName;
661 type Var = V::Var;
662
663 fn var<Q: ?Sized>(&self, name: &Q) -> Option<&Self::Var>
664 where
665 Self::VarName: Borrow<Q>,
666 Q: Hash + Eq,
667 {
668 self.var_env.var(name)
669 }
670
671 fn set_var(&mut self, name: Self::VarName, val: Self::Var) {
672 self.var_env.set_var(name, val);
673 }
674
675 fn env_vars(&self) -> Cow<'_, [(&Self::VarName, &Self::Var)]> {
676 self.var_env.env_vars()
677 }
678}
679
680impl<A, FM, L, V, EX, WD, B, N, ERR> ExportedVariableEnvironment
681 for Env<A, FM, L, V, EX, WD, B, N, ERR>
682where
683 V: ExportedVariableEnvironment,
684 N: Hash + Eq,
685{
686 fn exported_var(&self, name: &Self::VarName) -> Option<(&Self::Var, bool)> {
687 self.var_env.exported_var(name)
688 }
689
690 fn set_exported_var(&mut self, name: Self::VarName, val: Self::Var, exported: bool) {
691 self.var_env.set_exported_var(name, val, exported)
692 }
693}
694
695impl<A, FM, L, V, EX, WD, B, N, ERR> UnsetVariableEnvironment
696 for Env<A, FM, L, V, EX, WD, B, N, ERR>
697where
698 V: UnsetVariableEnvironment,
699 N: Hash + Eq,
700{
701 fn unset_var(&mut self, name: &V::VarName) {
702 self.var_env.unset_var(name)
703 }
704}
705
706impl<A, FM, L, V, EX, WD, B, N, ERR> ExecutableEnvironment for Env<A, FM, L, V, EX, WD, B, N, ERR>
707where
708 N: Hash + Eq,
709 EX: ExecutableEnvironment,
710{
711 fn spawn_executable(
712 &self,
713 data: ExecutableData<'_>,
714 ) -> Result<BoxFuture<'static, ExitStatus>, CommandError> {
715 self.exec_env.spawn_executable(data)
716 }
717}
718
719impl<A, FM, L, V, EX, WD, B, N, ERR> WorkingDirectoryEnvironment
720 for Env<A, FM, L, V, EX, WD, B, N, ERR>
721where
722 N: Hash + Eq,
723 WD: WorkingDirectoryEnvironment,
724{
725 fn path_relative_to_working_dir<'a>(&self, path: Cow<'a, Path>) -> Cow<'a, Path> {
726 self.working_dir_env.path_relative_to_working_dir(path)
727 }
728
729 fn current_working_dir(&self) -> &Path {
730 self.working_dir_env.current_working_dir()
731 }
732}
733
734impl<A, FM, L, V, EX, WD, B, N, ERR> ChangeWorkingDirectoryEnvironment
735 for Env<A, FM, L, V, EX, WD, B, N, ERR>
736where
737 N: Hash + Eq,
738 V: VariableEnvironment,
739 V::VarName: From<String>,
740 V::Var: From<String>,
741 WD: WorkingDirectoryEnvironment,
742 WD: ChangeWorkingDirectoryEnvironment,
743{
744 fn change_working_dir<'a>(&mut self, path: Cow<'a, Path>) -> io::Result<()> {
745 let old_cwd = self
746 .current_working_dir()
747 .to_string_lossy()
748 .into_owned()
749 .into();
750
751 self.working_dir_env.change_working_dir(path)?;
752
753 let new_cwd = self
754 .current_working_dir()
755 .to_string_lossy()
756 .into_owned()
757 .into();
758
759 self.set_var("PWD".to_owned().into(), new_cwd);
760 self.set_var("OLDPWD".to_owned().into(), old_cwd);
761
762 Ok(())
763 }
764}
765
766impl<A, FM, L, V, EX, WD, B, N, ERR> BuiltinEnvironment for Env<A, FM, L, V, EX, WD, B, N, ERR>
767where
768 N: Hash + Eq,
769 B: BuiltinEnvironment,
770{
771 type BuiltinName = B::BuiltinName;
772 type Builtin = B::Builtin;
773
774 fn builtin(&self, name: &Self::BuiltinName) -> Option<Self::Builtin> {
775 self.builtin_env.builtin(name)
776 }
777}
778
779pub type DefaultEnv<T> = Env<
783 ArgsEnv<T>,
784 TokioFileDescManagerEnv,
785 LastStatusEnv,
786 VarEnv<T, T>,
787 TokioExecEnv,
788 VirtualWorkingDirEnv,
789 BuiltinEnv<T>,
790 T,
791 RuntimeError,
792>;
793
794pub type DefaultEnvArc = DefaultEnv<Arc<String>>;
797
798impl<T> DefaultEnv<T>
799where
800 T: StringWrapper,
801{
802 pub fn new() -> io::Result<Self> {
806 DefaultEnvConfig::new().map(Self::with_config)
807 }
808}