Add script sourcing (#2803)

* Add script sourcing

* clippy
This commit is contained in:
Jonathan Turner 2020-12-19 20:47:34 +13:00 committed by GitHub
parent 058ef69da3
commit e5b136f70d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 98 additions and 42 deletions

View File

@ -58,7 +58,7 @@ pub fn search_paths() -> Vec<std::path::PathBuf> {
}
pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Box<dyn Error>> {
let mut context = EvaluationContext::basic()?;
let context = EvaluationContext::basic()?;
{
use crate::commands::*;
@ -69,6 +69,7 @@ pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Bo
whole_stream_command(Set),
whole_stream_command(SetEnv),
whole_stream_command(Def),
whole_stream_command(Source),
// System/file operations
whole_stream_command(Exec),
whole_stream_command(Pwd),
@ -325,7 +326,7 @@ pub async fn run_script_file(
let _ = run_startup_commands(&mut context, &config).await;
run_script_standalone(file_contents, redirect_stdin, &mut context, true).await?;
run_script_standalone(file_contents, redirect_stdin, &context, true).await?;
Ok(())
}
@ -497,7 +498,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
LineResult::Success(_) => {
process_script(
&session_text[line_start..],
&mut context,
&context,
false,
line_start,
true,
@ -648,7 +649,7 @@ async fn run_startup_commands(
pub async fn run_script_standalone(
script_text: String,
redirect_stdin: bool,
context: &mut EvaluationContext,
context: &EvaluationContext,
exit_on_error: bool,
) -> Result<(), Box<dyn Error>> {
let line = process_script(&script_text, context, redirect_stdin, 0, false).await;
@ -888,7 +889,7 @@ pub enum LineResult {
ClearHistory,
}
pub async fn parse_and_eval(line: &str, ctx: &mut EvaluationContext) -> Result<String, ShellError> {
pub async fn parse_and_eval(line: &str, ctx: &EvaluationContext) -> Result<String, ShellError> {
// FIXME: do we still need this?
let line = if let Some(s) = line.strip_suffix('\n') {
s
@ -917,7 +918,7 @@ pub async fn parse_and_eval(line: &str, ctx: &mut EvaluationContext) -> Result<S
/// Process the line by parsing the text to turn it into commands, classify those commands so that we understand what is being called in the pipeline, and then run this pipeline
pub async fn process_script(
script_text: &str,
ctx: &mut EvaluationContext,
ctx: &EvaluationContext,
redirect_stdin: bool,
span_offset: usize,
cli_mode: bool,
@ -926,7 +927,6 @@ pub async fn process_script(
LineResult::Success(script_text.to_string())
} else {
let line = chomp_newline(script_text);
ctx.raw_input = line.to_string();
let (block, err) = nu_parser::parse(&line, span_offset, &ctx.scope);
@ -1067,7 +1067,6 @@ pub async fn process_script(
current_errors: ctx.current_errors.clone(),
scope: ctx.scope.clone(),
name: Tag::unknown(),
raw_input: line.to_string(),
};
if let Ok(mut output_stream) =

View File

@ -108,6 +108,7 @@ pub(crate) mod size;
pub(crate) mod skip;
pub(crate) mod sleep;
pub(crate) mod sort_by;
pub(crate) mod source;
pub(crate) mod split;
pub(crate) mod split_by;
pub(crate) mod str_;
@ -255,6 +256,7 @@ pub(crate) use size::Size;
pub(crate) use skip::{Skip, SkipUntil, SkipWhile};
pub(crate) use sleep::Sleep;
pub(crate) use sort_by::SortBy;
pub(crate) use source::Source;
pub(crate) use split::{Split, SplitChars, SplitColumn, SplitRow};
pub(crate) use split_by::SplitBy;
pub(crate) use str_::{

View File

@ -35,7 +35,6 @@ impl WholeStreamCommand for Command {
ctrl_c: args.ctrl_c,
current_errors: args.current_errors,
name: args.call_info.name_tag,
raw_input: args.raw_input,
})
.await
}

View File

@ -47,7 +47,7 @@ pub(crate) async fn run_internal_command(
.then(move |item| {
let head = head.clone();
let command = command.clone();
let mut context = context.clone();
let context = context.clone();
async move {
match item {
Ok(ReturnSuccess::Action(action)) => match action {
@ -188,6 +188,29 @@ pub(crate) async fn run_internal_command(
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);
if let Ok(contents) = contents {
let result = crate::cli::run_script_standalone(
contents, true, &context, false,
)
.await;
if let Err(err) = result {
return InputStream::one(
UntaggedValue::Error(err.into()).into_untagged_value(),
);
}
InputStream::from_stream(futures::stream::iter(vec![]))
} else {
InputStream::one(
UntaggedValue::Error(ShellError::untagged_runtime_error(
format!("could not source '{}'", filename),
))
.into_untagged_value(),
)
}
}
CommandAction::AddPlugins(path) => {
match crate::plugin::scan(vec![std::path::PathBuf::from(path)]) {
Ok(plugins) => {

View File

@ -43,7 +43,6 @@ pub struct CommandArgs {
pub call_info: UnevaluatedCallInfo,
pub scope: Scope,
pub input: InputStream,
pub raw_input: String,
}
#[derive(Getters, Clone)]
@ -67,7 +66,6 @@ impl RawCommandArgs {
call_info: self.call_info,
scope: self.scope,
input: input.into(),
raw_input: String::default(),
}
}
}
@ -116,7 +114,6 @@ pub struct RunnableContext {
pub current_errors: Arc<Mutex<Vec<ShellError>>>,
pub scope: Scope,
pub name: Tag,
pub raw_input: String,
}
impl RunnableContext {

View File

@ -38,7 +38,6 @@ impl WholeStreamCommand for SubCommand {
ctrl_c: args.ctrl_c,
current_errors: args.current_errors,
name: args.call_info.name_tag,
raw_input: args.raw_input,
},
average,
)

View File

@ -31,7 +31,6 @@ impl WholeStreamCommand for SubCommand {
ctrl_c: args.ctrl_c,
current_errors: args.current_errors,
name: args.call_info.name_tag,
raw_input: args.raw_input,
},
ceil_big_int,
ceil_big_decimal,

View File

@ -31,7 +31,6 @@ impl WholeStreamCommand for SubCommand {
ctrl_c: args.ctrl_c,
current_errors: args.current_errors,
name: args.call_info.name_tag,
raw_input: args.raw_input,
},
floor_big_int,
floor_big_decimal,

View File

@ -31,7 +31,6 @@ impl WholeStreamCommand for SubCommand {
ctrl_c: args.ctrl_c,
current_errors: args.current_errors,
name: args.call_info.name_tag,
raw_input: args.raw_input,
},
maximum,
)

View File

@ -35,7 +35,6 @@ impl WholeStreamCommand for SubCommand {
ctrl_c: args.ctrl_c,
current_errors: args.current_errors,
name: args.call_info.name_tag,
raw_input: args.raw_input,
},
median,
)

View File

@ -31,7 +31,6 @@ impl WholeStreamCommand for SubCommand {
ctrl_c: args.ctrl_c,
current_errors: args.current_errors,
name: args.call_info.name_tag,
raw_input: args.raw_input,
},
minimum,
)

View File

@ -31,7 +31,6 @@ impl WholeStreamCommand for SubCommand {
ctrl_c: args.ctrl_c,
current_errors: args.current_errors,
name: args.call_info.name_tag,
raw_input: args.raw_input,
},
mode,
)

View File

@ -34,7 +34,6 @@ impl WholeStreamCommand for SubCommand {
ctrl_c: args.ctrl_c,
current_errors: args.current_errors,
name: args.call_info.name_tag,
raw_input: args.raw_input,
},
product,
)

View File

@ -35,7 +35,6 @@ impl WholeStreamCommand for SubCommand {
ctrl_c: args.ctrl_c,
current_errors: args.current_errors,
name: args.call_info.name_tag,
raw_input: args.raw_input,
},
summation,
)

View File

@ -88,7 +88,6 @@ impl WholeStreamCommand for RunExternalCommand {
ctrl_c: args.ctrl_c.clone(),
current_errors: Arc::new(Mutex::new(vec![])),
windows_drives_previous_cwd: Arc::new(Mutex::new(std::collections::HashMap::new())),
raw_input: String::default(),
}
};

View File

@ -165,7 +165,7 @@ async fn save(raw_args: CommandArgs) -> Result<OutputStream, ShellError> {
let host = raw_args.host.clone();
let ctrl_c = raw_args.ctrl_c.clone();
let current_errors = raw_args.current_errors.clone();
let mut shell_manager = raw_args.shell_manager.clone();
let shell_manager = raw_args.shell_manager.clone();
let head = raw_args.call_info.args.head.clone();
let (

View File

@ -0,0 +1,48 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_errors::ShellError;
use nu_protocol::{CommandAction, ReturnSuccess, Signature, SyntaxShape};
use nu_source::Tagged;
pub struct Source;
#[derive(Deserialize)]
pub struct SourceArgs {
pub filename: Tagged<String>,
}
#[async_trait]
impl WholeStreamCommand for Source {
fn name(&self) -> &str {
"source"
}
fn signature(&self) -> Signature {
Signature::build("source").required(
"filename",
SyntaxShape::String,
"the filepath to the script file to source",
)
}
fn usage(&self) -> &str {
"Runs a script file in the current context."
}
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
source(args).await
}
fn examples(&self) -> Vec<Example> {
vec![]
}
}
pub async fn source(args: CommandArgs) -> Result<OutputStream, ShellError> {
let (SourceArgs { filename }, _) = args.process().await?;
Ok(OutputStream::one(ReturnSuccess::action(
CommandAction::SourceScript(filename.item),
)))
}

View File

@ -16,7 +16,6 @@ pub struct EvaluationContext {
pub host: Arc<parking_lot::Mutex<Box<dyn Host>>>,
pub current_errors: Arc<Mutex<Vec<ShellError>>>,
pub ctrl_c: Arc<AtomicBool>,
pub raw_input: String,
pub user_recently_used_autoenv_untrust: Arc<AtomicBool>,
pub(crate) shell_manager: ShellManager,
@ -34,7 +33,6 @@ impl EvaluationContext {
shell_manager: raw_args.shell_manager.clone(),
user_recently_used_autoenv_untrust: Arc::new(AtomicBool::new(false)),
windows_drives_previous_cwd: Arc::new(Mutex::new(std::collections::HashMap::new())),
raw_input: String::default(),
}
}
@ -47,7 +45,6 @@ impl EvaluationContext {
shell_manager: args.shell_manager.clone(),
user_recently_used_autoenv_untrust: Arc::new(AtomicBool::new(false)),
windows_drives_previous_cwd: Arc::new(Mutex::new(std::collections::HashMap::new())),
raw_input: String::default(),
}
}
@ -62,7 +59,6 @@ impl EvaluationContext {
user_recently_used_autoenv_untrust: Arc::new(AtomicBool::new(false)),
shell_manager: ShellManager::basic()?,
windows_drives_previous_cwd: Arc::new(Mutex::new(std::collections::HashMap::new())),
raw_input: String::default(),
})
}
@ -82,7 +78,7 @@ impl EvaluationContext {
self.current_errors.lock().push(err);
}
pub(crate) fn maybe_print_errors(&mut self, source: Text) -> bool {
pub(crate) fn maybe_print_errors(&self, source: Text) -> bool {
let errors = self.current_errors.clone();
let mut errors = errors.lock();
@ -105,7 +101,7 @@ impl EvaluationContext {
block(config, &mut *self);
}
pub(crate) fn with_host<T>(&mut self, block: impl FnOnce(&mut dyn Host) -> T) -> T {
pub(crate) fn with_host<T>(&self, block: impl FnOnce(&mut dyn Host) -> T) -> T {
let mut host = self.host.lock();
block(&mut *host)
@ -117,7 +113,7 @@ impl EvaluationContext {
block(&mut *errors)
}
pub fn add_commands(&mut self, commands: Vec<Command>) {
pub fn add_commands(&self, commands: Vec<Command>) {
for command in commands {
self.scope.add_command(command.name().to_string(), command);
}
@ -156,7 +152,6 @@ impl EvaluationContext {
call_info: self.call_info(args, name_tag),
scope: self.scope.clone(),
input,
raw_input: self.raw_input.clone(),
}
}

View File

@ -26,7 +26,7 @@ use serde::Deserialize;
pub fn test_examples(cmd: Command) -> Result<(), ShellError> {
let examples = cmd.examples();
let mut base_context = EvaluationContext::basic()?;
let base_context = EvaluationContext::basic()?;
base_context.add_commands(vec![
// Mocks
@ -89,7 +89,7 @@ pub fn test_examples(cmd: Command) -> Result<(), ShellError> {
pub fn test(cmd: impl WholeStreamCommand + 'static) -> Result<(), ShellError> {
let examples = cmd.examples();
let mut base_context = EvaluationContext::basic()?;
let base_context = EvaluationContext::basic()?;
base_context.add_commands(vec![
whole_stream_command(Echo {}),
@ -144,7 +144,7 @@ pub fn test(cmd: impl WholeStreamCommand + 'static) -> Result<(), ShellError> {
pub fn test_anchors(cmd: Command) -> Result<(), ShellError> {
let examples = cmd.examples();
let mut base_context = EvaluationContext::basic()?;
let base_context = EvaluationContext::basic()?;
base_context.add_commands(vec![
// Minimal restricted commands to aid in testing
@ -192,7 +192,7 @@ pub fn test_anchors(cmd: Command) -> Result<(), ShellError> {
}
/// Parse and run a nushell pipeline
fn parse_line(line: &str, ctx: &mut EvaluationContext) -> Result<ClassifiedBlock, ShellError> {
fn parse_line(line: &str, ctx: &EvaluationContext) -> Result<ClassifiedBlock, ShellError> {
//FIXME: do we still need this?
let line = if let Some(line) = line.strip_suffix('\n') {
line

View File

@ -33,7 +33,7 @@ impl ShellManager {
})
}
pub fn insert_at_current(&mut self, shell: Box<dyn Shell + Send>) {
pub fn insert_at_current(&self, shell: Box<dyn Shell + Send>) {
self.shells.lock().push(shell);
self.current_shell
.store(self.shells.lock().len() - 1, Ordering::SeqCst);
@ -44,7 +44,7 @@ impl ShellManager {
self.current_shell.load(Ordering::SeqCst)
}
pub fn remove_at_current(&mut self) {
pub fn remove_at_current(&self) {
{
let mut shells = self.shells.lock();
if shells.len() > 0 {
@ -78,7 +78,7 @@ impl ShellManager {
env[self.current_shell()].pwd(args)
}
pub fn set_path(&mut self, path: String) {
pub fn set_path(&self, path: String) {
self.shells.lock()[self.current_shell()].set_path(path)
}
@ -93,7 +93,7 @@ impl ShellManager {
}
pub fn save(
&mut self,
&self,
full_path: &PathBuf,
save_data: &[u8],
name: Span,
@ -101,7 +101,7 @@ impl ShellManager {
self.shells.lock()[self.current_shell()].save(full_path, save_data, name)
}
pub fn next(&mut self) {
pub fn next(&self) {
{
let shell_len = self.shells.lock().len();
if self.current_shell() == (shell_len - 1) {
@ -114,7 +114,7 @@ impl ShellManager {
self.set_path(self.path())
}
pub fn prev(&mut self) {
pub fn prev(&self) {
{
let shell_len = self.shells.lock().len();
if self.current_shell() == 0 {

View File

@ -26,6 +26,8 @@ pub enum CommandAction {
AddEnvVariable(String, String),
/// Add plugins from path given
AddPlugins(String),
/// Run the given script in the current context (given filename)
SourceScript(String),
/// Go to the previous shell in the shell ring buffer
PreviousShell,
/// Go to the next shell in the shell ring buffer
@ -49,6 +51,7 @@ impl PrettyDebug for CommandAction {
CommandAction::EnterHelpShell(v) => b::typed("enter help shell", v.pretty()),
CommandAction::AddVariable(..) => b::description("add variable"),
CommandAction::AddEnvVariable(..) => b::description("add environment variable"),
CommandAction::SourceScript(..) => b::description("source script"),
CommandAction::AddPlugins(..) => b::description("add plugins"),
CommandAction::PreviousShell => b::description("previous shell"),
CommandAction::NextShell => b::description("next shell"),