From d2ac506de3219fdc4825bb492f06e8cf5882887b Mon Sep 17 00:00:00 2001 From: Darren Schroeder Date: Mon, 4 May 2020 13:15:24 -0500 Subject: [PATCH] Changes to allow plugins to be loaded in a multi-threaded manner (#1694) * Changes to allow plugins to be loaded in a multi-threaded manner in order to decrease startup time. * Ran rust fmt and clippy to find and fix first pass errors. Updated launch.jason to make debugging easier in vscode. Also added tasks.json so tasks like clippy can be ran easily. * ran fmt again * Delete launch.json Remove IDE settings file * Remove IDE settings file * Ignore vscode IDE settings * Cloned the context instead of Arc/Mutexing it. Co-authored-by: Darren Schroeder Co-authored-by: Jonathan Turner --- .gitignore | 3 ++ Cargo.lock | 2 + crates/nu-cli/Cargo.toml | 1 + crates/nu-cli/src/cli.rs | 102 +++++++++++++++++++----------------- crates/nu-errors/Cargo.toml | 1 + crates/nu-errors/src/lib.rs | 6 +++ 6 files changed, 66 insertions(+), 49 deletions(-) diff --git a/.gitignore b/.gitignore index 1079f63b..4c234e52 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,6 @@ debian/nu/ # JetBrains' IDE items .idea/* + +# VSCode's IDE items +.vscode/* diff --git a/Cargo.lock b/Cargo.lock index bb97240b..e21eea5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2175,6 +2175,7 @@ dependencies = [ "quickcheck", "quickcheck_macros", "rand", + "rayon", "regex", "roxmltree", "rusqlite", @@ -2210,6 +2211,7 @@ dependencies = [ "bigdecimal", "derive-new", "getset", + "glob", "language-reporting", "nu-build", "nu-source", diff --git a/crates/nu-cli/Cargo.toml b/crates/nu-cli/Cargo.toml index 6368b7b8..ce33967d 100644 --- a/crates/nu-cli/Cargo.toml +++ b/crates/nu-cli/Cargo.toml @@ -89,6 +89,7 @@ which = "3" trash = { version = "1.0.0", optional = true } clipboard = { version = "0.5", optional = true } starship = { version = "0.39.0", optional = true } +rayon = "1.3.0" [target.'cfg(unix)'.dependencies] users = "0.10.0" diff --git a/crates/nu-cli/src/cli.rs b/crates/nu-cli/src/cli.rs index 5d3abb40..82c91128 100644 --- a/crates/nu-cli/src/cli.rs +++ b/crates/nu-cli/src/cli.rs @@ -26,6 +26,8 @@ use std::iter::Iterator; use std::path::{Path, PathBuf}; use std::sync::atomic::Ordering; +use rayon::prelude::*; + fn load_plugin(path: &std::path::Path, context: &mut Context) -> Result<(), ShellError> { let mut child = std::process::Command::new(path) .stdin(std::process::Stdio::piped()) @@ -132,58 +134,60 @@ pub fn load_plugins(context: &mut Context) -> Result<(), ShellError> { pattern.push(std::path::Path::new("nu_plugin_[a-z0-9][a-z0-9]*")); - match glob::glob_with(&pattern.to_string_lossy(), opts) { - Err(_) => {} - Ok(binaries) => { - for bin in binaries.filter_map(Result::ok) { - let bin_name = { - if let Some(name) = bin.file_name() { - match name.to_str() { - Some(raw) => raw, - None => continue, - } - } else { - continue; + let plugs: Vec<_> = glob::glob_with(&pattern.to_string_lossy(), opts)? + .filter_map(|x| x.ok()) + .collect(); + + let _failures: Vec<_> = plugs + .par_iter() + .map(|path| { + let bin_name = { + if let Some(name) = path.file_name() { + match name.to_str() { + Some(raw) => raw, + None => "", } - }; - - let is_valid_name = { - #[cfg(windows)] - { - bin_name - .chars() - .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '.') - } - - #[cfg(not(windows))] - { - bin_name - .chars() - .all(|c| c.is_ascii_alphanumeric() || c == '_') - } - }; - - let is_executable = { - #[cfg(windows)] - { - bin_name.ends_with(".exe") || bin_name.ends_with(".bat") - } - - #[cfg(not(windows))] - { - true - } - }; - - if is_valid_name && is_executable { - trace!("Trying {:?}", bin.display()); - - // we are ok if this plugin load fails - let _ = load_plugin(&bin, context); + } else { + "" } + }; + + let is_valid_name = { + #[cfg(windows)] + { + bin_name + .chars() + .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '.') + } + + #[cfg(not(windows))] + { + bin_name + .chars() + .all(|c| c.is_ascii_alphanumeric() || c == '_') + } + }; + + let is_executable = { + #[cfg(windows)] + { + bin_name.ends_with(".exe") || bin_name.ends_with(".bat") + } + + #[cfg(not(windows))] + { + true + } + }; + + if is_valid_name && is_executable { + trace!("Trying {:?}", path.display()); + + // we are ok if this plugin load fails + let _ = load_plugin(&path, &mut context.clone()); } - } - } + }) + .collect(); } Ok(()) diff --git a/crates/nu-errors/Cargo.toml b/crates/nu-errors/Cargo.toml index 77dfcffa..8dbc74b8 100644 --- a/crates/nu-errors/Cargo.toml +++ b/crates/nu-errors/Cargo.toml @@ -25,6 +25,7 @@ getset = "0.1.0" serde_yaml = "0.8" toml = "0.5.6" serde_json = "1.0.51" +glob = "0.3.0" [build-dependencies] nu-build = { version = "0.13.0", path = "../nu-build" } diff --git a/crates/nu-errors/src/lib.rs b/crates/nu-errors/src/lib.rs index 36cd7bc9..031c93c2 100644 --- a/crates/nu-errors/src/lib.rs +++ b/crates/nu-errors/src/lib.rs @@ -864,6 +864,12 @@ impl std::convert::From> for ShellError } } +impl std::convert::From for ShellError { + fn from(input: glob::PatternError) -> ShellError { + ShellError::untagged_runtime_error(format!("{:?}", input)) + } +} + pub trait CoerceInto { fn coerce_into(self, operation: impl Into) -> Result; }