mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 14:36:08 +02:00
account for startup commands in the scope. (#3261)
* Revert "Impl one configurable function to run scripts (#3242)" * pass config startup.
This commit is contained in:
committed by
GitHub
parent
4c09716ad8
commit
00acf22f5f
@ -1,16 +1,14 @@
|
||||
use crate::EvaluationContext;
|
||||
use crate::Scope;
|
||||
use crate::{basic_shell_manager, config_holder::ConfigHolder};
|
||||
use crate::{env::basic_host::BasicHost, Host};
|
||||
use crate::{filesystem::filesystem_shell::FilesystemShellMode, EvaluationContext};
|
||||
use indexmap::IndexMap;
|
||||
use parking_lot::Mutex;
|
||||
use std::error::Error;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn basic_evaluation_context(
|
||||
mode: FilesystemShellMode,
|
||||
) -> Result<EvaluationContext, Box<dyn Error>> {
|
||||
pub fn basic_evaluation_context() -> Result<EvaluationContext, Box<dyn Error>> {
|
||||
let scope = Scope::new();
|
||||
let mut host = BasicHost {};
|
||||
let env_vars = host.vars().iter().cloned().collect::<IndexMap<_, _>>();
|
||||
@ -22,7 +20,7 @@ pub fn basic_evaluation_context(
|
||||
current_errors: Arc::new(Mutex::new(vec![])),
|
||||
ctrl_c: Arc::new(AtomicBool::new(false)),
|
||||
configs: Arc::new(Mutex::new(ConfigHolder::new())),
|
||||
shell_manager: basic_shell_manager::basic_shell_manager(mode)?,
|
||||
shell_manager: basic_shell_manager::basic_shell_manager()?,
|
||||
windows_drives_previous_cwd: Arc::new(Mutex::new(std::collections::HashMap::new())),
|
||||
})
|
||||
}
|
||||
|
@ -6,9 +6,11 @@ use std::error::Error;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn basic_shell_manager(mode: FilesystemShellMode) -> Result<ShellManager, Box<dyn Error>> {
|
||||
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(mode)?)])),
|
||||
shells: Arc::new(Mutex::new(vec![Box::new(FilesystemShell::basic(
|
||||
FilesystemShellMode::Cli,
|
||||
)?)])),
|
||||
})
|
||||
}
|
||||
|
@ -7,12 +7,12 @@ use crate::{command_args::CommandArgs, script};
|
||||
use log::trace;
|
||||
use nu_data::config::{self, Conf, NuConfig};
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{hir, ConfigPath, NuScript, RunScriptOptions};
|
||||
use nu_protocol::{hir, ConfigPath};
|
||||
use nu_source::{Span, Tag};
|
||||
use nu_stream::{InputStream, OutputStream};
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::{path::Path, sync::Arc};
|
||||
use std::{path::PathBuf, sync::atomic::AtomicBool};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct EvaluationContext {
|
||||
@ -177,9 +177,9 @@ impl EvaluationContext {
|
||||
}
|
||||
}
|
||||
|
||||
let options = exit_entry_script_options(&cfg_path);
|
||||
for script in startup_scripts {
|
||||
script::run_script(NuScript::Content(script), &options, self).await;
|
||||
if !startup_scripts.is_empty() {
|
||||
self.run_scripts(startup_scripts, cfg_path.get_path().parent())
|
||||
.await;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -270,27 +270,32 @@ impl EvaluationContext {
|
||||
|
||||
//Run exitscripts with scope frame and cfg still applied
|
||||
if let Some(scripts) = self.scope.get_exitscripts_of_frame_with_tag(&tag) {
|
||||
let options = exit_entry_script_options(&cfg_path);
|
||||
for script in scripts {
|
||||
script::run_script(NuScript::Content(script), &options, self).await;
|
||||
}
|
||||
self.run_scripts(scripts, cfg_path.get_path().parent())
|
||||
.await;
|
||||
}
|
||||
|
||||
//Unload config
|
||||
self.configs.lock().remove_cfg(&cfg_path);
|
||||
self.scope.exit_scope_with_tag(&tag);
|
||||
}
|
||||
}
|
||||
|
||||
fn exit_entry_script_options(cfg_path: &ConfigPath) -> RunScriptOptions {
|
||||
let root = PathBuf::from("/");
|
||||
RunScriptOptions::default()
|
||||
.with_cwd(
|
||||
cfg_path
|
||||
.get_path()
|
||||
.parent()
|
||||
.map(Path::to_path_buf)
|
||||
.unwrap_or(root),
|
||||
)
|
||||
.exit_on_error(false)
|
||||
/// Runs scripts with cwd of dir. If dir is None, this method does nothing.
|
||||
/// Each error is added to `self.current_errors`
|
||||
pub async fn run_scripts(&self, scripts: Vec<String>, dir: Option<&Path>) {
|
||||
if let Some(dir) = dir {
|
||||
for script in scripts {
|
||||
match script::run_script_in_dir(script.clone(), dir, &self).await {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
let err = ShellError::untagged_runtime_error(format!(
|
||||
"Err while executing exitscript. Err was\n{:?}",
|
||||
e
|
||||
));
|
||||
let text = script.into();
|
||||
self.host.lock().print_err(err, &text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ use futures::stream::BoxStream;
|
||||
use futures::StreamExt;
|
||||
use futures_codec::FramedRead;
|
||||
use futures_util::TryStreamExt;
|
||||
use log::trace;
|
||||
use nu_data::config::LocalConfigDiff;
|
||||
use nu_protocol::{CommandAction, ConfigPath, TaggedDictBuilder, Value};
|
||||
use nu_source::{Span, Tag};
|
||||
@ -302,11 +301,6 @@ impl Shell for FilesystemShell {
|
||||
if self.is_cli() {
|
||||
match dunce::canonicalize(self.path()) {
|
||||
Err(e) => {
|
||||
trace!(
|
||||
"Err canonicalize current path: {:?}, err: {:?}",
|
||||
self.path(),
|
||||
e
|
||||
);
|
||||
let err = ShellError::untagged_runtime_error(format!(
|
||||
"Could not get absolute path from current fs shell. The error was: {:?}",
|
||||
e
|
||||
|
@ -3,22 +3,19 @@ use crate::{MaybeTextCodec, StringOrBinary};
|
||||
use futures::StreamExt;
|
||||
use futures_codec::FramedRead;
|
||||
use nu_errors::ShellError;
|
||||
use nu_parser::ParserScope;
|
||||
use nu_protocol::{
|
||||
hir::{
|
||||
Call, ClassifiedCommand, Expression, InternalCommand, Literal, NamedArguments,
|
||||
SpannedExpression,
|
||||
},
|
||||
NuScript, ReturnSuccess, RunScriptOptions,
|
||||
use nu_protocol::hir::{
|
||||
Call, ClassifiedCommand, Expression, InternalCommand, Literal, NamedArguments,
|
||||
SpannedExpression,
|
||||
};
|
||||
use nu_protocol::{Primitive, UntaggedValue, Value};
|
||||
use nu_protocol::{Primitive, ReturnSuccess, UntaggedValue, Value};
|
||||
use nu_stream::{InputStream, ToInputStream};
|
||||
|
||||
use crate::EvaluationContext;
|
||||
use log::{debug, trace};
|
||||
use nu_source::{Span, Tag, Text};
|
||||
use std::iter::Iterator;
|
||||
use std::path::Path;
|
||||
use std::{iter::Iterator, sync::atomic::Ordering};
|
||||
use std::{error::Error, sync::atomic::Ordering};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum LineResult {
|
||||
@ -30,7 +27,6 @@ pub enum LineResult {
|
||||
ClearHistory,
|
||||
}
|
||||
|
||||
//TODO is this still needed
|
||||
fn chomp_newline(s: &str) -> &str {
|
||||
if let Some(s) = s.strip_suffix('\n') {
|
||||
s
|
||||
@ -39,106 +35,36 @@ fn chomp_newline(s: &str) -> &str {
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs script `script` configurable by `options`
|
||||
/// All errors are printed out.
|
||||
pub async fn run_script(script: NuScript, options: &RunScriptOptions, ctx: &EvaluationContext) {
|
||||
let code = match script.get_code() {
|
||||
Ok(code) => code,
|
||||
Err(e) => {
|
||||
ctx.host.lock().print_err(e, &Text::from("".to_string()));
|
||||
return;
|
||||
}
|
||||
};
|
||||
pub async fn run_script_in_dir(
|
||||
script: String,
|
||||
dir: &Path,
|
||||
ctx: &EvaluationContext,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
//Save path before to switch back to it after executing script
|
||||
let path_before = ctx.shell_manager.path();
|
||||
|
||||
if let Err(e) = setup_shell(options, ctx) {
|
||||
ctx.host.lock().print_err(e, &Text::from("".to_string()));
|
||||
return;
|
||||
}
|
||||
|
||||
if !options.use_existing_scope {
|
||||
ctx.scope.enter_scope()
|
||||
}
|
||||
|
||||
let line_result = process_script(&code, options, ctx).await;
|
||||
evaluate_line_result(line_result, options, ctx).await;
|
||||
|
||||
if !options.use_existing_scope {
|
||||
ctx.scope.exit_scope()
|
||||
}
|
||||
|
||||
//Leave script shell
|
||||
ctx.shell_manager.remove_at_current();
|
||||
}
|
||||
|
||||
fn setup_shell(options: &RunScriptOptions, ctx: &EvaluationContext) -> Result<(), ShellError> {
|
||||
//Switch to correct shell
|
||||
if options.cli_mode {
|
||||
ctx.shell_manager.enter_cli_mode()?;
|
||||
} else {
|
||||
ctx.shell_manager.enter_script_mode()?;
|
||||
}
|
||||
|
||||
//Switch to cwd if given
|
||||
if let Some(path) = &options.with_cwd {
|
||||
ctx.shell_manager
|
||||
.set_path(path.to_string_lossy().to_string());
|
||||
}
|
||||
ctx.shell_manager
|
||||
.set_path(dir.to_string_lossy().to_string());
|
||||
run_script_standalone(script, false, ctx, false).await?;
|
||||
ctx.shell_manager.set_path(path_before);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn evaluate_line_result(
|
||||
line_result: LineResult,
|
||||
options: &RunScriptOptions,
|
||||
context: &EvaluationContext,
|
||||
) {
|
||||
match line_result {
|
||||
LineResult::Success(line) => {
|
||||
let error_code = {
|
||||
let errors = context.current_errors.clone();
|
||||
let errors = errors.lock();
|
||||
|
||||
if errors.len() > 0 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
};
|
||||
|
||||
maybe_print_errors(&context, Text::from(line));
|
||||
if error_code != 0 && options.exit_on_error {
|
||||
std::process::exit(error_code);
|
||||
}
|
||||
}
|
||||
|
||||
LineResult::Error(line, err) => {
|
||||
context
|
||||
.host
|
||||
.lock()
|
||||
.print_err(err, &Text::from(line.clone()));
|
||||
|
||||
maybe_print_errors(&context, Text::from(line));
|
||||
if options.exit_on_error {
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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,
|
||||
options: &RunScriptOptions,
|
||||
ctx: &EvaluationContext,
|
||||
redirect_stdin: bool,
|
||||
span_offset: usize,
|
||||
cli_mode: bool,
|
||||
) -> LineResult {
|
||||
if script_text.trim() == "" {
|
||||
LineResult::Success(script_text.to_string())
|
||||
} else {
|
||||
let line = chomp_newline(script_text);
|
||||
|
||||
let (block, err) = nu_parser::parse(&line, options.span_offset, &ctx.scope);
|
||||
let (block, err) = nu_parser::parse(&line, span_offset, &ctx.scope);
|
||||
|
||||
debug!("{:#?}", block);
|
||||
//println!("{:#?}", pipeline);
|
||||
@ -153,7 +79,7 @@ pub async fn process_script(
|
||||
// ...and it doesn't have any arguments
|
||||
// ...and we're in the CLI
|
||||
// ...then change to this directory
|
||||
if options.cli_mode
|
||||
if cli_mode
|
||||
&& block.block.len() == 1
|
||||
&& block.block[0].pipelines.len() == 1
|
||||
&& block.block[0].pipelines[0].list.len() == 1
|
||||
@ -234,7 +160,7 @@ pub async fn process_script(
|
||||
}
|
||||
}
|
||||
|
||||
let input_stream = if options.redirect_stdin {
|
||||
let input_stream = if redirect_stdin {
|
||||
let file = futures::io::AllowStdIo::new(std::io::stdin());
|
||||
let stream = FramedRead::new(file, MaybeTextCodec::default()).map(|line| {
|
||||
if let Ok(line) = line {
|
||||
@ -309,3 +235,55 @@ pub async fn process_script(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn run_script_standalone(
|
||||
script_text: String,
|
||||
redirect_stdin: bool,
|
||||
context: &EvaluationContext,
|
||||
exit_on_error: bool,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
context
|
||||
.shell_manager
|
||||
.enter_script_mode()
|
||||
.map_err(Box::new)?;
|
||||
let line = process_script(&script_text, context, redirect_stdin, 0, false).await;
|
||||
|
||||
match line {
|
||||
LineResult::Success(line) => {
|
||||
let error_code = {
|
||||
let errors = context.current_errors.clone();
|
||||
let errors = errors.lock();
|
||||
|
||||
if errors.len() > 0 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
};
|
||||
|
||||
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()));
|
||||
|
||||
maybe_print_errors(&context, Text::from(line));
|
||||
if exit_on_error {
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
||||
//exit script mode shell
|
||||
context.shell_manager.remove_at_current();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -27,13 +27,6 @@ impl ShellManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn enter_cli_mode(&self) -> Result<(), std::io::Error> {
|
||||
//New fs_shell starting from current path
|
||||
let fs_shell = FilesystemShell::with_location(self.path(), FilesystemShellMode::Cli)?;
|
||||
self.insert_at_current(Box::new(fs_shell));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn insert_at_current(&self, shell: Box<dyn Shell + Send>) {
|
||||
self.shells.lock().push(shell);
|
||||
self.current_shell
|
||||
|
Reference in New Issue
Block a user