From 69e7b984048bb0fb5d51c9cd788b198b960e7c78 Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 24 Sep 2022 11:13:57 +0200 Subject: [PATCH] Refactor script parsing and error handling --- src/error.rs | 14 ++++++--- src/main.rs | 6 ++-- src/scripting/executor.rs | 63 +++++++++++++++++++++++---------------- 3 files changed, 52 insertions(+), 31 deletions(-) diff --git a/src/error.rs b/src/error.rs index 8b855fc..ea84bed 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,23 +1,29 @@ use std::path::PathBuf; use miette::Diagnostic; +use nu_protocol::ShellError; use thiserror::Error; pub type AppResult = std::result::Result; #[derive(Error, Diagnostic, Debug)] pub enum AppError { + #[error("Miette error")] + #[diagnostic(code(tourmaline::error))] + Miette(miette::Error), + #[error("Error while evaluating nu script")] #[diagnostic()] - Nu(miette::Error), + Nu(#[from] ShellError), - #[error("Could not find the script file {0}")] + #[error("Could not find the script file")] ScriptNotFound(PathBuf), #[diagnostic()] - #[error("Could not parse the source file {0}")] + #[error("Could not parse the source file")] ParseError(#[from] nu_parser::ParseError), + #[diagnostic()] #[error("Could not find the main mehod in the script file {0}")] MissingMain(PathBuf), @@ -27,6 +33,6 @@ pub enum AppError { impl From for AppError { fn from(e: miette::Error) -> Self { - Self::Nu(e) + Self::Miette(e) } } diff --git a/src/main.rs b/src/main.rs index 57c2625..ee85e20 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,7 @@ use tourmaline::{ }; #[tokio::main(flavor = "current_thread")] -async fn main() { +async fn main() -> miette::Result<()> { color_eyre::install().unwrap(); dotenv::dotenv().unwrap(); let executor = TaskExecutor::new(); @@ -24,5 +24,7 @@ async fn main() { }, ], }; - executor.setup_users(user_cfg).await.unwrap(); + executor.setup_users(user_cfg).await?; + + Ok(()) } diff --git a/src/scripting/executor.rs b/src/scripting/executor.rs index 663f42c..eb97326 100644 --- a/src/scripting/executor.rs +++ b/src/scripting/executor.rs @@ -5,6 +5,7 @@ use std::{ path::{Path, PathBuf}, }; +use nu_cli::gather_parent_env_vars; use tokio::fs; use miette::IntoDiagnostic; @@ -72,6 +73,7 @@ impl NuExecutor { let mut engine_state = nu_command::create_default_context(); let mut stack = nu_protocol::engine::Stack::new(); let init_cwd = nu_cli::get_init_cwd(); + gather_parent_env_vars(&mut engine_state, &init_cwd); nu_engine::convert_env_values(&mut engine_state, &mut stack); let vars = mem::take(&mut self.global_vars); @@ -87,7 +89,7 @@ impl NuExecutor { &engine_state, &mut stack, &block, - PipelineData::new(Span::new(0, 0)), + empty_pipeline(), false, false, ) @@ -99,17 +101,20 @@ impl NuExecutor { tokio::task::spawn_blocking(move || { // TODO: Create the AST for the call here instead of parsing it from a string let args = format!("main {}", args.join(" ")); - if !nu_cli::eval_source( - &mut engine_state, + let (call_block, working_set) = parse_nu(&mut engine_state, args.as_bytes(), None)?; + let delta = working_set.render(); + engine_state.merge_delta(delta); + + nu_engine::eval_block( + &engine_state, &mut stack, - args.as_bytes(), - "", - PipelineData::new(Span::new(0, 0)), - ) { - Err(AppError::FailedToExecuteScript) - } else { - Ok(()) - } + &call_block, + empty_pipeline(), + false, + false, + )?; + + AppResult::Ok(()) }) .await .unwrap()?; @@ -145,31 +150,39 @@ fn add_variables_to_state( /// Reads the nu script file and /// returns its root block async fn read_script_file(path: &Path, engine_state: &mut EngineState) -> AppResult { - let mut working_set = StateWorkingSet::new(engine_state); - // TODO: Async let script_contents = fs::read(&path).await.into_diagnostic()?; let string_path = path.to_string_lossy().into_owned(); // parse the source file - let (block, err) = nu_parser::parse( - &mut working_set, - Some(&string_path), - &script_contents, - false, - &[], - ); - - if let Some(err) = err { - return Err(AppError::from(err)); - } + let (block, working_set) = parse_nu(engine_state, &script_contents, Some(&string_path))?; // check if a main method exists in the block if !working_set.find_decl(b"main", &Type::Block).is_some() { return Err(AppError::MissingMain(PathBuf::from(path))); } - engine_state.merge_delta(working_set.render()); + let delta = working_set.render(); + engine_state.merge_delta(delta); Ok(block) } +fn parse_nu<'a>( + engine_state: &'a mut EngineState, + script: &[u8], + script_path: Option<&str>, +) -> AppResult<(Block, StateWorkingSet<'a>)> { + let mut working_set = StateWorkingSet::new(engine_state); + let (block, err) = nu_parser::parse(&mut working_set, script_path, script, false, &[]); + + if let Some(err) = err { + Err(AppError::from(err)) + } else { + Ok((block, working_set)) + } +} + +fn empty_pipeline() -> PipelineData { + PipelineData::new(Span::new(0, 0)) +} + fn map_var_to_value(var: VarValue) -> Value { let span = Span::new(0, 0);