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 <fdncred@hotmail.com>
Co-authored-by: Jonathan Turner <jonathandturner@users.noreply.github.com>
This commit is contained in:
Darren Schroeder 2020-05-04 13:15:24 -05:00 committed by GitHub
parent a9968046ed
commit d2ac506de3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 66 additions and 49 deletions

3
.gitignore vendored
View File

@ -17,3 +17,6 @@ debian/nu/
# JetBrains' IDE items # JetBrains' IDE items
.idea/* .idea/*
# VSCode's IDE items
.vscode/*

2
Cargo.lock generated
View File

@ -2175,6 +2175,7 @@ dependencies = [
"quickcheck", "quickcheck",
"quickcheck_macros", "quickcheck_macros",
"rand", "rand",
"rayon",
"regex", "regex",
"roxmltree", "roxmltree",
"rusqlite", "rusqlite",
@ -2210,6 +2211,7 @@ dependencies = [
"bigdecimal", "bigdecimal",
"derive-new", "derive-new",
"getset", "getset",
"glob",
"language-reporting", "language-reporting",
"nu-build", "nu-build",
"nu-source", "nu-source",

View File

@ -89,6 +89,7 @@ which = "3"
trash = { version = "1.0.0", optional = true } trash = { version = "1.0.0", optional = true }
clipboard = { version = "0.5", optional = true } clipboard = { version = "0.5", optional = true }
starship = { version = "0.39.0", optional = true } starship = { version = "0.39.0", optional = true }
rayon = "1.3.0"
[target.'cfg(unix)'.dependencies] [target.'cfg(unix)'.dependencies]
users = "0.10.0" users = "0.10.0"

View File

@ -26,6 +26,8 @@ use std::iter::Iterator;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use rayon::prelude::*;
fn load_plugin(path: &std::path::Path, context: &mut Context) -> Result<(), ShellError> { fn load_plugin(path: &std::path::Path, context: &mut Context) -> Result<(), ShellError> {
let mut child = std::process::Command::new(path) let mut child = std::process::Command::new(path)
.stdin(std::process::Stdio::piped()) .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]*")); pattern.push(std::path::Path::new("nu_plugin_[a-z0-9][a-z0-9]*"));
match glob::glob_with(&pattern.to_string_lossy(), opts) { let plugs: Vec<_> = glob::glob_with(&pattern.to_string_lossy(), opts)?
Err(_) => {} .filter_map(|x| x.ok())
Ok(binaries) => { .collect();
for bin in binaries.filter_map(Result::ok) {
let bin_name = { let _failures: Vec<_> = plugs
if let Some(name) = bin.file_name() { .par_iter()
match name.to_str() { .map(|path| {
Some(raw) => raw, let bin_name = {
None => continue, if let Some(name) = path.file_name() {
} match name.to_str() {
} else { Some(raw) => raw,
continue; None => "",
} }
}; } 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 {:?}", bin.display());
// we are ok if this plugin load fails
let _ = load_plugin(&bin, context);
} }
};
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(()) Ok(())

View File

@ -25,6 +25,7 @@ getset = "0.1.0"
serde_yaml = "0.8" serde_yaml = "0.8"
toml = "0.5.6" toml = "0.5.6"
serde_json = "1.0.51" serde_json = "1.0.51"
glob = "0.3.0"
[build-dependencies] [build-dependencies]
nu-build = { version = "0.13.0", path = "../nu-build" } nu-build = { version = "0.13.0", path = "../nu-build" }

View File

@ -864,6 +864,12 @@ impl std::convert::From<Box<dyn std::error::Error + Send + Sync>> for ShellError
} }
} }
impl std::convert::From<glob::PatternError> for ShellError {
fn from(input: glob::PatternError) -> ShellError {
ShellError::untagged_runtime_error(format!("{:?}", input))
}
}
pub trait CoerceInto<U> { pub trait CoerceInto<U> {
fn coerce_into(self, operation: impl Into<String>) -> Result<U, ShellError>; fn coerce_into(self, operation: impl Into<String>) -> Result<U, ShellError>;
} }