Don't leak set/set-env/source scopes via actions (#2849)

This commit is contained in:
Jonathan Turner
2021-01-03 19:44:21 +13:00
committed by GitHub
parent 77f915befe
commit fc44df1e45
11 changed files with 114 additions and 152 deletions

View File

@ -84,7 +84,9 @@ async fn benchmark(raw_args: CommandArgs) -> Result<OutputStream, ShellError> {
#[cfg(feature = "rich-benchmark")]
let start = time().await;
context.scope.enter_scope();
let result = run_block(&block.block, &context, input).await;
context.scope.exit_scope();
let output = result?.into_vec().await;
#[cfg(feature = "rich-benchmark")]
@ -152,7 +154,10 @@ where
// add autoview for an empty block
let time_block = add_implicit_autoview(time_block.block);
let _ = run_block(&time_block, context, benchmark_output).await?;
context.scope.enter_scope();
let result = run_block(&time_block, context, benchmark_output).await;
context.scope.exit_scope();
result?;
context.clear_errors();
Ok(block_output.into())

View File

@ -19,7 +19,6 @@ pub async fn run_block(
mut input: InputStream,
) -> Result<InputStream, ShellError> {
let mut output: Result<InputStream, ShellError> = Ok(InputStream::empty());
ctx.scope.enter_scope();
for (_, definition) in block.definitions.iter() {
ctx.scope.add_definition(definition.clone());
}
@ -48,7 +47,6 @@ pub async fn run_block(
{
Ok(x) => x,
Err(e) => {
ctx.scope.exit_scope();
return Err(e);
}
};
@ -57,36 +55,30 @@ pub async fn run_block(
value: UntaggedValue::Error(e),
..
}))) => {
ctx.scope.exit_scope();
return Err(e);
}
Ok(Some(_item)) => {
if let Some(err) = ctx.get_errors().get(0) {
ctx.clear_errors();
ctx.scope.exit_scope();
return Err(err.clone());
}
if ctx.ctrl_c.load(Ordering::SeqCst) {
ctx.scope.exit_scope();
return Ok(InputStream::empty());
}
}
Ok(None) => {
if let Some(err) = ctx.get_errors().get(0) {
ctx.clear_errors();
ctx.scope.exit_scope();
return Err(err.clone());
}
}
Err(e) => {
ctx.scope.exit_scope();
return Err(e);
}
}
}
}
Err(e) => {
ctx.scope.exit_scope();
return Err(e);
}
}
@ -102,13 +94,11 @@ pub async fn run_block(
value: UntaggedValue::Error(e),
..
}))) => {
ctx.scope.exit_scope();
return Err(e);
}
Ok(Some(_item)) => {
if let Some(err) = ctx.get_errors().get(0) {
ctx.clear_errors();
ctx.scope.exit_scope();
return Err(err.clone());
}
if ctx.ctrl_c.load(Ordering::SeqCst) {
@ -117,25 +107,21 @@ pub async fn run_block(
// causes lifetime issues. A future contribution
// could attempt to return the current output.
// https://github.com/nushell/nushell/pull/2830#discussion_r550319687
ctx.scope.exit_scope();
return Ok(InputStream::empty());
}
}
Ok(None) => {
if let Some(err) = ctx.get_errors().get(0) {
ctx.clear_errors();
ctx.scope.exit_scope();
return Err(err.clone());
}
}
Err(e) => {
ctx.scope.exit_scope();
return Err(e);
}
}
}
Err(e) => {
ctx.scope.exit_scope();
return Err(e);
}
}
@ -144,7 +130,6 @@ pub async fn run_block(
input = InputStream::empty();
}
}
ctx.scope.exit_scope();
output
}

View File

