Move script to nu engine (#3092)

* Move run_script to engine

* Add which dep and feature to engine

* Change unwrap to expect

* Add wasm specification

* Remove which from default, add specification correctly

* Add nu-platform-specifics

* Move is_external_cmd to platform_specifics

* Add is_external_cmd to host and use it instead of nu_platform directly

* Clean up if else logic in is_external_cmd

* Bump nu-platform-specifics version

* Pass context to print_err

* Commit cargo.lock

* Move print functions to own module inside nu-engine

* Hypocratic change to run windows-nightly again

* Add import for Ordering

* Move printing of error to host

* Move platform specific which functionality to basic host

* Allow no use of cmd_name

* Fix windows compile issue
This commit is contained in:
Leonhard Kipp 2021-03-12 06:20:54 +01:00 committed by GitHub
parent 86a89404be
commit 6cf8df8685
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 576 additions and 559 deletions

868
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -84,6 +84,7 @@ which-support = [
"nu-cli/which",
"nu-command/ichwh",
"nu-command/which",
"nu-engine/which"
]
default = [

View file

@ -1,12 +1,11 @@
use crate::line_editor::configure_ctrl_c;
use nu_command::commands::default_context::create_default_context;
#[allow(unused_imports)]
use nu_command::maybe_print_errors;
use nu_engine::run_block;
use nu_engine::EvaluationContext;
use nu_engine::{
print::maybe_print_errors, run_block, script::run_script_standalone, EvaluationContext,
};
#[allow(unused_imports)]
pub(crate) use nu_command::script::{process_script, LineResult};
pub(crate) use nu_engine::script::{process_script, LineResult};
#[cfg(feature = "rustyline-support")]
use crate::line_editor::{
@ -21,8 +20,6 @@ use nu_stream::InputStream;
#[allow(unused_imports)]
use std::sync::atomic::Ordering;
use nu_command::script::{print_err, run_script_standalone};
#[cfg(feature = "rustyline-support")]
use rustyline::{self, error::ReadlineError};
@ -79,7 +76,7 @@ pub async fn run_script_file(
syncer.sync_path_vars(ctx);
if let Err(reason) = syncer.autoenv(ctx) {
print_err(reason, &Text::from(""), ctx);
ctx.host.lock().print_err(reason, &Text::from(""));
}
let _ = register_plugins(ctx);
@ -107,7 +104,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
syncer.sync_path_vars(ctx);
if let Err(reason) = syncer.autoenv(ctx) {
print_err(reason, &Text::from(""), ctx);
ctx.host.lock().print_err(reason, &Text::from(""));
}
let _ = configure_ctrl_c(ctx);
@ -199,14 +196,14 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
}
}
Err(e) => {
crate::cli::print_err(e, &Text::from(prompt_line), &context);
context.host.lock().print_err(e, &Text::from(prompt_line));
context.clear_errors();
"> ".to_string()
}
},
Err(e) => {
crate::cli::print_err(e, &Text::from(prompt_line), &context);
context.host.lock().print_err(e, &Text::from(prompt_line));
context.clear_errors();
"> ".to_string()
@ -274,7 +271,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
}
if let Err(reason) = syncer.autoenv(ctx) {
print_err(reason, &Text::from(""), ctx);
ctx.host.lock().print_err(reason, &Text::from(""));
}
let _ = configure_rustyline_editor(&mut rl, config);
@ -296,7 +293,10 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
rl.add_history_entry(&line);
let _ = rl.save_history(&history_path);
print_err(err, &Text::from(session_text.clone()), &context);
context
.host
.lock()
.print_err(err, &Text::from(session_text.clone()));
maybe_print_errors(&context, Text::from(session_text.clone()));
}

View file

@ -5,7 +5,7 @@ use std::error::Error;
use crate::prelude::*;
#[allow(unused_imports)]
use nu_command::script::LineResult;
use nu_engine::script::LineResult;
#[cfg(feature = "rustyline-support")]
use crate::shell::Helper;

View file

@ -20,7 +20,6 @@ pub(crate) mod chart;
pub(crate) mod classified;
#[cfg(feature = "clipboard-cli")]
pub(crate) mod clip;
pub mod command;
pub(crate) mod compact;
pub(crate) mod config;
pub(crate) mod constants;

