History, more test coverage improvements, and refactorings. (#3217)

Improvements overall to Nu. Also among the changes here, we can also be more confident towards incorporating `3041`. End to end tests for checking envs properly exported to externals is not added here (since it's in the other PR)

A few things added in this PR (probably forgetting some too)

* no writes happen to history during test runs.
* environment syncing end to end coverage added.
* clean up / refactorings few areas.
* testing API for finer control (can write tests passing more than one pipeline)
* can pass environment variables in tests that nu will inherit when running.

* No longer needed.

* no longer under a module. No need to use super.
This commit is contained in:
Andrés N. Robalino
2021-03-27 00:08:03 -05:00
committed by GitHub
parent b243b3ee1d
commit 8fc8fc89aa
31 changed files with 483 additions and 241 deletions

View File

@ -1,20 +0,0 @@
use crate::basic_shell_manager;
use crate::env::basic_host::BasicHost;
use crate::EvaluationContext;
use crate::Scope;
use parking_lot::Mutex;
use std::error::Error;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
pub fn basic_evaluation_context() -> Result<EvaluationContext, Box<dyn Error>> {
Ok(EvaluationContext {
scope: Scope::new(),
host: Arc::new(parking_lot::Mutex::new(Box::new(BasicHost))),
current_errors: Arc::new(Mutex::new(vec![])),
ctrl_c: Arc::new(AtomicBool::new(false)),
user_recently_used_autoenv_untrust: Arc::new(AtomicBool::new(false)),
shell_manager: basic_shell_manager::basic_shell_manager()?,
windows_drives_previous_cwd: Arc::new(Mutex::new(std::collections::HashMap::new())),
})
}

View File

@ -1,14 +0,0 @@
use crate::filesystem::filesystem_shell::FilesystemShell;
use crate::shell::shell_manager::ShellManager;
use parking_lot::Mutex;
use std::error::Error;
use std::sync::atomic::AtomicUsize;
use std::sync::Arc;
pub fn basic_shell_manager() -> Result<ShellManager, Box<dyn Error>> {
Ok(ShellManager {
current_shell: Arc::new(AtomicUsize::new(0)),
shells: Arc::new(Mutex::new(vec![Box::new(FilesystemShell::basic()?)])),
})
}

View File

@ -7,6 +7,21 @@ use std::ffi::OsString;
#[derive(Debug)]
pub struct BasicHost;
pub fn print_err(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);
});
}
}
impl Host for BasicHost {
fn stdout(&mut self, out: &str) {
match out {
@ -23,18 +38,7 @@ 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);
});
}
print_err(err, source);
}
#[allow(unused_variables)]

View File

