1use crate::{
2 Config, ENV_VARIABLE_ID, IntoValue, NU_VARIABLE_ID, OutDest, ShellError, Span, Value, VarId,
3 engine::{
4 ArgumentStack, DEFAULT_OVERLAY_NAME, EngineState, EnvName, ErrorHandlerStack, Redirection,
5 StackCallArgGuard, StackCollectValueGuard, StackIoGuard, StackOutDest,
6 },
7 report_shell_warning,
8};
9use std::{
10 collections::{HashMap, HashSet},
11 fs::File,
12 path::{Component, MAIN_SEPARATOR},
13 sync::Arc,
14};
15
16pub type EnvVars = HashMap<String, HashMap<EnvName, Value>>;
18
19#[derive(Debug, Clone)]
37pub struct Stack {
38 pub vars: Vec<(VarId, Value)>,
40 pub env_vars: Vec<Arc<EnvVars>>,
42 pub env_hidden: Arc<HashMap<String, HashSet<EnvName>>>,
44 pub active_overlays: Vec<String>,
46 pub arguments: ArgumentStack,
48 pub error_handlers: ErrorHandlerStack,
50 pub finally_run_handlers: ErrorHandlerStack,
52 pub recursion_count: u64,
53 pub parent_stack: Option<Arc<Stack>>,
54 pub parent_deletions: Vec<VarId>,
56 pub deletions: Vec<VarId>,
58 pub config: Option<Arc<Config>>,
60 pub(crate) out_dest: StackOutDest,
61}
62
63impl Default for Stack {
64 fn default() -> Self {
65 Self::new()
66 }
67}
68
69impl Stack {
70 pub fn new() -> Self {
78 Self {
79 vars: Vec::new(),
80 env_vars: Vec::new(),
81 env_hidden: Arc::new(HashMap::new()),
82 active_overlays: vec![DEFAULT_OVERLAY_NAME.to_string()],
83 arguments: ArgumentStack::new(),
84 error_handlers: ErrorHandlerStack::new(),
85 finally_run_handlers: ErrorHandlerStack::new(),
86 recursion_count: 0,
87 parent_stack: None,
88 parent_deletions: vec![],
89 deletions: vec![],
90 config: None,
91 out_dest: StackOutDest::new(),
92 }
93 }
94
95 pub fn with_parent(parent: Arc<Stack>) -> Stack {
100 Stack {
101 env_vars: parent.env_vars.clone(),
103 env_hidden: parent.env_hidden.clone(),
104 active_overlays: parent.active_overlays.clone(),
105 arguments: ArgumentStack::new(),
106 error_handlers: ErrorHandlerStack::new(),
107 finally_run_handlers: ErrorHandlerStack::new(),
108 recursion_count: parent.recursion_count,
109 vars: vec![],
110 parent_deletions: vec![],
111 deletions: vec![],
112 config: parent.config.clone(),
113 out_dest: parent.out_dest.clone(),
114 parent_stack: Some(parent),
115 }
116 }
117
118 pub fn with_changes_from_child(parent: Arc<Stack>, child: Stack) -> Stack {
125 drop(child.parent_stack);
128 let mut unique_stack = Arc::unwrap_or_clone(parent);
129
130 unique_stack
131 .vars
132 .retain(|(var, _)| !child.parent_deletions.contains(var));
133 for (var, value) in child.vars {
134 unique_stack.add_var(var, value);
135 }
136 unique_stack.env_vars = child.env_vars;
137 unique_stack.env_hidden = child.env_hidden;
138 unique_stack.active_overlays = child.active_overlays;
139 unique_stack.config = child.config;
140 unique_stack
141 }
142
143 pub fn with_env(
144 &mut self,
145 env_vars: &[Arc<EnvVars>],
146 env_hidden: &Arc<HashMap<String, HashSet<EnvName>>>,
147 ) {
148 if self.env_vars.iter().any(|scope| !scope.is_empty()) {
150 env_vars.clone_into(&mut self.env_vars);
151 }
152
153 if !self.env_hidden.is_empty() {
154 self.env_hidden.clone_from(env_hidden);
155 }
156 }
157
158 fn lookup_var(&self, var_id: VarId) -> Option<Value> {
160 for (id, val) in &self.vars {
161 if var_id == *id {
162 return Some(val.clone());
163 }
164 }
165
166 if let Some(stack) = &self.parent_stack
167 && !self.parent_deletions.contains(&var_id)
168 {
169 return stack.lookup_var(var_id);
170 }
171 None
172 }
173
174 pub fn get_var(&self, var_id: VarId, span: Span) -> Result<Value, ShellError> {
178 match self.lookup_var(var_id) {
179 Some(v) => Ok(v.with_span(span)),
180 None => Err(ShellError::VariableNotFoundAtRuntime { span }),
181 }
182 }
183
184 pub fn get_var_with_origin(&self, var_id: VarId, span: Span) -> Result<Value, ShellError> {
189 match self.lookup_var(var_id) {
190 Some(v) => Ok(v),
191 None => {
192 if var_id == NU_VARIABLE_ID || var_id == ENV_VARIABLE_ID {
193 return Err(ShellError::GenericError {
194 error: "Built-in variables `$env` and `$nu` have no metadata".into(),
195 msg: "no metadata available".into(),
196 span: Some(span),
197 help: None,
198 inner: vec![],
199 });
200 }
201 Err(ShellError::VariableNotFoundAtRuntime { span })
202 }
203 }
204 }
205
206 pub fn get_config(&self, engine_state: &EngineState) -> Arc<Config> {
210 self.config
211 .clone()
212 .unwrap_or_else(|| engine_state.config.clone())
213 }
214
215 pub fn update_config(&mut self, engine_state: &EngineState) -> Result<(), ShellError> {
220 if let Some(value) = self.get_env_var(engine_state, "config") {
221 let old = self.get_config(engine_state);
222 let mut config = (*old).clone();
223 let result = config.update_from_value(&old, value);
224 self.add_env_var("config".into(), config.clone().into_value(value.span()));
226 self.config = Some(config.into());
227 if let Some(warning) = result? {
228 report_shell_warning(Some(self), engine_state, &warning);
229 }
230 } else {
231 self.config = None;
232 }
233 Ok(())
234 }
235
236 pub fn add_var(&mut self, var_id: VarId, value: Value) {
237 for (id, val) in &mut self.vars {
239 if *id == var_id {
240 *val = value;
241 return;
242 }
243 }
244 self.vars.push((var_id, value));
245 }
246
247 pub fn remove_var(&mut self, var_id: VarId) {
248 for (idx, (id, _)) in self.vars.iter().enumerate() {
249 if *id == var_id {
250 self.vars.remove(idx);
251 break;
252 }
253 }
254 if self.parent_stack.is_some() {
257 self.parent_deletions.push(var_id);
258 }
259 self.deletions.push(var_id);
260 }
261
262 pub fn add_env_var(&mut self, var: String, value: Value) {
263 if let Some(last_overlay) = self.active_overlays.last() {
264 let env_name = EnvName::from(var);
265 if let Some(env_hidden) = Arc::make_mut(&mut self.env_hidden).get_mut(last_overlay) {
266 env_hidden.remove(&env_name);
268 }
269
270 if let Some(scope) = self.env_vars.last_mut() {
271 let scope = Arc::make_mut(scope);
272 if let Some(env_vars) = scope.get_mut(last_overlay) {
273 env_vars.insert(env_name, value);
274 } else {
275 scope.insert(
276 last_overlay.into(),
277 [(env_name, value)].into_iter().collect(),
278 );
279 }
280 } else {
281 self.env_vars.push(Arc::new(
282 [(
283 last_overlay.into(),
284 [(env_name, value)].into_iter().collect(),
285 )]
286 .into_iter()
287 .collect(),
288 ));
289 }
290 } else {
291 panic!("internal error: no active overlay");
293 }
294 }
295
296 pub fn set_last_exit_code(&mut self, code: i32, span: Span) {
297 self.add_env_var("LAST_EXIT_CODE".into(), Value::int(code.into(), span));
298 }
299
300 pub fn set_last_error(&mut self, error: &ShellError) {
301 if let Some(code) = error.external_exit_code() {
302 self.set_last_exit_code(code.item, code.span);
303 } else if let Some(code) = error.exit_code() {
304 self.set_last_exit_code(code, Span::unknown());
305 }
306 }
307
308 pub fn last_overlay_name(&self) -> Result<String, ShellError> {
309 self.active_overlays
310 .last()
311 .cloned()
312 .ok_or_else(|| ShellError::NushellFailed {
313 msg: "No active overlay".into(),
314 })
315 }
316
317 pub fn captures_to_stack(&self, captures: Vec<(VarId, Value)>) -> Stack {
318 self.captures_to_stack_preserve_out_dest(captures)
319 .collect_value()
320 }
321
322 pub fn captures_to_stack_preserve_out_dest(&self, captures: Vec<(VarId, Value)>) -> Stack {
323 let mut env_vars = self.env_vars.clone();
324 env_vars.push(Arc::new(HashMap::new()));
325
326 Stack {
327 vars: captures,
328 env_vars,
329 env_hidden: self.env_hidden.clone(),
330 active_overlays: self.active_overlays.clone(),
331 arguments: ArgumentStack::new(),
332 error_handlers: ErrorHandlerStack::new(),
333 finally_run_handlers: ErrorHandlerStack::new(),
334 recursion_count: self.recursion_count,
335 parent_stack: None,
336 parent_deletions: vec![],
337 deletions: vec![],
338 config: self.config.clone(),
339 out_dest: self.out_dest.clone(),
340 }
341 }
342
343 pub fn gather_captures(&self, engine_state: &EngineState, captures: &[(VarId, Span)]) -> Stack {
344 let mut vars = Vec::with_capacity(captures.len());
345
346 let fake_span = Span::new(0, 0);
347
348 for (capture, _) in captures {
349 if let Ok(value) = self.get_var(*capture, fake_span) {
352 vars.push((*capture, value));
353 } else if let Some(const_val) = &engine_state.get_var(*capture).const_val {
354 vars.push((*capture, const_val.clone()));
355 }
356 }
357
358 let mut env_vars = self.env_vars.clone();
359 env_vars.push(Arc::new(HashMap::new()));
360
361 Stack {
362 vars,
363 env_vars,
364 env_hidden: self.env_hidden.clone(),
365 active_overlays: self.active_overlays.clone(),
366 arguments: ArgumentStack::new(),
367 error_handlers: ErrorHandlerStack::new(),
368 finally_run_handlers: ErrorHandlerStack::new(),
369 recursion_count: self.recursion_count,
370 parent_stack: None,
371 parent_deletions: vec![],
372 deletions: vec![],
373 config: self.config.clone(),
374 out_dest: self.out_dest.clone(),
375 }
376 }
377
378 pub fn get_env_vars(&self, engine_state: &EngineState) -> HashMap<String, Value> {
380 let mut result = HashMap::new();
381
382 for active_overlay in self.active_overlays.iter() {
383 if let Some(env_vars) = engine_state.env_vars.get(active_overlay) {
384 result.extend(
385 env_vars
386 .iter()
387 .filter(|(k, _)| {
388 if let Some(env_hidden) = self.env_hidden.get(active_overlay) {
389 !env_hidden.contains(*k)
390 } else {
391 true
393 }
394 })
395 .map(|(k, v)| (k.as_str().to_string(), v.clone()))
396 .collect::<HashMap<String, Value>>(),
397 );
398 }
399 }
400
401 result.extend(self.get_stack_env_vars());
402
403 result
404 }
405
406 pub fn get_stack_env_vars(&self) -> HashMap<String, Value> {
408 let mut result = HashMap::new();
409
410 for scope in &self.env_vars {
411 for active_overlay in self.active_overlays.iter() {
412 if let Some(env_vars) = scope.get(active_overlay) {
413 result.extend(
414 env_vars
415 .iter()
416 .map(|(k, v)| (k.as_str().to_string(), v.clone())),
417 );
418 }
419 }
420 }
421
422 result
423 }
424
425 pub fn get_stack_overlay_env_vars(&self, overlay_name: &str) -> HashMap<String, Value> {
427 let mut result = HashMap::new();
428
429 for scope in &self.env_vars {
430 if let Some(active_overlay) = self.active_overlays.iter().find(|n| n == &overlay_name)
431 && let Some(env_vars) = scope.get(active_overlay)
432 {
433 result.extend(
434 env_vars
435 .iter()
436 .map(|(k, v)| (k.as_str().to_string(), v.clone())),
437 );
438 }
439 }
440
441 result
442 }
443
444 pub fn get_hidden_env_vars(
446 &self,
447 excluded_overlay_name: &str,
448 engine_state: &EngineState,
449 ) -> HashMap<String, Value> {
450 let mut result = HashMap::new();
451
452 for overlay_name in self.active_overlays.iter().rev() {
453 if overlay_name == excluded_overlay_name {
454 continue;
455 }
456 if let Some(env_names) = self.env_hidden.get(overlay_name) {
457 for n in env_names {
458 if result.contains_key(n.as_str()) {
459 continue;
460 }
461 if let Some(Some(v)) = engine_state
463 .env_vars
464 .get(overlay_name)
465 .map(|env_vars| env_vars.get(n))
466 {
467 result.insert(n.as_str().to_string(), v.clone());
468 }
469 }
470 }
471 }
472 result
473 }
474
475 pub fn get_env_var_names(&self, engine_state: &EngineState) -> HashSet<String> {
477 let mut result = HashSet::new();
478
479 for active_overlay in self.active_overlays.iter() {
480 if let Some(env_vars) = engine_state.env_vars.get(active_overlay) {
481 result.extend(
482 env_vars
483 .keys()
484 .filter(|k| {
485 if let Some(env_hidden) = self.env_hidden.get(active_overlay) {
486 !env_hidden.contains(*k)
487 } else {
488 true
490 }
491 })
492 .map(|k| k.as_str().to_string())
493 .collect::<HashSet<String>>(),
494 );
495 }
496 }
497
498 for scope in &self.env_vars {
499 for active_overlay in self.active_overlays.iter() {
500 if let Some(env_vars) = scope.get(active_overlay) {
501 result.extend(
502 env_vars
503 .keys()
504 .map(|k| k.as_str().to_string())
505 .collect::<HashSet<String>>(),
506 );
507 }
508 }
509 }
510
511 result
512 }
513
514 pub fn get_env_var<'a>(
515 &'a self,
516 engine_state: &'a EngineState,
517 name: &str,
518 ) -> Option<&'a Value> {
519 for scope in self.env_vars.iter().rev() {
520 for active_overlay in self.active_overlays.iter().rev() {
521 if let Some(env_vars) = scope.get(active_overlay)
522 && let Some(v) = env_vars.get(&EnvName::from(name))
523 {
524 return Some(v);
525 }
526 }
527 }
528
529 for active_overlay in self.active_overlays.iter().rev() {
530 let is_hidden = if let Some(env_hidden) = self.env_hidden.get(active_overlay) {
531 env_hidden.contains(&EnvName::from(name))
532 } else {
533 false
534 };
535
536 if !is_hidden
537 && let Some(env_vars) = engine_state.env_vars.get(active_overlay)
538 && let Some(v) = env_vars.get(&EnvName::from(name))
539 {
540 return Some(v);
541 }
542 }
543 None
544 }
545
546 pub fn has_env_var(&self, engine_state: &EngineState, name: &str) -> bool {
547 for scope in self.env_vars.iter().rev() {
548 for active_overlay in self.active_overlays.iter().rev() {
549 if let Some(env_vars) = scope.get(active_overlay)
550 && env_vars.contains_key(&EnvName::from(name))
551 {
552 return true;
553 }
554 }
555 }
556
557 for active_overlay in self.active_overlays.iter().rev() {
558 let is_hidden = if let Some(env_hidden) = self.env_hidden.get(active_overlay) {
559 env_hidden.contains(&EnvName::from(name))
560 } else {
561 false
562 };
563
564 if !is_hidden
565 && let Some(env_vars) = engine_state.env_vars.get(active_overlay)
566 && env_vars.contains_key(&EnvName::from(name))
567 {
568 return true;
569 }
570 }
571
572 false
573 }
574
575 pub fn remove_env_var(&mut self, engine_state: &EngineState, name: &str) -> bool {
576 for scope in self.env_vars.iter_mut().rev() {
577 let scope = Arc::make_mut(scope);
578 for active_overlay in self.active_overlays.iter().rev() {
579 if let Some(env_vars) = scope.get_mut(active_overlay)
580 && env_vars.remove(&EnvName::from(name)).is_some()
581 {
582 return true;
583 }
584 }
585 }
586
587 for active_overlay in self.active_overlays.iter().rev() {
588 if let Some(env_vars) = engine_state.env_vars.get(active_overlay)
589 && env_vars.get(&EnvName::from(name)).is_some()
590 {
591 let env_hidden = Arc::make_mut(&mut self.env_hidden);
592 if let Some(env_hidden_in_overlay) = env_hidden.get_mut(active_overlay) {
593 env_hidden_in_overlay.insert(EnvName::from(name));
594 } else {
595 env_hidden.insert(
596 active_overlay.into(),
597 [EnvName::from(name)].into_iter().collect(),
598 );
599 }
600
601 return true;
602 }
603 }
604
605 false
606 }
607
608 pub fn has_env_overlay(&self, name: &str, engine_state: &EngineState) -> bool {
609 for scope in self.env_vars.iter().rev() {
610 if scope.contains_key(name) {
611 return true;
612 }
613 }
614
615 engine_state.env_vars.contains_key(name)
616 }
617
618 pub fn is_overlay_active(&self, name: &str) -> bool {
619 self.active_overlays.iter().any(|n| n == name)
620 }
621
622 pub fn add_overlay(&mut self, name: String) {
623 self.active_overlays.retain(|o| o != &name);
624 self.active_overlays.push(name);
625 }
626
627 pub fn remove_overlay(&mut self, name: &str) {
628 self.active_overlays.retain(|o| o != name);
629 }
630
631 pub fn stdout(&self) -> &OutDest {
637 self.out_dest.stdout()
638 }
639
640 pub fn stderr(&self) -> &OutDest {
646 self.out_dest.stderr()
647 }
648
649 pub fn pipe_stdout(&self) -> Option<&OutDest> {
651 self.out_dest.pipe_stdout.as_ref()
652 }
653
654 pub fn pipe_stderr(&self) -> Option<&OutDest> {
656 self.out_dest.pipe_stderr.as_ref()
657 }
658
659 pub fn start_collect_value(&mut self) -> StackCollectValueGuard<'_> {
663 StackCollectValueGuard::new(self)
664 }
665
666 pub fn use_call_arg_out_dest(&mut self) -> StackCallArgGuard<'_> {
670 StackCallArgGuard::new(self)
671 }
672
673 pub fn push_redirection(
675 &mut self,
676 stdout: Option<Redirection>,
677 stderr: Option<Redirection>,
678 ) -> StackIoGuard<'_> {
679 StackIoGuard::new(self, stdout, stderr)
680 }
681
682 pub fn collect_value(mut self) -> Self {
689 self.out_dest.pipe_stdout = Some(OutDest::Value);
690 self.out_dest.pipe_stderr = None;
691 self
692 }
693
694 pub fn capture_all(mut self) -> Self {
703 self.out_dest.pipe_stdout = Some(OutDest::Value);
704 self.out_dest.pipe_stderr = Some(OutDest::Value);
705 self
706 }
707
708 pub fn reset_out_dest(mut self) -> Self {
713 self.out_dest = StackOutDest::new();
714 self
715 }
716
717 pub fn reset_pipes(mut self) -> Self {
722 self.out_dest.pipe_stdout = None;
723 self.out_dest.pipe_stderr = None;
724 self
725 }
726
727 pub fn stdout_file(mut self, file: File) -> Self {
766 self.out_dest.stdout = OutDest::File(Arc::new(file));
767 self
768 }
769
770 pub fn stderr_file(mut self, file: File) -> Self {
774 self.out_dest.stderr = OutDest::File(Arc::new(file));
775 self
776 }
777
778 pub fn set_cwd(&mut self, path: impl AsRef<std::path::Path>) -> Result<(), ShellError> {
783 fn error(msg: &str) -> Result<(), ShellError> {
786 Err(ShellError::GenericError {
787 error: msg.into(),
788 msg: "".into(),
789 span: None,
790 help: None,
791 inner: vec![],
792 })
793 }
794
795 let path = path.as_ref();
796
797 if !path.is_absolute() {
798 if let Some(Component::Prefix(_)) = path.components().next() {
799 return Err(ShellError::GenericError {
800 error: "Cannot set $env.PWD to a prefix-only path".to_string(),
801 msg: "".into(),
802 span: None,
803 help: Some(format!(
804 "Try to use {}{MAIN_SEPARATOR} instead",
805 path.display()
806 )),
807 inner: vec![],
808 });
809 }
810
811 error("Cannot set $env.PWD to a non-absolute path")
812 } else if !path.exists() {
813 error("Cannot set $env.PWD to a non-existent directory")
814 } else if !path.is_dir() {
815 error("Cannot set $env.PWD to a non-directory")
816 } else {
817 let path = nu_path::strip_trailing_slash(path);
819 let value = Value::string(path.to_string_lossy(), Span::unknown());
820 self.add_env_var("PWD".into(), value);
821 Ok(())
822 }
823 }
824}
825
826#[cfg(test)]
827mod test {
828 use std::sync::Arc;
829
830 use crate::{Span, Value, VarId, engine::EngineState};
831
832 use super::Stack;
833
834 #[test]
835 fn test_children_see_inner_values() {
836 let mut original = Stack::new();
837 original.add_var(VarId::new(0), Value::test_string("hello"));
838
839 let cloned = Stack::with_parent(Arc::new(original));
840 assert_eq!(
841 cloned.get_var(VarId::new(0), Span::test_data()),
842 Ok(Value::test_string("hello"))
843 );
844 }
845
846 #[test]
847 fn test_children_dont_see_deleted_values() {
848 let mut original = Stack::new();
849 original.add_var(VarId::new(0), Value::test_string("hello"));
850
851 let mut cloned = Stack::with_parent(Arc::new(original));
852 cloned.remove_var(VarId::new(0));
853
854 assert_eq!(
855 cloned.get_var(VarId::new(0), Span::test_data()),
856 Err(crate::ShellError::VariableNotFoundAtRuntime {
857 span: Span::test_data()
858 })
859 );
860 }
861
862 #[test]
863 fn test_children_changes_override_parent() {
864 let mut original = Stack::new();
865 original.add_var(VarId::new(0), Value::test_string("hello"));
866
867 let mut cloned = Stack::with_parent(Arc::new(original));
868 cloned.add_var(VarId::new(0), Value::test_string("there"));
869 assert_eq!(
870 cloned.get_var(VarId::new(0), Span::test_data()),
871 Ok(Value::test_string("there"))
872 );
873
874 cloned.remove_var(VarId::new(0));
875 assert_eq!(
877 cloned.get_var(VarId::new(0), Span::test_data()),
878 Err(crate::ShellError::VariableNotFoundAtRuntime {
879 span: Span::test_data()
880 })
881 );
882 }
883 #[test]
884 fn test_children_changes_persist_in_offspring() {
885 let mut original = Stack::new();
886 original.add_var(VarId::new(0), Value::test_string("hello"));
887
888 let mut cloned = Stack::with_parent(Arc::new(original));
889 cloned.add_var(VarId::new(1), Value::test_string("there"));
890
891 cloned.remove_var(VarId::new(0));
892 let cloned = Stack::with_parent(Arc::new(cloned));
893
894 assert_eq!(
895 cloned.get_var(VarId::new(0), Span::test_data()),
896 Err(crate::ShellError::VariableNotFoundAtRuntime {
897 span: Span::test_data()
898 })
899 );
900
901 assert_eq!(
902 cloned.get_var(VarId::new(1), Span::test_data()),
903 Ok(Value::test_string("there"))
904 );
905 }
906
907 #[test]
908 fn test_merging_children_back_to_parent() {
909 let mut original = Stack::new();
910 let engine_state = EngineState::new();
911 original.add_var(VarId::new(0), Value::test_string("hello"));
912
913 let original_arc = Arc::new(original);
914 let mut cloned = Stack::with_parent(original_arc.clone());
915 cloned.add_var(VarId::new(1), Value::test_string("there"));
916
917 cloned.remove_var(VarId::new(0));
918
919 cloned.add_env_var(
920 "ADDED_IN_CHILD".to_string(),
921 Value::test_string("New Env Var"),
922 );
923
924 let original = Stack::with_changes_from_child(original_arc, cloned);
925
926 assert_eq!(
927 original.get_var(VarId::new(0), Span::test_data()),
928 Err(crate::ShellError::VariableNotFoundAtRuntime {
929 span: Span::test_data()
930 })
931 );
932
933 assert_eq!(
934 original.get_var(VarId::new(1), Span::test_data()),
935 Ok(Value::test_string("there"))
936 );
937
938 assert_eq!(
939 original
940 .get_env_var(&engine_state, "ADDED_IN_CHILD")
941 .cloned(),
942 Some(Value::test_string("New Env Var")),
943 );
944 }
945}