@ -176,39 +176,6 @@ pub(crate) async fn run_internal_command(
));
InputStream::from_stream(futures::stream::iter(vec![]))
}
CommandAction::AddVariable(name, value) => {
context.scope.add_var(name, value);
InputStream::from_stream(futures::stream::iter(vec![]))
}
CommandAction::AddEnvVariable(name, value) => {
context.scope.add_env_var(name, value);
InputStream::from_stream(futures::stream::iter(vec![]))
}
CommandAction::SourceScript(filename) => {
let contents = std::fs::read_to_string(&filename.item);
match contents {
Ok(contents) => {
let result = crate::script::run_script_standalone(
contents, true, &context, false,
)
.await;
if let Err(err) = result {
context.error(err.into());
}
InputStream::empty()
}
Err(_) => {
context.error(ShellError::labeled_error(
"Can't load file to source",
"can't load file",
filename.span(),
));
InputStream::empty()
}
}
}
CommandAction::AddPlugins(path) => {
match crate::plugin::scan(vec![std::path::PathBuf::from(path)]) {
Ok(plugins) => {

View File

@ -83,8 +83,9 @@ async fn do_(raw_args: CommandArgs) -> Result<OutputStream, ShellError> {
};
block.block.set_redirect(block_redirection);
context.scope.enter_scope();
let result = run_block(&block.block, &context, input).await;
context.scope.exit_scope();
if ignore_errors {
// To properly ignore errors we need to redirect stderr, consume it, and remove

View File

@ -2,10 +2,7 @@ use crate::prelude::*;
use crate::{commands::WholeStreamCommand, evaluate::evaluate_baseline_expr};
use nu_errors::ShellError;
use nu_protocol::{
hir::CapturedBlock, hir::ClassifiedCommand, CommandAction, ReturnSuccess, Signature,
SyntaxShape,
};
use nu_protocol::{hir::CapturedBlock, hir::ClassifiedCommand, Signature, SyntaxShape};
use nu_source::Tagged;
pub struct Set;
@ -97,7 +94,10 @@ pub async fn set(args: CommandArgs) -> Result<OutputStream, ShellError> {
format!("${}", name.item)
};
Ok(OutputStream::one(ReturnSuccess::action(
CommandAction::AddVariable(name, value),
)))
// Note: this is a special case for setting the context from a command
// In this case, if we don't set it now, we'll lose the scope that this
// variable should be set into.
ctx.scope.add_var(name, value);
Ok(OutputStream::empty())
}

View File

@ -2,10 +2,7 @@ use crate::prelude::*;
use crate::{commands::WholeStreamCommand, evaluate::evaluate_baseline_expr};
use nu_errors::ShellError;
use nu_protocol::{
hir::CapturedBlock, hir::ClassifiedCommand, CommandAction, ReturnSuccess, Signature,
SyntaxShape,
};
use nu_protocol::{hir::CapturedBlock, hir::ClassifiedCommand, Signature, SyntaxShape};
use nu_source::Tagged;
pub struct SetEnv;
@ -98,7 +95,10 @@ pub async fn set_env(args: CommandArgs) -> Result<OutputStream, ShellError> {
let name = name.item.clone();
Ok(OutputStream::one(ReturnSuccess::action(
CommandAction::AddEnvVariable(name, value),
)))
// Note: this is a special case for setting the context from a command
// In this case, if we don't set it now, we'll lose the scope that this
// variable should be set into.
ctx.scope.add_env_var(name, value);
Ok(OutputStream::empty())
}

View File

@ -2,7 +2,7 @@ use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_errors::ShellError;
use nu_protocol::{CommandAction, ReturnSuccess, Signature, SyntaxShape};
use nu_protocol::{Signature, SyntaxShape};
use nu_source::Tagged;
pub struct Source;
@ -40,9 +40,30 @@ impl WholeStreamCommand for Source {
}
pub async fn source(args: CommandArgs) -> Result<OutputStream, ShellError> {
let ctx = EvaluationContext::from_args(&args);
let (SourceArgs { filename }, _) = args.process().await?;
Ok(OutputStream::one(ReturnSuccess::action(
CommandAction::SourceScript(filename),
)))
// Note: this is a special case for setting the context from a command
// In this case, if we don't set it now, we'll lose the scope that this
// variable should be set into.
let contents = std::fs::read_to_string(&filename.item);
match contents {
Ok(contents) => {
let result = crate::script::run_script_standalone(contents, true, &ctx, false).await;
if let Err(err) = result {
ctx.error(err.into());
}
Ok(OutputStream::empty())
}
Err(_) => {
ctx.error(ShellError::labeled_error(
"Can't load file to source",
"can't load file",
filename.span(),
));
Ok(OutputStream::empty())
}
}
}

View File

@ -52,6 +52,10 @@ impl Scope {
names
}
pub fn len(&self) -> usize {
self.frames.lock().len()
}
fn has_cmd_helper(&self, name: &str, f: fn(&ScopeFrame, &str) -> bool) -> bool {
self.frames.lock().iter().any(|frame| f(frame, name))
}