@ -1,13 +1,24 @@
use crate::evaluate::scope::Scope;
use crate::history_path::history_path;
use nu_data::config::NuConfig;
use nu_errors::ShellError;
use nu_protocol::{Primitive, TaggedDictBuilder, UntaggedValue, Value};
use nu_source::Tag;
pub fn nu(scope: &Scope, tag: impl Into<Tag>) -> Result<Value, ShellError> {
let env = &scope.get_env_vars();
let tag = tag.into();
let env = &scope.get_env_vars();
let config = if let Some(Value {
value: UntaggedValue::Primitive(Primitive::FilePath(path)),
..
}) = scope.get_var("config-path")
{
NuConfig::with(Some(path).map(|p| p.into_os_string()))
} else {
NuConfig::new()
};
let mut nu_dict = TaggedDictBuilder::new(&tag);
let mut dict = TaggedDictBuilder::new(&tag);
@ -18,16 +29,10 @@ pub fn nu(scope: &Scope, tag: impl Into<Tag>) -> Result<Value, ShellError> {
}
nu_dict.insert_value("env", dict.into_value());
let config_file = match scope.get_var("config-path") {
Some(Value {
value: UntaggedValue::Primitive(Primitive::FilePath(path)),
..
}) => Some(path),
_ => None,
};
let config = nu_data::config::read(&tag, &config_file)?;
nu_dict.insert_value("config", UntaggedValue::row(config).into_value(&tag));
nu_dict.insert_value(
"config",
UntaggedValue::row(config.vars.clone()).into_value(&tag),
);
let mut table = vec![];
for v in env.iter() {
@ -49,15 +54,9 @@ pub fn nu(scope: &Scope, tag: impl Into<Tag>) -> Result<Value, ShellError> {
let temp = std::env::temp_dir();
nu_dict.insert_value("temp-dir", UntaggedValue::filepath(temp).into_value(&tag));
let config = if let Some(path) = config_file {
path
} else {
nu_data::config::default_path()?
};
nu_dict.insert_value(
"config-path",
UntaggedValue::filepath(config).into_value(&tag),
UntaggedValue::filepath(nu_data::config::path::source_file(&config)).into_value(&tag),
);
#[cfg(feature = "rustyline-support")]
@ -69,11 +68,9 @@ pub fn nu(scope: &Scope, tag: impl Into<Tag>) -> Result<Value, ShellError> {
);
}
let config: Box<dyn nu_data::config::Conf> = Box::new(nu_data::config::NuConfig::new());
let history = history_path(&config);
nu_dict.insert_value(
"history-path",
UntaggedValue::filepath(history).into_value(&tag),
UntaggedValue::filepath(nu_data::config::path::history(&config)).into_value(&tag),
);
Ok(nu_dict.into_value())

View File

@ -1,13 +1,13 @@
use crate::call_info::UnevaluatedCallInfo;
use crate::command_args::CommandArgs;
use crate::env::host::Host;
use crate::env::{basic_host::BasicHost, host::Host};
use crate::evaluate::scope::Scope;
use crate::shell::shell_manager::ShellManager;
use crate::whole_stream_command::Command;
use indexmap::IndexMap;
use nu_errors::ShellError;
use nu_protocol::hir;
use nu_source::Tag;
use nu_source::{Tag, Text};
use nu_stream::{InputStream, OutputStream};
use parking_lot::Mutex;
use std::sync::atomic::AtomicBool;
@ -27,6 +27,18 @@ pub struct EvaluationContext {
}
impl EvaluationContext {
pub fn basic() -> Result<EvaluationContext, ShellError> {
Ok(EvaluationContext {
scope: Scope::new(),
host: Arc::new(parking_lot::Mutex::new(Box::new(BasicHost))),
current_errors: Arc::new(Mutex::new(vec![])),
ctrl_c: Arc::new(AtomicBool::new(false)),
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())),
})
}
pub fn from_args(args: &CommandArgs) -> EvaluationContext {
EvaluationContext {
scope: args.scope.clone(),
@ -121,3 +133,18 @@ impl EvaluationContext {
output
}
}
pub fn maybe_print_errors(context: &EvaluationContext, source: Text) -> bool {
let errors = context.current_errors.clone();
let mut errors = errors.lock();
if errors.len() > 0 {
let error = errors[0].clone();
*errors = vec![];
context.host.lock().print_err(error, &source);
true
} else {
false
}
}

View File

@ -1,22 +0,0 @@
use nu_data::config::Conf;
use std::path::PathBuf;
const DEFAULT_LOCATION: &str = "history.txt";
pub fn history_path(config: &dyn Conf) -> PathBuf {
let default_path = nu_data::config::user_data()
.map(|mut p| {
p.push(DEFAULT_LOCATION);
p
})
.unwrap_or_else(|_| PathBuf::from(DEFAULT_LOCATION));
config
.var("history-path")
.map_or(default_path.clone(), |custom_path| {
match custom_path.as_string() {
Ok(path) => PathBuf::from(path),
Err(_) => default_path,
}
})
}

View File

@ -1,25 +1,19 @@
pub mod basic_evaluation_context;
pub mod basic_shell_manager;
mod call_info;
mod command_args;
pub mod deserializer;
pub mod documentation;
mod env;
mod evaluate;
mod evaluation_context;
pub mod evaluation_context;
mod example;
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;
pub use crate::basic_evaluation_context::basic_evaluation_context;
pub use crate::basic_shell_manager::basic_shell_manager;
pub use crate::call_info::UnevaluatedCallInfo;
pub use crate::command_args::{
CommandArgs, EvaluatedCommandArgs, EvaluatedWholeStreamCommandArgs, RawCommandArgs,
@ -36,7 +30,6 @@ pub use crate::example::Example;
pub use crate::filesystem::dir_info::{DirBuilder, DirInfo, FileInfo};
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};

View File

@ -1,18 +0,0 @@
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();
if errors.len() > 0 {
let error = errors[0].clone();
*errors = vec![];
context.host.lock().print_err(error, &source);
true
} else {
false
}
}

View File

@ -1,5 +1,5 @@
use crate::path::canonicalize;
use crate::run_block;
use crate::{path::canonicalize, print::maybe_print_errors};
use crate::{MaybeTextCodec, StringOrBinary};
use futures::StreamExt;
use futures_codec::FramedRead;
@ -11,7 +11,7 @@ use nu_protocol::hir::{
use nu_protocol::{Primitive, ReturnSuccess, UntaggedValue, Value};
use nu_stream::{InputStream, ToInputStream};
use crate::EvaluationContext;
use crate::{evaluation_context, EvaluationContext};
use log::{debug, trace};
use nu_source::{Span, Tag, Text};
use std::iter::Iterator;
@ -244,19 +244,16 @@ pub async fn run_script_standalone(
}
};
maybe_print_errors(&context, Text::from(line));
evaluation_context::maybe_print_errors(&context, Text::from(line));
if error_code != 0 && exit_on_error {
std::process::exit(error_code);
}
}
LineResult::Error(line, err) => {
context
.host
.lock()
.print_err(err, &Text::from(line.clone()));
context.with_host(|host| host.print_err(err, &Text::from(line.clone())));
maybe_print_errors(&context, Text::from(line));
evaluation_context::maybe_print_errors(&context, Text::from(line));
if exit_on_error {
std::process::exit(1);
}

View File

@ -1,10 +1,12 @@
use crate::command_args::EvaluatedWholeStreamCommandArgs;
use crate::maybe_text_codec::StringOrBinary;
use crate::shell::Shell;
use futures::Stream;
use nu_stream::OutputStream;
use crate::filesystem::filesystem_shell::FilesystemShell;
use crate::shell::shell_args::{CdArgs, CopyArgs, LsArgs, MkdirArgs, MvArgs, RemoveArgs};
use crate::shell::Shell;
use encoding_rs::Encoding;
use nu_errors::ShellError;
use nu_source::{Span, Tag};
@ -20,6 +22,13 @@ pub struct ShellManager {
}
impl ShellManager {
pub fn basic() -> Result<Self, ShellError> {
Ok(ShellManager {
current_shell: Arc::new(AtomicUsize::new(0)),
shells: Arc::new(Mutex::new(vec![Box::new(FilesystemShell::basic()?)])),
})
}
pub fn insert_at_current(&self, shell: Box<dyn Shell + Send>) {
self.shells.lock().push(shell);
self.current_shell