summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Žádník <kubouch@gmail.com>2022-09-08 23:41:49 +0300
committerGitHub <noreply@github.com>2022-09-08 23:41:49 +0300
commite76b3d61deef832adce76b0f73f19131de8cbc9e (patch)
tree19de8a3bceeaae39f9e72783c30840d472e30ca6
parent1adebefc3ea5dd996a3ae53e398b5cc9e6f6a602 (diff)
Require static path for `source-env` (#6526)0.68.1
-rw-r--r--crates/nu-command/src/env/source_env.rs134
-rw-r--r--crates/nu-command/tests/commands/source_env.rs32
-rw-r--r--crates/nu-parser/src/parse_keywords.rs10
-rw-r--r--crates/nu-parser/src/parser.rs4
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")]