diff --git a/Cargo.lock b/Cargo.lock index 08fcb94a0b..07ddf93483 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1542,7 +1542,6 @@ dependencies = [ "prettytable-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "ptree 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rawkey 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "roxmltree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rusqlite 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustyline 5.0.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index f9e13c9348..b5256b8404 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,7 +59,6 @@ unicode-xid = "0.2.0" serde_ini = "0.2.0" subprocess = "0.1.18" mime = "0.3.13" -regex = "1.2.1" pretty-hex = "0.1.0" hex = "0.3.2" tempfile = "3.1.0" diff --git a/src/cli.rs b/src/cli.rs index ec8c7085c6..c3b3eaeb5a 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -15,7 +15,6 @@ use crate::parser::{hir, CallNode, Pipeline, PipelineElement, TokenNode}; use crate::prelude::*; use log::{debug, trace}; -use regex::Regex; use rustyline::error::ReadlineError; use rustyline::{self, config::Configurer, config::EditMode, ColorMode, Config, Editor}; use std::env; @@ -98,38 +97,12 @@ fn load_plugin(path: &std::path::Path, context: &mut Context) -> Result<(), Shel result } -fn load_plugins_in_dir(path: &std::path::PathBuf, context: &mut Context) -> Result<(), ShellError> { - let re_bin = Regex::new(r"^nu_plugin_[A-Za-z_]+$")?; - let re_exe = Regex::new(r"^nu_plugin_[A-Za-z_]+\.(exe|bat)$")?; +fn search_paths() -> Vec { + let mut search_paths = Vec::new(); - trace!("Looking for plugins in {:?}", path); - - match std::fs::read_dir(path) { - Ok(p) => { - for entry in p { - let entry = entry?; - let filename = entry.file_name(); - let f_name = filename.to_string_lossy(); - - if re_bin.is_match(&f_name) || re_exe.is_match(&f_name) { - let mut load_path = path.clone(); - trace!("Found {:?}", f_name); - load_path.push(f_name.to_string()); - load_plugin(&load_path, context)?; - } - } - } - _ => {} - } - Ok(()) -} - -fn load_plugins(context: &mut Context) -> Result<(), ShellError> { match env::var_os("PATH") { Some(paths) => { - for path in env::split_paths(&paths) { - let _ = load_plugins_in_dir(&path, context); - } + search_paths = env::split_paths(&paths).collect::>(); } None => println!("PATH is not defined in the environment."), } @@ -140,7 +113,7 @@ fn load_plugins(context: &mut Context) -> Result<(), ShellError> { let mut path = std::path::PathBuf::from("."); path.push("target"); path.push("debug"); - let _ = load_plugins_in_dir(&path, context); + search_paths.push(path); } #[cfg(not(debug_assertions))] @@ -149,8 +122,78 @@ fn load_plugins(context: &mut Context) -> Result<(), ShellError> { let mut path = std::path::PathBuf::from("."); path.push("target"); path.push("release"); + search_paths.push(path); + } - let _ = load_plugins_in_dir(&path, context); + search_paths +} + +fn load_plugins(context: &mut Context) -> Result<(), ShellError> { + let opts = glob::MatchOptions { + case_sensitive: false, + require_literal_separator: false, + require_literal_leading_dot: false, + }; + + for path in search_paths() { + let mut pattern = path.to_path_buf(); + + pattern.push(std::path::Path::new("nu_plugin_[a-z]*")); + + match glob::glob_with(&pattern.to_string_lossy(), opts) { + Err(_) => {} + Ok(binaries) => { + for bin in binaries.filter_map(Result::ok) { + if !bin.is_file() { + continue; + } + + let bin_name = { + if let Some(name) = bin.file_name() { + match name.to_str() { + Some(raw) => raw, + None => continue, + } + } else { + continue; + } + }; + + let is_valid_name = { + #[cfg(windows)] + { + bin_name + .chars() + .all(|c| c.is_ascii_alphabetic() || c == '_' || c == '.') + } + + #[cfg(not(windows))] + { + bin_name + .chars() + .all(|c| c.is_ascii_alphabetic() || 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()); + load_plugin(&bin, context)?; + } + } + } + } } Ok(()) diff --git a/src/errors.rs b/src/errors.rs index d97435d226..579576e710 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -555,16 +555,6 @@ impl std::convert::From for ShellError { } } -impl std::convert::From for ShellError { - fn from(input: regex::Error) -> ShellError { - ProximateShellError::String(StringError { - title: format!("{:?}", input), - error: Value::nothing(), - }) - .start() - } -} - impl std::convert::From> for ShellError { fn from(input: Box) -> ShellError { ProximateShellError::String(StringError { diff --git a/src/plugins/str.rs b/src/plugins/str.rs index 99700449b4..60b0146ef5 100644 --- a/src/plugins/str.rs +++ b/src/plugins/str.rs @@ -2,20 +2,12 @@ use nu::{ serve_plugin, CallInfo, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, Signature, SyntaxType, Tagged, Value, }; -use regex::Regex; #[derive(Debug, Eq, PartialEq)] enum Action { Downcase, Upcase, ToInteger, - Replace(ReplaceAction), -} - -#[derive(Debug, Eq, PartialEq)] -enum ReplaceAction { - Direct, - FindAndReplace, } struct Str { @@ -45,41 +37,12 @@ impl Str { Err(_) => Value::string(input), }, }, - Some(Action::Replace(ref mode)) => match mode { - ReplaceAction::Direct => Value::string(self.first_param()), - ReplaceAction::FindAndReplace => { - let regex = Regex::new(self.first_param()); - - match regex { - Ok(re) => Value::string(re.replace(input, self.second_param()).to_owned()), - Err(_) => Value::string(input), - } - } - }, None => Value::string(input), }; Ok(applied) } - fn did_supply_field(&self) -> bool { - self.field.is_some() - } - - fn first_param(&self) -> &str { - let idx = if self.did_supply_field() { 1 } else { 0 }; - self.get_param(idx) - } - - fn second_param(&self) -> &str { - let idx = if self.did_supply_field() { 2 } else { 1 }; - self.get_param(idx) - } - - fn get_param(&self, idx: usize) -> &str { - self.params.as_ref().unwrap().get(idx).unwrap().as_str() - } - fn for_field(&mut self, field: &str) { self.field = Some(String::from(field)); } @@ -92,14 +55,6 @@ impl Str { self.error = Some(message.to_string()); } - fn for_replace(&mut self, mode: ReplaceAction) { - if self.permit() { - self.action = Some(Action::Replace(mode)); - } else { - self.log_error("can only apply one"); - } - } - fn for_to_int(&mut self) { if self.permit() { self.action = Some(Action::ToInteger); @@ -125,7 +80,7 @@ impl Str { } pub fn usage() -> &'static str { - "Usage: str field [--downcase|--upcase|--to-int|--replace|--find-replace]" + "Usage: str field [--downcase|--upcase|--to-int]" } } @@ -172,8 +127,6 @@ impl Plugin for Str { .switch("downcase") .switch("upcase") .switch("to-int") - .switch("replace") - .switch("find-replace") .rest(SyntaxType::Member) .filter()) } @@ -190,12 +143,6 @@ impl Plugin for Str { if args.has("to-int") { self.for_to_int(); } - if args.has("replace") { - self.for_replace(ReplaceAction::Direct); - } - if args.has("find-replace") { - self.for_replace(ReplaceAction::FindAndReplace); - } if let Some(possible_field) = args.nth(0) { match possible_field { @@ -203,16 +150,6 @@ impl Plugin for Str { item: Value::Primitive(Primitive::String(s)), .. } => match self.action { - Some(Action::Replace(ReplaceAction::Direct)) => { - if args.len() == 2 { - self.for_field(&s); - } - } - Some(Action::Replace(ReplaceAction::FindAndReplace)) => { - if args.len() == 3 { - self.for_field(&s); - } - } Some(Action::Downcase) | Some(Action::Upcase) | Some(Action::ToInteger) @@ -258,7 +195,7 @@ fn main() { #[cfg(test)] mod tests { - use super::{Action, ReplaceAction, Str}; + use super::{Action, Str}; use indexmap::IndexMap; use nu::{ CallInfo, EvaluatedArgs, Plugin, Primitive, ReturnSuccess, SourceMap, Span, Tag, Tagged, @@ -266,16 +203,6 @@ mod tests { }; use num_bigint::BigInt; - impl Str { - fn replace_with(&mut self, value: &str) { - self.params.as_mut().unwrap().push(value.to_string()); - } - - fn find_with(&mut self, search: &str) { - self.params.as_mut().unwrap().push(search.to_string()); - } - } - struct CallStub { positionals: Vec>, flags: IndexMap>, @@ -328,7 +255,7 @@ mod tests { let configured = plugin.config().unwrap(); - for action_flag in &["downcase", "upcase", "to-int", "replace", "find-replace"] { + for action_flag in &["downcase", "upcase", "to-int"] { assert!(configured.named.get(*action_flag).is_some()); } } @@ -362,33 +289,6 @@ mod tests { .is_ok()); assert_eq!(plugin.action.unwrap(), Action::ToInteger); } - - #[test] - fn str_plugin_accepts_replace() { - let mut plugin = Str::new(); - - assert!(plugin - .begin_filter(CallStub::new().with_long_flag("replace").create()) - .is_ok()); - assert_eq!( - plugin.action.unwrap(), - Action::Replace(ReplaceAction::Direct) - ); - } - - #[test] - fn str_plugin_accepts_find_replace() { - let mut plugin = Str::new(); - - assert!(plugin - .begin_filter(CallStub::new().with_long_flag("find-replace").create()) - .is_ok()); - assert_eq!( - plugin.action.unwrap(), - Action::Replace(ReplaceAction::FindAndReplace) - ); - } - #[test] fn str_plugin_accepts_field() { let mut plugin = Str::new(); @@ -441,26 +341,6 @@ mod tests { assert_eq!(strutils.apply("9999").unwrap(), Value::int(9999 as i64)); } - #[test] - fn str_replace() { - let mut strutils = Str::new(); - strutils.for_replace(ReplaceAction::Direct); - strutils.replace_with("robalino"); - assert_eq!(strutils.apply("andres").unwrap(), Value::string("robalino")); - } - - #[test] - fn str_find_replace() { - let mut strutils = Str::new(); - strutils.for_replace(ReplaceAction::FindAndReplace); - strutils.find_with(r"kittens"); - strutils.replace_with("jotandrehuda"); - assert_eq!( - strutils.apply("wykittens").unwrap(), - Value::string("wyjotandrehuda") - ); - } - #[test] fn str_plugin_applies_upcase_with_field() { let mut plugin = Str::new(); @@ -604,114 +484,4 @@ mod tests { _ => {} } } - - #[test] - fn str_plugin_applies_replace_with_field() { - let mut plugin = Str::new(); - - assert!(plugin - .begin_filter( - CallStub::new() - .with_parameter("rustconf") - .with_parameter("22nd August 2019") - .with_long_flag("replace") - .create() - ) - .is_ok()); - - let subject = structured_sample_record("rustconf", "1st January 1970"); - let output = plugin.filter(subject).unwrap(); - - match output[0].as_ref().unwrap() { - ReturnSuccess::Value(Tagged { - item: Value::Row(o), - .. - }) => assert_eq!( - *o.get_data(&String::from("rustconf")).borrow(), - Value::string(String::from("22nd August 2019")) - ), - _ => {} - } - } - - #[test] - fn str_plugin_applies_replace_without_field() { - let mut plugin = Str::new(); - - assert!(plugin - .begin_filter( - CallStub::new() - .with_parameter("22nd August 2019") - .with_long_flag("replace") - .create() - ) - .is_ok()); - - let subject = unstructured_sample_record("1st January 1970"); - let output = plugin.filter(subject).unwrap(); - - match output[0].as_ref().unwrap() { - ReturnSuccess::Value(Tagged { - item: Value::Primitive(Primitive::String(s)), - .. - }) => assert_eq!(*s, String::from("22nd August 2019")), - _ => {} - } - } - - #[test] - fn str_plugin_applies_find_replace_with_field() { - let mut plugin = Str::new(); - - assert!(plugin - .begin_filter( - CallStub::new() - .with_parameter("staff") - .with_parameter("kittens") - .with_parameter("jotandrehuda") - .with_long_flag("find-replace") - .create() - ) - .is_ok()); - - let subject = structured_sample_record("staff", "wykittens"); - let output = plugin.filter(subject).unwrap(); - - match output[0].as_ref().unwrap() { - ReturnSuccess::Value(Tagged { - item: Value::Row(o), - .. - }) => assert_eq!( - *o.get_data(&String::from("staff")).borrow(), - Value::string(String::from("wyjotandrehuda")) - ), - _ => {} - } - } - - #[test] - fn str_plugin_applies_find_replace_without_field() { - let mut plugin = Str::new(); - - assert!(plugin - .begin_filter( - CallStub::new() - .with_parameter("kittens") - .with_parameter("jotandrehuda") - .with_long_flag("find-replace") - .create() - ) - .is_ok()); - - let subject = unstructured_sample_record("wykittens"); - let output = plugin.filter(subject).unwrap(); - - match output[0].as_ref().unwrap() { - ReturnSuccess::Value(Tagged { - item: Value::Primitive(Primitive::String(s)), - .. - }) => assert_eq!(*s, String::from("wyjotandrehuda")), - _ => {} - } - } } diff --git a/tests/filter_str_tests.rs b/tests/filter_str_tests.rs index e26a18850e..9f92186fa6 100644 --- a/tests/filter_str_tests.rs +++ b/tests/filter_str_tests.rs @@ -10,9 +10,7 @@ fn can_only_apply_one() { "open caco3_plastics.csv | first 1 | str origin --downcase --upcase" ); - assert!( - actual.contains("Usage: str field [--downcase|--upcase|--to-int|--replace|--find-replace]") - ); + assert!(actual.contains("Usage: str field [--downcase|--upcase|--to-int")); } #[test] @@ -92,78 +90,3 @@ fn converts_to_int() { assert_eq!(actual, "2509000000"); } - -#[test] -fn replaces() { - Playground::setup("plugin_str_test_4", |dirs, sandbox| { - sandbox.with_files(vec![FileWithContent( - "sample.toml", - r#" - [package] - name = "nushell" - "#, - )]); - - let actual = nu!( - cwd: dirs.test(), h::pipeline( - r#" - open sample.toml - | str package.name --replace wykittenshell - | get package.name - | echo $it - "# - )); - - assert_eq!(actual, "wykittenshell"); - }) -} - -#[test] -fn find_and_replaces() { - Playground::setup("plugin_str_test_5", |dirs, sandbox| { - sandbox.with_files(vec![FileWithContent( - "sample.toml", - r#" - [fortune.teller] - phone = "1-800-KATZ" - "#, - )]); - - let actual = nu!( - cwd: dirs.test(), h::pipeline( - r#" - open sample.toml - | str fortune.teller.phone --find-replace KATZ "5289" - | get fortune.teller.phone - | echo $it - "# - )); - - assert_eq!(actual, "1-800-5289"); - }) -} - -#[test] -fn find_and_replaces_without_passing_field() { - Playground::setup("plugin_str_test_6", |dirs, sandbox| { - sandbox.with_files(vec![FileWithContent( - "sample.toml", - r#" - [fortune.teller] - phone = "1-800-KATZ" - "#, - )]); - - let actual = nu!( - cwd: dirs.test(), h::pipeline( - r#" - open sample.toml - | get fortune.teller.phone - | str --find-replace KATZ "5289" - | echo $it - "# - )); - - assert_eq!(actual, "1-800-5289"); - }) -}