nu_command/env/
with_env.rs

1use nu_engine::{command_prelude::*, eval_block};
2use nu_protocol::{debugger::WithoutDebug, engine::Closure};
3
4#[derive(Clone)]
5pub struct WithEnv;
6
7impl Command for WithEnv {
8    fn name(&self) -> &str {
9        "with-env"
10    }
11
12    fn signature(&self) -> Signature {
13        Signature::build("with-env")
14            .input_output_types(vec![(Type::Any, Type::Any)])
15            .required(
16                "variable",
17                SyntaxShape::Any,
18                "The environment variable to temporarily set.",
19            )
20            .required(
21                "block",
22                SyntaxShape::Closure(None),
23                "The block to run once the variable is set.",
24            )
25            .category(Category::Env)
26    }
27
28    fn description(&self) -> &str {
29        "Runs a block with an environment variable set."
30    }
31
32    fn run(
33        &self,
34        engine_state: &EngineState,
35        stack: &mut Stack,
36        call: &Call,
37        input: PipelineData,
38    ) -> Result<PipelineData, ShellError> {
39        with_env(engine_state, stack, call, input)
40    }
41
42    fn examples(&self) -> Vec<Example> {
43        vec![Example {
44            description: "Set by key-value record",
45            example: r#"with-env {X: "Y", W: "Z"} { [$env.X $env.W] }"#,
46            result: Some(Value::list(
47                vec![Value::test_string("Y"), Value::test_string("Z")],
48                Span::test_data(),
49            )),
50        }]
51    }
52}
53
54fn with_env(
55    engine_state: &EngineState,
56    stack: &mut Stack,
57    call: &Call,
58    input: PipelineData,
59) -> Result<PipelineData, ShellError> {
60    let env: Record = call.req(engine_state, stack, 0)?;
61    let capture_block: Closure = call.req(engine_state, stack, 1)?;
62    let block = engine_state.get_block(capture_block.block_id);
63    let mut stack = stack.captures_to_stack_preserve_out_dest(capture_block.captures);
64
65    // TODO: factor list of prohibited env vars into common place
66    for prohibited in ["PWD", "FILE_PWD", "CURRENT_FILE"] {
67        if env.contains(prohibited) {
68            return Err(ShellError::AutomaticEnvVarSetManually {
69                envvar_name: prohibited.into(),
70                span: call.head,
71            });
72        }
73    }
74
75    for (k, v) in env {
76        stack.add_env_var(k, v);
77    }
78
79    eval_block::<WithoutDebug>(engine_state, &mut stack, block, input)
80}
81
82#[cfg(test)]
83mod test {
84    use super::*;
85
86    #[test]
87    fn test_examples() {
88        use crate::test_examples;
89
90        test_examples(WithEnv {})
91    }
92}