nu_command/env/
source_env.rs1use nu_engine::{
2 command_prelude::*, find_in_dirs_env, get_dirs_var_from_call, get_eval_block_with_early_return,
3 redirect_env,
4};
5use nu_protocol::{engine::CommandType, shell_error::io::IoError, BlockId};
6use std::path::PathBuf;
7
8#[derive(Clone)]
10pub struct SourceEnv;
11
12impl Command for SourceEnv {
13 fn name(&self) -> &str {
14 "source-env"
15 }
16
17 fn signature(&self) -> Signature {
18 Signature::build("source-env")
19 .input_output_types(vec![(Type::Any, Type::Any)])
20 .required(
21 "filename",
22 SyntaxShape::OneOf(vec![SyntaxShape::String, SyntaxShape::Nothing]), "The filepath to the script file to source the environment from (`null` for no-op).",
24 )
25 .category(Category::Core)
26 }
27
28 fn description(&self) -> &str {
29 "Source the environment from a source file into the current environment."
30 }
31
32 fn extra_description(&self) -> &str {
33 r#"This command is a parser keyword. For details, check:
34 https://www.nushell.sh/book/thinking_in_nu.html"#
35 }
36
37 fn command_type(&self) -> CommandType {
38 CommandType::Keyword
39 }
40
41 fn run(
42 &self,
43 engine_state: &EngineState,
44 caller_stack: &mut Stack,
45 call: &Call,
46 input: PipelineData,
47 ) -> Result<PipelineData, ShellError> {
48 if call.get_parser_info(caller_stack, "noop").is_some() {
49 return Ok(PipelineData::empty());
50 }
51
52 let source_filename: Spanned<String> = call.req(engine_state, caller_stack, 0)?;
53
54 let block_id: i64 = call.req_parser_info(engine_state, caller_stack, "block_id")?;
57 let block_id = BlockId::new(block_id as usize);
58
59 let file_path = if let Some(path) = find_in_dirs_env(
61 &source_filename.item,
62 engine_state,
63 caller_stack,
64 get_dirs_var_from_call(caller_stack, call),
65 )? {
66 PathBuf::from(&path)
67 } else {
68 return Err(ShellError::Io(IoError::new(
69 std::io::ErrorKind::NotFound,
70 source_filename.span,
71 PathBuf::from(source_filename.item),
72 )));
73 };
74
75 if let Some(parent) = file_path.parent() {
76 let file_pwd = Value::string(parent.to_string_lossy(), call.head);
77
78 caller_stack.add_env_var("FILE_PWD".to_string(), file_pwd);
79 }
80
81 caller_stack.add_env_var(
82 "CURRENT_FILE".to_string(),
83 Value::string(file_path.to_string_lossy(), call.head),
84 );
85
86 let block = engine_state.get_block(block_id).clone();
88 let mut callee_stack = caller_stack
89 .gather_captures(engine_state, &block.captures)
90 .reset_pipes();
91
92 let eval_block_with_early_return = get_eval_block_with_early_return(engine_state);
93
94 let result = eval_block_with_early_return(engine_state, &mut callee_stack, &block, input);
95
96 redirect_env(engine_state, caller_stack, &callee_stack);
98
99 caller_stack.remove_env_var(engine_state, "FILE_PWD");
101 caller_stack.remove_env_var(engine_state, "CURRENT_FILE");
102
103 result
104 }
105
106 fn examples(&self) -> Vec<Example> {
107 vec![
108 Example {
109 description: "Sources the environment from foo.nu in the current context",
110 example: r#"source-env foo.nu"#,
111 result: None,
112 },
113 Example {
114 description: "Sourcing `null` is a no-op.",
115 example: r#"source-env null"#,
116 result: None,
117 },
118 ]
119 }
120}