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 1079f63b23..4c234e523b 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 bb97240b86..e21eea5ce1 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 6368b7b815..ce33967d65 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 5d3abb40df..82c9112882 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 77dfcffa59..8dbc74b8bc 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 36cd7bc932..031c93c252 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; }