View file

@ -28,7 +28,7 @@ pub(crate) async fn run_external_command(
) -> Result<InputStream, ShellError> {
trace!(target: "nu::run::external", "-> {}", command.name);
if !did_find_command(&command.name) {
if !context.host.lock().is_external_cmd(&command.name) {
return Err(ShellError::labeled_error(
"Command not found",
"command not found",
@ -443,35 +443,6 @@ fn spawn(
}
}
pub fn did_find_command(#[allow(unused)] name: &str) -> bool {
#[cfg(not(feature = "which"))]
{
// we can't perform this check, so just assume it can be found
true
}
#[cfg(all(feature = "which", unix))]
{
which::which(name).is_ok()
}
#[cfg(all(feature = "which", windows))]
{
if which::which(name).is_ok() {
true
} else {
// Reference: https://ss64.com/nt/syntax-internal.html
let cmd_builtins = [
"assoc", "break", "color", "copy", "date", "del", "dir", "dpath", "echo", "erase",
"for", "ftype", "md", "mkdir", "mklink", "move", "path", "ren", "rename", "rd",
"rmdir", "start", "time", "title", "type", "ver", "verify", "vol",
];
cmd_builtins.contains(&name)
}
}
}
fn expand_tilde<SI: ?Sized, P, HD>(input: &SI, home_dir: HD) -> std::borrow::Cow<str>
where
SI: AsRef<str>,

View file

@ -147,7 +147,7 @@ async fn maybe_autocd_dir<'a>(
|| (cmd.args.is_empty()
&& PathBuf::from(name).is_dir()
&& dunce::canonicalize(name).is_ok()
&& !crate::commands::classified::external::did_find_command(&name))
&& !ctx.host.lock().is_external_cmd(&name))
{
Some(name)
} else {

View file

@ -1,5 +1,5 @@
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_engine::{script, WholeStreamCommand};
use nu_errors::ShellError;
use nu_parser::expand_path;
@ -50,7 +50,7 @@ pub async fn source(args: CommandArgs) -> Result<OutputStream, ShellError> {
let contents = std::fs::read_to_string(expand_path(&filename.item).into_owned());
match contents {
Ok(contents) => {
let result = crate::script::run_script_standalone(contents, true, &ctx, false).await;
let result = script::run_script_standalone(contents, true, &ctx, false).await;
if let Err(err) = result {
ctx.error(err.into());

View file

@ -7,7 +7,9 @@ use nu_errors::ShellError;
use nu_protocol::{Primitive, Signature, SyntaxShape, UntaggedValue, Value};
use nu_table::{draw_table, Alignment, StyledString, TextStyle};
use std::collections::HashMap;
use std::sync::atomic::Ordering;
use std::time::Instant;
#[cfg(feature = "table-pager")]
use {
futures::future::join,

View file

@ -8,15 +8,11 @@ extern crate indexmap;
mod prelude;
pub mod commands;
mod futures;
pub mod maybe_print_errors;
pub mod script;
pub mod utils;
#[cfg(test)]
mod examples;
pub use crate::maybe_print_errors::maybe_print_errors;
pub use nu_data::config;
pub use nu_data::dict::TaggedListBuilder;
pub use nu_data::primitive;

View file

@ -46,7 +46,6 @@ macro_rules! trace_out_stream {
}};
}
pub(crate) use crate::commands::command::RunnableContext;
pub(crate) use async_trait::async_trait;
pub(crate) use bigdecimal::BigDecimal;
pub(crate) use futures::{Stream, StreamExt};
@ -58,11 +57,12 @@ pub(crate) use nu_engine::EvaluationContext;
pub(crate) use nu_engine::Example;
pub(crate) use nu_engine::Host;
pub(crate) use nu_engine::RawCommandArgs;
pub(crate) use nu_engine::RunnableContext;
pub(crate) use nu_engine::ShellManager;
pub(crate) use nu_engine::{get_full_help, CommandArgs, Scope, WholeStreamCommand};
pub(crate) use nu_parser::ParserScope;
pub(crate) use nu_protocol::{out, row};
pub(crate) use nu_source::{AnchorLocation, PrettyDebug, Span, SpannedItem, Tag, TaggedItem, Text};
pub(crate) use nu_source::{AnchorLocation, PrettyDebug, Span, SpannedItem, Tag, TaggedItem};
pub(crate) use nu_stream::ToInputStream;
pub(crate) use nu_stream::{InputStream, Interruptible, OutputStream};
pub(crate) use nu_value_ext::ValueExt;
@ -71,7 +71,7 @@ pub(crate) use num_traits::cast::ToPrimitive;
pub(crate) use serde::Deserialize;
pub(crate) use std::collections::VecDeque;
pub(crate) use std::future::Future;
pub(crate) use std::sync::atomic::{AtomicBool, Ordering};
pub(crate) use std::sync::atomic::AtomicBool;
pub(crate) use std::sync::Arc;
#[allow(clippy::wrong_self_convention)]

View file

@ -18,6 +18,8 @@ nu-value-ext = { version = "0.28.0", path = "../nu-value-ext" }
nu-ansi-term = { version = "0.28.0", path = "../nu-ansi-term" }
trash = { version = "1.3.0", optional = true }
which = { version = "4.0.2", optional = true }
codespan-reporting = "0.11.0"
async-recursion = "0.3.2"
async-trait = "0.1.42"
bytes = "0.5.6"

View file

@ -1,5 +1,7 @@
use crate::Host;
use nu_errors::ShellError;
use nu_protocol::{errln, outln};
use nu_source::Text;
use std::ffi::OsString;
#[derive(Debug)]
@ -20,6 +22,21 @@ impl Host for BasicHost {
}
}
fn print_err(&mut self, err: ShellError, source: &Text) {
if let Some(diag) = err.into_diagnostic() {
let source = source.to_string();
let mut files = codespan_reporting::files::SimpleFiles::new();
files.add("shell", source);
let writer = termcolor::StandardStream::stderr(termcolor::ColorChoice::Auto);
let config = codespan_reporting::term::Config::default();
let _ = std::panic::catch_unwind(move || {
let _ = codespan_reporting::term::emit(&mut writer.lock(), &config, &files, &diag);
});
}
}
#[allow(unused_variables)]
fn vars(&mut self) -> Vec<(String, String)> {
#[cfg(not(target_arch = "wasm32"))]
@ -61,14 +78,6 @@ impl Host for BasicHost {
}
}
fn out_termcolor(&self) -> termcolor::StandardStream {
termcolor::StandardStream::stdout(termcolor::ColorChoice::Auto)
}
fn err_termcolor(&self) -> termcolor::StandardStream {
termcolor::StandardStream::stderr(termcolor::ColorChoice::Auto)
}
fn width(&self) -> usize {
let (mut term_width, _) = term_size::dimensions().unwrap_or((80, 20));
term_width -= 1;
@ -79,4 +88,33 @@ impl Host for BasicHost {
let (_, term_height) = term_size::dimensions().unwrap_or((80, 20));
term_height
}
fn is_external_cmd(&self, #[allow(unused)] cmd_name: &str) -> bool {
#[cfg(any(target_arch = "wasm32", not(feature = "which")))]
{
true
}
#[cfg(all(unix, feature = "which"))]
{
which::which(cmd_name).is_ok()
}
#[cfg(all(windows, feature = "which"))]
{
if which::which(cmd_name).is_ok() {
true
} else {
// Reference: https://ss64.com/nt/syntax-internal.html
let cmd_builtins = [
"assoc", "break", "color", "copy", "date", "del", "dir", "dpath", "echo",
"erase", "for", "ftype", "md", "mkdir", "mklink", "move", "path", "ren",
"rename", "rd", "rmdir", "start", "time", "title", "type", "ver", "verify",
"vol",
];
cmd_builtins.contains(&cmd_name)
}
}
}
}

View file

@ -1,13 +1,15 @@
use indexmap::IndexMap;
use nu_errors::ShellError;
use nu_source::Text;
use std::ffi::OsString;
use std::fmt::Debug;
pub trait Host: Debug + Send {
fn out_termcolor(&self) -> termcolor::StandardStream;
fn err_termcolor(&self) -> termcolor::StandardStream;
use super::basic_host::BasicHost;
pub trait Host: Debug + Send {
fn stdout(&mut self, out: &str);
fn stderr(&mut self, out: &str);
fn print_err(&mut self, err: ShellError, source: &Text);
fn vars(&mut self) -> Vec<(String, String)>;
fn env_get(&mut self, key: OsString) -> Option<OsString>;
@ -16,6 +18,8 @@ pub trait Host: Debug + Send {
fn width(&self) -> usize;
fn height(&self) -> usize;
fn is_external_cmd(&self, cmd_name: &str) -> bool;
}
impl Host for Box<dyn Host> {
@ -27,6 +31,10 @@ impl Host for Box<dyn Host> {
(**self).stderr(out)
}
fn print_err(&mut self, err: ShellError, source: &Text) {
(**self).print_err(err, source)
}
fn vars(&mut self) -> Vec<(String, String)> {
(**self).vars()
}
@ -43,14 +51,6 @@ impl Host for Box<dyn Host> {
(**self).env_rm(key)
}
fn out_termcolor(&self) -> termcolor::StandardStream {
(**self).out_termcolor()
}
fn err_termcolor(&self) -> termcolor::StandardStream {
(**self).err_termcolor()
}
fn width(&self) -> usize {
(**self).width()
}
@ -58,6 +58,10 @@ impl Host for Box<dyn Host> {
fn height(&self) -> usize {
(**self).height()
}
fn is_external_cmd(&self, name: &str) -> bool {
(**self).is_external_cmd(name)
}
}
#[derive(Debug)]
@ -90,6 +94,10 @@ impl Host for FakeHost {
self.line_written = out.to_string();
}
fn print_err(&mut self, err: ShellError, source: &Text) {
BasicHost {}.print_err(err, source);
}
fn vars(&mut self) -> Vec<(String, String)> {
self.env_vars
.iter()
@ -118,14 +126,6 @@ impl Host for FakeHost {
.shift_remove(&key.into_string().expect("Couldn't convert to string."));
}
fn out_termcolor(&self) -> termcolor::StandardStream {
termcolor::StandardStream::stdout(termcolor::ColorChoice::Auto)
}
fn err_termcolor(&self) -> termcolor::StandardStream {
termcolor::StandardStream::stderr(termcolor::ColorChoice::Auto)
}
fn width(&self) -> usize {
1
}
@ -133,4 +133,8 @@ impl Host for FakeHost {
fn height(&self) -> usize {
1
}
fn is_external_cmd(&self, _: &str) -> bool {
true
}
}

View file

@ -12,6 +12,9 @@ pub mod filesystem;
mod history_path;
mod maybe_text_codec;
pub mod plugin;
pub mod print;
mod runnable_context;
pub mod script;
pub mod shell;
mod whole_stream_command;
@ -35,6 +38,7 @@ pub use crate::filesystem::filesystem_shell::FilesystemShell;
pub use crate::filesystem::path;
pub use crate::history_path::history_path;
pub use crate::maybe_text_codec::{MaybeTextCodec, StringOrBinary};
pub use crate::runnable_context::RunnableContext;
pub use crate::shell::help_shell::{command_dict, HelpShell};
pub use crate::shell::painter::Painter;
pub use crate::shell::palette::{DefaultPalette, Palette};

View file

@ -1,6 +1,7 @@
use nu_engine::EvaluationContext;
use nu_source::Text;
use crate::EvaluationContext;
pub fn maybe_print_errors(context: &EvaluationContext, source: Text) -> bool {
let errors = context.current_errors.clone();
let mut errors = errors.lock();
@ -9,7 +10,7 @@ pub fn maybe_print_errors(context: &EvaluationContext, source: Text) -> bool {
let error = errors[0].clone();
*errors = vec![];
crate::script::print_err(error, &source, context);
context.host.lock().print_err(error, &source);
true
} else {
false

View file

@ -1,13 +1,14 @@
use crate::prelude::*;
use nu_engine::Command;
use crate::{Command, Host, Scope, ShellManager};
use nu_errors::ShellError;
use nu_source::Tag;
use nu_stream::InputStream;
use parking_lot::Mutex;
use std::sync::atomic::AtomicBool;
use std::sync::{atomic::AtomicBool, Arc};
pub struct RunnableContext {
pub input: InputStream,
pub shell_manager: ShellManager,
pub host: Arc<parking_lot::Mutex<Box<dyn Host>>>,
pub host: Arc<Mutex<Box<dyn Host>>>,
pub ctrl_c: Arc<AtomicBool>,
pub current_errors: Arc<Mutex<Vec<ShellError>>>,
pub scope: Scope,

View file

@ -1,19 +1,22 @@
use crate::maybe_print_errors;
use crate::prelude::*;
use crate::run_block;
use crate::{path::canonicalize, print::maybe_print_errors};
use crate::{MaybeTextCodec, StringOrBinary};
use futures::StreamExt;
use futures_codec::FramedRead;
use nu_engine::path::canonicalize;
use nu_engine::run_block;
use nu_engine::EvaluationContext;
use nu_engine::{MaybeTextCodec, StringOrBinary};
use nu_errors::ShellError;
use nu_protocol::hir::{ClassifiedCommand, Expression, InternalCommand, Literal, NamedArguments};
use nu_protocol::hir::{
Call, ClassifiedCommand, Expression, InternalCommand, Literal, NamedArguments,
SpannedExpression,
};
use nu_protocol::{Primitive, ReturnSuccess, UntaggedValue, Value};
use nu_stream::ToInputStream;
use nu_stream::{InputStream, ToInputStream};
use crate::EvaluationContext;
use log::{debug, trace};
use std::error::Error;
use nu_source::{Span, Tag, Text};
use std::iter::Iterator;
use std::path::Path;
use std::{error::Error, sync::atomic::Ordering};
#[derive(Debug)]
pub enum LineResult {
@ -33,21 +36,6 @@ fn chomp_newline(s: &str) -> &str {
}
}
pub fn print_err(err: ShellError, source: &Text, ctx: &EvaluationContext) {
if let Some(diag) = err.into_diagnostic() {
let source = source.to_string();
let mut files = codespan_reporting::files::SimpleFiles::new();
files.add("shell", source);
let writer = ctx.host.lock().err_termcolor();
let config = codespan_reporting::term::Config::default();
let _ = std::panic::catch_unwind(move || {
let _ = codespan_reporting::term::emit(&mut writer.lock(), &config, &files, &diag);
});
}
}
/// 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,
@ -113,7 +101,7 @@ pub async fn process_script(
.unwrap_or(true)
&& canonicalize(ctx.shell_manager.path(), name).is_ok()
&& Path::new(&name).is_dir()
&& !crate::commands::classified::external::did_find_command(&name)
&& !ctx.host.lock().is_external_cmd(&name)
{
// Here we work differently if we're in Windows because of the expected Windows behavior
#[cfg(windows)]
@ -192,18 +180,24 @@ pub async fn process_script(
// values to compute them.
use futures::stream::TryStreamExt;
let context = RunnableContext {
input,
shell_manager: ctx.shell_manager.clone(),
host: ctx.host.clone(),
ctrl_c: ctx.ctrl_c.clone(),
current_errors: ctx.current_errors.clone(),
scope: ctx.scope.clone(),
name: Tag::unknown(),
};
let autoview_cmd = ctx
.get_command("autoview")
.expect("Could not find autoview command");
if let Ok(mut output_stream) =
crate::commands::autoview::command::autoview(context).await
if let Ok(mut output_stream) = ctx
.run_command(
autoview_cmd,
Tag::unknown(),
Call::new(
Box::new(SpannedExpression::new(
Expression::string("autoview".to_string()),
Span::unknown(),
)),
Span::unknown(),
),
input,
)
.await
{
loop {
match output_stream.try_next().await {
@ -257,7 +251,10 @@ pub async fn run_script_standalone(
}
LineResult::Error(line, err) => {
print_err(err, &Text::from(line.clone()), &context);
context
.host
.lock()
.print_err(err, &Text::from(line.clone()));
maybe_print_errors(&context, Text::from(line));
if exit_on_error {
@ -267,6 +264,5 @@ pub async fn run_script_standalone(
_ => {}
}
Ok(())
}