diff options
author | Jakub Žádník <kubouch@gmail.com> | 2022-09-08 23:41:49 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-08 23:41:49 +0300 |
commit | e76b3d61deef832adce76b0f73f19131de8cbc9e (patch) | |
tree | 19de8a3bceeaae39f9e72783c30840d472e30ca6 | |
parent | 1adebefc3ea5dd996a3ae53e398b5cc9e6f6a602 (diff) |
Require static path for `source-env` (#6526)0.68.1
-rw-r--r-- | crates/nu-command/src/env/source_env.rs | 134 | ||||
-rw-r--r-- | crates/nu-command/tests/commands/source_env.rs | 32 | ||||
-rw-r--r-- | crates/nu-parser/src/parse_keywords.rs | 10 | ||||
-rw-r--r-- | crates/nu-parser/src/parser.rs | 4 |
4 files changed, 61 insertions, 119 deletions
diff --git a/crates/nu-command/src/env/source_env.rs b/crates/nu-command/src/env/source_env.rs index 642c1ff45..6de2e07bd 100644 --- a/crates/nu-command/src/env/source_env.rs +++ b/crates/nu-command/src/env/source_env.rs @@ -1,11 +1,10 @@ use std::path::PathBuf; use nu_engine::{eval_block, find_in_dirs_env, redirect_env, CallExt}; -use nu_parser::parse; use nu_protocol::ast::Call; -use nu_protocol::engine::{Command, EngineState, Stack, StateWorkingSet}; +use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::{ - Category, CliError, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Value, + Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Value, }; /// Source a file for environment variables. @@ -40,96 +39,47 @@ impl Command for SourceEnv { ) -> Result<PipelineData, ShellError> { let source_filename: Spanned<String> = call.req(engine_state, caller_stack, 0)?; - if let Some(path) = find_in_dirs_env(&source_filename.item, engine_state, caller_stack)? { - if let Ok(content) = std::fs::read_to_string(&path) { - let mut parent = PathBuf::from(&path); - parent.pop(); - - let mut new_engine_state = engine_state.clone(); - - let (block, delta) = { - let mut working_set = StateWorkingSet::new(&new_engine_state); - - // Set the currently parsed directory - working_set.currently_parsed_cwd = Some(parent.clone()); - - let (block, err) = parse(&mut working_set, None, content.as_bytes(), true, &[]); - - if let Some(err) = err { - // Because the error span points at new_engine_state, we must create the error message now - let msg = format!( - r#"Found this parser error: {:?}"#, - CliError(&err, &working_set) - ); - - return Err(ShellError::GenericError( - "Failed to parse content".to_string(), - "cannot parse this file".to_string(), - Some(source_filename.span), - Some(msg), - vec![], - )); - } else { - (block, working_set.render()) - } - }; - - // Merge parser changes to a temporary engine state - new_engine_state.merge_delta(delta)?; - - // Set the currently evaluated directory - let file_pwd = Value::String { - val: parent.to_string_lossy().to_string(), - span: call.head, - }; - - caller_stack.add_env_var("FILE_PWD".to_string(), file_pwd); - - // Evaluate the parsed file's block - let mut callee_stack = caller_stack.gather_captures(&block.captures); - - let result = eval_block( - &new_engine_state, - &mut callee_stack, - &block, - input, - true, - true, - ); - - let result = if let Err(err) = result { - // Because the error span points at new_engine_state, we must create the error message now - let working_set = StateWorkingSet::new(&new_engine_state); - - let msg = format!( - r#"Found this shell error: {:?}"#, - CliError(&err, &working_set) - ); - - Err(ShellError::GenericError( - "Failed to evaluate content".to_string(), - "cannot evaluate this file".to_string(), - Some(source_filename.span), - Some(msg), - vec![], - )) - } else { - result - }; - - // Merge the block's environment to the current stack - redirect_env(engine_state, caller_stack, &callee_stack); - - // Remove the file-relative PWD - caller_stack.remove_env_var(engine_state, "FILE_PWD"); - - result - } else { - Err(ShellError::FileNotFound(source_filename.span)) - } + // Note: this hidden positional is the block_id that corresponded to the 0th position + // it is put here by the parser + let block_id: i64 = call.req(engine_state, caller_stack, 1)?; + + // Set the currently evaluated directory (file-relative PWD) + let mut parent = if let Some(path) = + find_in_dirs_env(&source_filename.item, engine_state, caller_stack)? + { + PathBuf::from(&path) } else { - Err(ShellError::FileNotFound(source_filename.span)) - } + return Err(ShellError::FileNotFound(source_filename.span)); + }; + parent.pop(); + + let file_pwd = Value::String { + val: parent.to_string_lossy().to_string(), + span: call.head, + }; + + caller_stack.add_env_var("FILE_PWD".to_string(), file_pwd); + + // Evaluate the block + let block = engine_state.get_block(block_id as usize).clone(); + let mut callee_stack = caller_stack.gather_captures(&block.captures); + + let result = eval_block( + engine_state, + &mut callee_stack, + &block, + input, + call.redirect_stdout, + call.redirect_stderr, + ); + + // Merge the block's environment to the current stack + redirect_env(engine_state, caller_stack, &callee_stack); + + // Remove the file-relative PWD + caller_stack.remove_env_var(engine_state, "FILE_PWD"); + + result } fn examples(&self) -> Vec<Example> { diff --git a/crates/nu-command/tests/commands/source_env.rs b/crates/nu-command/tests/commands/source_env.rs index c4ab9fcee..b7f3e93ac 100644 --- a/crates/nu-command/tests/commands/source_env.rs +++ b/crates/nu-command/tests/commands/source_env.rs @@ -143,6 +143,7 @@ fn sources_unicode_file_in_non_utf8_dir() { // How do I create non-UTF-8 path??? } +#[ignore] #[test] fn can_source_dynamic_path() { Playground::setup("can_source_dynamic_path", |dirs, sandbox| { @@ -269,39 +270,26 @@ fn source_env_dont_cd_overlay() { } #[test] -fn source_env_nice_parse_error() { - Playground::setup("source_env_nice_parse_error", |dirs, sandbox| { +fn source_env_is_scoped() { + Playground::setup("source_env_is_scoped", |dirs, sandbox| { sandbox.with_files(vec![FileWithContentToBeTrimmed( "spam.nu", r#" - let x - "#, + def foo [] { 'foo' } + alias bar = 'bar' + "#, )]); - let inp = &[r#"source-env spam.nu"#]; + let inp = &[r#"source-env spam.nu"#, r#"foo"#]; let actual = nu!(cwd: dirs.test(), pipeline(&inp.join("; "))); - assert!(actual.err.contains("cannot parse this file")); - assert!(actual.err.contains("───")); - }) -} - -#[test] -fn source_env_nice_shell_error() { - Playground::setup("source_env_nice_shell_error", |dirs, sandbox| { - sandbox.with_files(vec![FileWithContentToBeTrimmed( - "spam.nu", - r#" - let-env FILE_PWD = 'foo' - "#, - )]); + assert!(actual.err.contains("did you mean")); - let inp = &[r#"source-env spam.nu"#]; + let inp = &[r#"source-env spam.nu"#, r#"bar"#]; let actual = nu!(cwd: dirs.test(), pipeline(&inp.join("; "))); - assert!(actual.err.contains("cannot evaluate this file")); - assert!(actual.err.contains("───")); + assert!(actual.err.contains("did you mean")); }) } diff --git a/crates/nu-parser/src/parse_keywords.rs b/crates/nu-parser/src/parse_keywords.rs index 172a0c3e5..ebb137130 100644 --- a/crates/nu-parser/src/parse_keywords.rs +++ b/crates/nu-parser/src/parse_keywords.rs @@ -2902,8 +2902,10 @@ pub fn parse_source( let mut error = None; let name = working_set.get_span_contents(spans[0]); - if name == b"source" { - if let Some(decl_id) = working_set.find_decl(b"source", &Type::Any) { + if name == b"source" || name == b"source-env" { + let scoped = name == b"source-env"; + + if let Some(decl_id) = working_set.find_decl(name, &Type::Any) { let cwd = working_set.get_cwd(); // Is this the right call to be using here? @@ -2958,7 +2960,7 @@ pub fn parse_source( working_set, path.file_name().and_then(|x| x.to_str()), &contents, - false, + scoped, expand_aliases_denylist, ); @@ -2983,7 +2985,7 @@ pub fn parse_source( let mut call_with_block = call; - // Adding this expression to the positional creates a syntax highlighting error + // FIXME: Adding this expression to the positional creates a syntax highlighting error // after writing `source example.nu` call_with_block.add_positional(Expression { expr: Expr::Int(block_id as i64), diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index f92cb69e6..33e5f6e7a 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -4815,7 +4815,9 @@ pub fn parse_builtin_commands( (pipeline, err) } b"overlay" => parse_overlay(working_set, &lite_command.parts, expand_aliases_denylist), - b"source" => parse_source(working_set, &lite_command.parts, expand_aliases_denylist), + b"source" | b"source-env" => { + parse_source(working_set, &lite_command.parts, expand_aliases_denylist) + } b"export" => parse_export_in_block(working_set, lite_command, expand_aliases_denylist), b"hide" => parse_hide(working_set, &lite_command.parts, expand_aliases_denylist), #[cfg(feature = "plugin")] |