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