From cc35572b40c49cc3aa517ff11881a87ae9f97d13 Mon Sep 17 00:00:00 2001 From: George Kaplan Date: Thu, 17 Jan 2019 21:29:59 -0500 Subject: [PATCH 01/18] derive Copy trait for MatchOptions --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 9b795da..c82b011 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -945,7 +945,7 @@ fn chars_eq(a: char, b: char, case_sensitive: bool) -> bool { /// Configuration options to modify the behaviour of `Pattern::matches_with(..)`. #[allow(missing_copy_implementations)] -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] pub struct MatchOptions { /// Whether or not patterns should be matched in a case-sensitive manner. /// This currently only considers upper/lower case relationships between From 1a25d8e7653b8c59742f4c69860024ef139bd7a3 Mon Sep 17 00:00:00 2001 From: George Kaplan Date: Thu, 17 Jan 2019 21:41:46 -0500 Subject: [PATCH 02/18] remove unused import --- src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c82b011..d1a5cf5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,8 +61,6 @@ #![deny(missing_docs)] #![cfg_attr(all(test, windows), feature(std_misc))] -#[allow(unused_imports)] -use std::ascii::AsciiExt; use std::cmp; use std::fmt; use std::fs; From b545492ead682a50710b2fc8cb8bef58815de43b Mon Sep 17 00:00:00 2001 From: George Kaplan Date: Thu, 17 Jan 2019 21:42:14 -0500 Subject: [PATCH 03/18] replace try! macro and move definitions to top of fn body --- src/lib.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d1a5cf5..6164947 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -167,9 +167,6 @@ pub fn glob(pattern: &str) -> Result { /// Paths are yielded in alphabetical order. pub fn glob_with(pattern: &str, options: &MatchOptions) -> Result { - // make sure that the pattern is valid first, else early return with error - let _compiled = try!(Pattern::new(pattern)); - #[cfg(windows)] fn check_windows_verbatim(p: &Path) -> bool { use std::path::Prefix; @@ -193,6 +190,12 @@ pub fn glob_with(pattern: &str, options: &MatchOptions) p.to_path_buf() } + // make sure that the pattern is valid first, else early return with error + if let Err(err) = Pattern::new(pattern) { + return Err(err); + } + + let mut components = Path::new(pattern).components().peekable(); loop { match components.peek() { @@ -232,8 +235,7 @@ pub fn glob_with(pattern: &str, options: &MatchOptions) .split_terminator(path::is_separator); for component in components { - let compiled = try!(Pattern::new(component)); - dir_patterns.push(compiled); + dir_patterns.push(Pattern::new(component)?); } if root_len == pattern.len() { From ad4450d5b01555832c56844a8f6b8f82fe262a4a Mon Sep 17 00:00:00 2001 From: George Kaplan Date: Thu, 17 Jan 2019 21:42:56 -0500 Subject: [PATCH 04/18] remove redundant struct field repetitions --- src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6164947..c4fc8c3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -251,10 +251,10 @@ pub fn glob_with(pattern: &str, options: &MatchOptions) let todo = Vec::new(); Ok(Paths { - dir_patterns: dir_patterns, - require_dir: require_dir, + dir_patterns, + require_dir, options: options.clone(), - todo: todo, + todo, scope: Some(scope), }) } @@ -633,9 +633,9 @@ impl Pattern { } Ok(Pattern { - tokens: tokens, + tokens, original: pattern.to_string(), - is_recursive: is_recursive, + is_recursive, }) } From fe54f394e3814946b0e70c9dc2d83797fe49352e Mon Sep 17 00:00:00 2001 From: George Kaplan Date: Thu, 17 Jan 2019 21:43:22 -0500 Subject: [PATCH 05/18] remove redundant return statement --- src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index c4fc8c3..dbeeffa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -796,7 +796,8 @@ fn fill_todo(todo: &mut Vec>, _ => return None, } } - return Some(s); + + Some(s) } let add = |todo: &mut Vec<_>, next_path: PathBuf| { From 99da6be79c5c576eafc777be39a11b72fa7d6710 Mon Sep 17 00:00:00 2001 From: George Kaplan Date: Thu, 17 Jan 2019 21:43:53 -0500 Subject: [PATCH 06/18] remove 'static specifier on consts --- src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index dbeeffa..838d974 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -516,10 +516,10 @@ enum MatchResult { EntirePatternDoesntMatch, } -const ERROR_WILDCARDS: &'static str = "wildcards are either regular `*` or recursive `**`"; -const ERROR_RECURSIVE_WILDCARDS: &'static str = "recursive wildcards must form a single path \ +const ERROR_WILDCARDS: &str = "wildcards are either regular `*` or recursive `**`"; +const ERROR_RECURSIVE_WILDCARDS: &str = "recursive wildcards must form a single path \ component"; -const ERROR_INVALID_RANGE: &'static str = "invalid range pattern"; +const ERROR_INVALID_RANGE: &str = "invalid range pattern"; impl Pattern { /// This function compiles Unix shell style patterns. From 4d8426b9c8afac179e19ad9444ecc723fb65e15b Mon Sep 17 00:00:00 2001 From: George Kaplan Date: Thu, 17 Jan 2019 21:44:16 -0500 Subject: [PATCH 07/18] use affirmative condition rather than negative one --- src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 838d974..b367530 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -383,13 +383,13 @@ impl Iterator for Paths { // advanced to the next pattern for this path idx = next + 1; } - } else if next != self.dir_patterns.len() - 1 { - // advanced to the next pattern for this path - idx = next + 1; - } else { + } else if next == self.dir_patterns.len() - 1 { // not a directory and it's the last pattern, meaning no // match continue; + } else { + // advanced to the next pattern for this path + idx = next + 1; } } From f5f06b40347eea38a0b042210c996576a054de7e Mon Sep 17 00:00:00 2001 From: George Kaplan Date: Thu, 17 Jan 2019 21:56:10 -0500 Subject: [PATCH 08/18] pass by value with new copy impl --- src/lib.rs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b367530..245bf3a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -149,7 +149,7 @@ pub struct Paths { /// ``` /// Paths are yielded in alphabetical order. pub fn glob(pattern: &str) -> Result { - glob_with(pattern, &MatchOptions::new()) + glob_with(pattern, MatchOptions::new()) } /// Return an iterator that produces all the `Path`s that match the given @@ -165,7 +165,7 @@ pub fn glob(pattern: &str) -> Result { /// passed to this function. /// /// Paths are yielded in alphabetical order. -pub fn glob_with(pattern: &str, options: &MatchOptions) +pub fn glob_with(pattern: &str, options: MatchOptions) -> Result { #[cfg(windows)] fn check_windows_verbatim(p: &Path) -> bool { @@ -222,13 +222,13 @@ pub fn glob_with(pattern: &str, options: &MatchOptions) return Ok(Paths { dir_patterns: Vec::new(), require_dir: false, - options: options.clone(), + options, todo: Vec::new(), scope: None, }); } - let scope = root.map(to_scope).unwrap_or_else(|| PathBuf::from(".")); + let scope = root.map_or_else(|| PathBuf::from("."), to_scope); let mut dir_patterns = Vec::new(); let components = pattern[cmp::min(root_len, pattern.len())..] @@ -253,7 +253,7 @@ pub fn glob_with(pattern: &str, options: &MatchOptions) Ok(Paths { dir_patterns, require_dir, - options: options.clone(), + options, todo, scope: Some(scope), }) @@ -333,7 +333,7 @@ impl Iterator for Paths { &self.dir_patterns, 0, &scope, - &self.options); + self.options); } } @@ -373,7 +373,7 @@ impl Iterator for Paths { &self.dir_patterns, next, &path, - &self.options); + self.options); if next == self.dir_patterns.len() - 1 { // pattern ends in recursive pattern, so return this @@ -402,7 +402,7 @@ impl Iterator for Paths { None => continue, Some(x) => x } - }, &self.options) { + }, self.options) { if idx == self.dir_patterns.len() - 1 { // it is not possible for a pattern to match a directory // *AND* its children so we don't need to check the @@ -413,7 +413,7 @@ impl Iterator for Paths { } } else { fill_todo(&mut self.todo, &self.dir_patterns, - idx + 1, &path, &self.options); + idx + 1, &path, self.options); } } } @@ -674,7 +674,7 @@ impl Pattern { /// assert!(Pattern::new("d*g").unwrap().matches("doog")); /// ``` pub fn matches(&self, str: &str) -> bool { - self.matches_with(str, &MatchOptions::new()) + self.matches_with(str, MatchOptions::new()) } /// Return if the given `Path`, when converted to a `str`, matches this @@ -686,13 +686,13 @@ impl Pattern { /// Return if the given `str` matches this `Pattern` using the specified /// match options. - pub fn matches_with(&self, str: &str, options: &MatchOptions) -> bool { + pub fn matches_with(&self, str: &str, options: MatchOptions) -> bool { self.matches_from(true, str.chars(), 0, options) == Match } /// Return if the given `Path`, when converted to a `str`, matches this /// `Pattern` using the specified match options. - pub fn matches_path_with(&self, path: &Path, options: &MatchOptions) -> bool { + pub fn matches_path_with(&self, path: &Path, options: MatchOptions) -> bool { // FIXME (#9639): This needs to handle non-utf8 paths path.to_str().map_or(false, |s| self.matches_with(s, options)) } @@ -706,7 +706,7 @@ impl Pattern { mut follows_separator: bool, mut file: std::str::Chars, i: usize, - options: &MatchOptions) + options: MatchOptions) -> MatchResult { for (ti, token) in self.tokens[i..].iter().enumerate() { @@ -786,7 +786,7 @@ fn fill_todo(todo: &mut Vec>, patterns: &[Pattern], idx: usize, path: &Path, - options: &MatchOptions) { + options: MatchOptions) { // convert a pattern that's just many Char(_) to a string fn pattern_as_str(pattern: &Pattern) -> Option { let mut s = String::new(); @@ -891,7 +891,7 @@ fn parse_char_specifiers(s: &[char]) -> Vec { cs } -fn in_char_specifiers(specifiers: &[CharSpecifier], c: char, options: &MatchOptions) -> bool { +fn in_char_specifiers(specifiers: &[CharSpecifier], c: char, options: MatchOptions) -> bool { for &specifier in specifiers.iter() { match specifier { From 3049fbdefe1c4b42e5a583009e4c43adf6a1bc7b Mon Sep 17 00:00:00 2001 From: George Kaplan Date: Thu, 17 Jan 2019 21:56:32 -0500 Subject: [PATCH 09/18] elide unnecessary lifetimes --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 245bf3a..d824ef1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -698,7 +698,7 @@ impl Pattern { } /// Access the original glob pattern. - pub fn as_str<'a>(&'a self) -> &'a str { + pub fn as_str(&self) -> &str { &self.original } From 4223d07713411e0cd779f42a6437f08e5c24ce31 Mon Sep 17 00:00:00 2001 From: George Kaplan Date: Thu, 17 Jan 2019 21:57:03 -0500 Subject: [PATCH 10/18] use Self in impl blocks --- src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d824ef1..aee6e4f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -488,8 +488,8 @@ impl fmt::Display for Pattern { impl FromStr for Pattern { type Err = PatternError; - fn from_str(s: &str) -> Result { - Pattern::new(s) + fn from_str(s: &str) -> Result { + Self::new(s) } } @@ -525,7 +525,7 @@ impl Pattern { /// This function compiles Unix shell style patterns. /// /// An invalid glob pattern will yield a `PatternError`. - pub fn new(pattern: &str) -> Result { + pub fn new(pattern: &str) -> Result { let chars = pattern.chars().collect::>(); let mut tokens = Vec::new(); @@ -632,7 +632,7 @@ impl Pattern { } } - Ok(Pattern { + Ok(Self { tokens, original: pattern.to_string(), is_recursive, @@ -981,8 +981,8 @@ impl MatchOptions { /// require_literal_leading_dot: false /// } /// ``` - pub fn new() -> MatchOptions { - MatchOptions { + pub fn new() -> Self { + Self { case_sensitive: true, require_literal_separator: false, require_literal_leading_dot: false, From 0d6f408324054bbe62d1533aa7526ce17ed1761f Mon Sep 17 00:00:00 2001 From: George Kaplan Date: Thu, 17 Jan 2019 21:57:28 -0500 Subject: [PATCH 11/18] use !is_empty rather than len > 0, for _ in &_ rather than for _ in _.iter() --- src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index aee6e4f..fc2e868 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -325,7 +325,7 @@ impl Iterator for Paths { // failing to fill the buffer is an iteration error construction of the // iterator (i.e. glob()) only fails if it fails to compile the Pattern if let Some(scope) = self.scope.take() { - if self.dir_patterns.len() > 0 { + if !self.dir_patterns.is_empty() { // Shouldn't happen, but we're using -1 as a special index. assert!(self.dir_patterns.len() < !0 as usize); @@ -790,7 +790,7 @@ fn fill_todo(todo: &mut Vec>, // convert a pattern that's just many Char(_) to a string fn pattern_as_str(pattern: &Pattern) -> Option { let mut s = String::new(); - for token in pattern.tokens.iter() { + for token in &pattern.tokens { match *token { Char(c) => s.push(c), _ => return None, @@ -854,8 +854,8 @@ fn fill_todo(todo: &mut Vec>, // requires that the pattern has a leading dot, even if the // `MatchOptions` field `require_literal_leading_dot` is not // set. - if pattern.tokens.len() > 0 && pattern.tokens[0] == Char('.') { - for &special in [".", ".."].iter() { + if !pattern.tokens.is_empty() && pattern.tokens[0] == Char('.') { + for &special in &[".", ".."] { if pattern.matches_with(special, options) { add(todo, path.join(special)); } From 1b7759c389f5f612320c72170efa7c0583028c29 Mon Sep 17 00:00:00 2001 From: George Kaplan Date: Thu, 17 Jan 2019 22:01:15 -0500 Subject: [PATCH 12/18] fix borrow/pass-by-value errors in tests --- src/lib.rs | 70 +++++++++++++++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fc2e868..120a73d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1169,7 +1169,7 @@ mod test { } for c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ".chars() { let options = MatchOptions { case_sensitive: false, ..MatchOptions::new() }; - assert!(pat.matches_with(&c.to_string(), &options)); + assert!(pat.matches_with(&c.to_string(), options)); } assert!(pat.matches("1")); assert!(pat.matches("2")); @@ -1229,10 +1229,10 @@ mod test { require_literal_leading_dot: false, }; - assert!(pat.matches_with("aBcDeFg", &options)); - assert!(pat.matches_with("abcdefg", &options)); - assert!(pat.matches_with("ABCDEFG", &options)); - assert!(pat.matches_with("AbCdEfG", &options)); + assert!(pat.matches_with("aBcDeFg", options)); + assert!(pat.matches_with("abcdefg", options)); + assert!(pat.matches_with("ABCDEFG", options)); + assert!(pat.matches_with("AbCdEfG", options)); } #[test] @@ -1252,13 +1252,13 @@ mod test { require_literal_leading_dot: false, }; - assert!(pat_within.matches_with("a", &options_case_insensitive)); - assert!(pat_within.matches_with("A", &options_case_insensitive)); - assert!(!pat_within.matches_with("A", &options_case_sensitive)); + assert!(pat_within.matches_with("a", options_case_insensitive)); + assert!(pat_within.matches_with("A", options_case_insensitive)); + assert!(!pat_within.matches_with("A", options_case_sensitive)); - assert!(!pat_except.matches_with("a", &options_case_insensitive)); - assert!(!pat_except.matches_with("A", &options_case_insensitive)); - assert!(pat_except.matches_with("A", &options_case_sensitive)); + assert!(!pat_except.matches_with("a", options_case_insensitive)); + assert!(!pat_except.matches_with("A", options_case_insensitive)); + assert!(pat_except.matches_with("A", options_case_sensitive)); } #[test] @@ -1275,29 +1275,29 @@ mod test { require_literal_leading_dot: false, }; - assert!(Pattern::new("abc/def").unwrap().matches_with("abc/def", &options_require_literal)); + assert!(Pattern::new("abc/def").unwrap().matches_with("abc/def", options_require_literal)); assert!(!Pattern::new("abc?def") .unwrap() - .matches_with("abc/def", &options_require_literal)); + .matches_with("abc/def", options_require_literal)); assert!(!Pattern::new("abc*def") .unwrap() - .matches_with("abc/def", &options_require_literal)); + .matches_with("abc/def", options_require_literal)); assert!(!Pattern::new("abc[/]def") .unwrap() - .matches_with("abc/def", &options_require_literal)); + .matches_with("abc/def", options_require_literal)); assert!(Pattern::new("abc/def") .unwrap() - .matches_with("abc/def", &options_not_require_literal)); + .matches_with("abc/def", options_not_require_literal)); assert!(Pattern::new("abc?def") .unwrap() - .matches_with("abc/def", &options_not_require_literal)); + .matches_with("abc/def", options_not_require_literal)); assert!(Pattern::new("abc*def") .unwrap() - .matches_with("abc/def", &options_not_require_literal)); + .matches_with("abc/def", options_not_require_literal)); assert!(Pattern::new("abc[/]def") .unwrap() - .matches_with("abc/def", &options_not_require_literal)); + .matches_with("abc/def", options_not_require_literal)); } #[test] @@ -1315,38 +1315,38 @@ mod test { }; let f = |options| Pattern::new("*.txt").unwrap().matches_with(".hello.txt", options); - assert!(f(&options_not_require_literal_leading_dot)); - assert!(!f(&options_require_literal_leading_dot)); + assert!(f(options_not_require_literal_leading_dot)); + assert!(!f(options_require_literal_leading_dot)); let f = |options| Pattern::new(".*.*").unwrap().matches_with(".hello.txt", options); - assert!(f(&options_not_require_literal_leading_dot)); - assert!(f(&options_require_literal_leading_dot)); + assert!(f(options_not_require_literal_leading_dot)); + assert!(f(options_require_literal_leading_dot)); let f = |options| Pattern::new("aaa/bbb/*").unwrap().matches_with("aaa/bbb/.ccc", options); - assert!(f(&options_not_require_literal_leading_dot)); - assert!(!f(&options_require_literal_leading_dot)); + assert!(f(options_not_require_literal_leading_dot)); + assert!(!f(options_require_literal_leading_dot)); let f = |options| { Pattern::new("aaa/bbb/*").unwrap().matches_with("aaa/bbb/c.c.c.", options) }; - assert!(f(&options_not_require_literal_leading_dot)); - assert!(f(&options_require_literal_leading_dot)); + assert!(f(options_not_require_literal_leading_dot)); + assert!(f(options_require_literal_leading_dot)); let f = |options| Pattern::new("aaa/bbb/.*").unwrap().matches_with("aaa/bbb/.ccc", options); - assert!(f(&options_not_require_literal_leading_dot)); - assert!(f(&options_require_literal_leading_dot)); + assert!(f(options_not_require_literal_leading_dot)); + assert!(f(options_require_literal_leading_dot)); let f = |options| Pattern::new("aaa/?bbb").unwrap().matches_with("aaa/.bbb", options); - assert!(f(&options_not_require_literal_leading_dot)); - assert!(!f(&options_require_literal_leading_dot)); + assert!(f(options_not_require_literal_leading_dot)); + assert!(!f(options_require_literal_leading_dot)); let f = |options| Pattern::new("aaa/[.]bbb").unwrap().matches_with("aaa/.bbb", options); - assert!(f(&options_not_require_literal_leading_dot)); - assert!(!f(&options_require_literal_leading_dot)); + assert!(f(options_not_require_literal_leading_dot)); + assert!(!f(options_require_literal_leading_dot)); let f = |options| Pattern::new("**/*").unwrap().matches_with(".bbb", options); - assert!(f(&options_not_require_literal_leading_dot)); - assert!(!f(&options_require_literal_leading_dot)); + assert!(f(options_not_require_literal_leading_dot)); + assert!(!f(options_require_literal_leading_dot)); } #[test] From 507a08477975f59feacd973075ddb071b5c556d6 Mon Sep 17 00:00:00 2001 From: George Kaplan Date: Thu, 17 Jan 2019 22:16:19 -0500 Subject: [PATCH 13/18] don't assume `macos` target os has a /root directory --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 120a73d..e5ea92a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1031,7 +1031,7 @@ mod test { // this test assumes that there is a /root directory and that // the user running this test is not root or otherwise doesn't // have permission to read its contents - #[cfg(unix)] + #[cfg(all(unix, not(target_os="macos")))] #[test] fn test_iteration_errors() { use std::io; From 3c53061d360e7578c5696935647db67d4dbf91cf Mon Sep 17 00:00:00 2001 From: George Kaplan Date: Thu, 17 Jan 2019 22:19:18 -0500 Subject: [PATCH 14/18] removed borrow in doctest --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index e5ea92a..7812c68 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,7 +48,7 @@ //! require_literal_separator: false, //! require_literal_leading_dot: false, //! }; -//! for entry in glob_with("local/*a*", &options).unwrap() { +//! for entry in glob_with("local/*a*", options).unwrap() { //! if let Ok(path) = entry { //! println!("{:?}", path.display()) //! } From 2f09a1f7d20f66f36fb38e790b28c72e6d8fcb68 Mon Sep 17 00:00:00 2001 From: George Kaplan Date: Thu, 17 Jan 2019 22:23:33 -0500 Subject: [PATCH 15/18] ran cargo fmt --- src/lib.rs | 301 ++++++++++++++++++++++----------------- tests/glob-std.rs | 353 +++++++++++++++++++++++++++++----------------- 2 files changed, 400 insertions(+), 254 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7812c68..8e35e44 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,24 +55,26 @@ //! } //! ``` -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://www.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/glob/")] +#![doc( + html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/glob/" +)] #![deny(missing_docs)] #![cfg_attr(all(test, windows), feature(std_misc))] use std::cmp; +use std::error::Error; use std::fmt; use std::fs; use std::io; -use std::path::{self, Path, PathBuf, Component}; +use std::path::{self, Component, Path, PathBuf}; use std::str::FromStr; -use std::error::Error; -use PatternToken::{Char, AnyChar, AnySequence, AnyRecursiveSequence, AnyWithin}; +use CharSpecifier::{CharRange, SingleChar}; +use MatchResult::{EntirePatternDoesntMatch, Match, SubPatternDoesntMatch}; use PatternToken::AnyExcept; -use CharSpecifier::{SingleChar, CharRange}; -use MatchResult::{Match, SubPatternDoesntMatch, EntirePatternDoesntMatch}; +use PatternToken::{AnyChar, AnyRecursiveSequence, AnySequence, AnyWithin, Char}; /// An iterator that yields `Path`s from the filesystem that match a particular /// pattern. @@ -165,8 +167,7 @@ pub fn glob(pattern: &str) -> Result { /// passed to this function. /// /// Paths are yielded in alphabetical order. -pub fn glob_with(pattern: &str, options: MatchOptions) - -> Result { +pub fn glob_with(pattern: &str, options: MatchOptions) -> Result { #[cfg(windows)] fn check_windows_verbatim(p: &Path) -> bool { use std::path::Prefix; @@ -195,12 +196,10 @@ pub fn glob_with(pattern: &str, options: MatchOptions) return Err(err); } - let mut components = Path::new(pattern).components().peekable(); loop { match components.peek() { - Some(&Component::Prefix(..)) | - Some(&Component::RootDir) => { + Some(&Component::Prefix(..)) | Some(&Component::RootDir) => { components.next(); } _ => break, @@ -231,8 +230,8 @@ pub fn glob_with(pattern: &str, options: MatchOptions) let scope = root.map_or_else(|| PathBuf::from("."), to_scope); let mut dir_patterns = Vec::new(); - let components = pattern[cmp::min(root_len, pattern.len())..] - .split_terminator(path::is_separator); + let components = + pattern[cmp::min(root_len, pattern.len())..].split_terminator(path::is_separator); for component in components { dir_patterns.push(Pattern::new(component)?); @@ -299,10 +298,12 @@ impl Error for GlobError { impl fmt::Display for GlobError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, - "attempting to read `{}` resulted in an error: {}", - self.path.display(), - self.error) + write!( + f, + "attempting to read `{}` resulted in an error: {}", + self.path.display(), + self.error + ) } } @@ -329,11 +330,7 @@ impl Iterator for Paths { // Shouldn't happen, but we're using -1 as a special index. assert!(self.dir_patterns.len() < !0 as usize); - fill_todo(&mut self.todo, - &self.dir_patterns, - 0, - &scope, - self.options); + fill_todo(&mut self.todo, &self.dir_patterns, 0, &scope, self.options); } } @@ -360,8 +357,9 @@ impl Iterator for Paths { let mut next = idx; // collapse consecutive recursive patterns - while (next + 1) < self.dir_patterns.len() && - self.dir_patterns[next + 1].is_recursive { + while (next + 1) < self.dir_patterns.len() + && self.dir_patterns[next + 1].is_recursive + { next += 1; } @@ -369,11 +367,13 @@ impl Iterator for Paths { // the path is a directory, so it's a match // push this directory's contents - fill_todo(&mut self.todo, - &self.dir_patterns, - next, - &path, - self.options); + fill_todo( + &mut self.todo, + &self.dir_patterns, + next, + &path, + self.options, + ); if next == self.dir_patterns.len() - 1 { // pattern ends in recursive pattern, so return this @@ -394,15 +394,18 @@ impl Iterator for Paths { } // not recursive, so match normally - if self.dir_patterns[idx].matches_with({ - match path.file_name().and_then(|s| s.to_str()) { - // FIXME (#9639): How do we handle non-utf8 filenames? - // Ignore them for now; ideally we'd still match them - // against a * - None => continue, - Some(x) => x - } - }, self.options) { + if self.dir_patterns[idx].matches_with( + { + match path.file_name().and_then(|s| s.to_str()) { + // FIXME (#9639): How do we handle non-utf8 filenames? + // Ignore them for now; ideally we'd still match them + // against a * + None => continue, + Some(x) => x, + } + }, + self.options, + ) { if idx == self.dir_patterns.len() - 1 { // it is not possible for a pattern to match a directory // *AND* its children so we don't need to check the @@ -412,8 +415,13 @@ impl Iterator for Paths { return Some(Ok(path)); } } else { - fill_todo(&mut self.todo, &self.dir_patterns, - idx + 1, &path, self.options); + fill_todo( + &mut self.todo, + &self.dir_patterns, + idx + 1, + &path, + self.options, + ); } } } @@ -439,10 +447,11 @@ impl Error for PatternError { impl fmt::Display for PatternError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, - "Pattern syntax error near position {}: {}", - self.pos, - self.msg) + write!( + f, + "Pattern syntax error near position {}: {}", + self.pos, self.msg + ) } } @@ -518,7 +527,7 @@ enum MatchResult { const ERROR_WILDCARDS: &str = "wildcards are either regular `*` or recursive `**`"; const ERROR_RECURSIVE_WILDCARDS: &str = "recursive wildcards must form a single path \ - component"; + component"; const ERROR_INVALID_RANGE: &str = "invalid range pattern"; impl Pattern { @@ -526,7 +535,6 @@ impl Pattern { /// /// An invalid glob pattern will yield a `PatternError`. pub fn new(pattern: &str) -> Result { - let chars = pattern.chars().collect::>(); let mut tokens = Vec::new(); let mut is_recursive = false; @@ -561,18 +569,18 @@ impl Pattern { if i < chars.len() && path::is_separator(chars[i]) { i += 1; true - // or the pattern ends here - // this enables the existing globbing mechanism + // or the pattern ends here + // this enables the existing globbing mechanism } else if i == chars.len() { true - // `**` ends in non-separator + // `**` ends in non-separator } else { return Err(PatternError { pos: i, msg: ERROR_RECURSIVE_WILDCARDS, }); } - // `**` begins with non-separator + // `**` begins with non-separator } else { return Err(PatternError { pos: old - 1, @@ -595,7 +603,6 @@ impl Pattern { } } '[' => { - if i + 4 <= chars.len() && chars[i + 1] == '!' { match chars[i + 3..].iter().position(|x| *x == ']') { None => (), @@ -694,7 +701,8 @@ impl Pattern { /// `Pattern` using the specified match options. pub fn matches_path_with(&self, path: &Path, options: MatchOptions) -> bool { // FIXME (#9639): This needs to handle non-utf8 paths - path.to_str().map_or(false, |s| self.matches_with(s, options)) + path.to_str() + .map_or(false, |s| self.matches_with(s, options)) } /// Access the original glob pattern. @@ -702,13 +710,13 @@ impl Pattern { &self.original } - fn matches_from(&self, - mut follows_separator: bool, - mut file: std::str::Chars, - i: usize, - options: MatchOptions) - -> MatchResult { - + fn matches_from( + &self, + mut follows_separator: bool, + mut file: std::str::Chars, + i: usize, + options: MatchOptions, + ) -> MatchResult { for (ti, token) in self.tokens[i..].iter().enumerate() { match *token { AnySequence | AnyRecursiveSequence => { @@ -731,14 +739,19 @@ impl Pattern { follows_separator = path::is_separator(c); match *token { AnyRecursiveSequence if !follows_separator => continue, - AnySequence if options.require_literal_separator && - follows_separator => return SubPatternDoesntMatch, + AnySequence + if options.require_literal_separator && follows_separator => + { + return SubPatternDoesntMatch + } _ => (), } - match self.matches_from(follows_separator, - file.clone(), - i + ti + 1, - options) { + match self.matches_from( + follows_separator, + file.clone(), + i + ti + 1, + options, + ) { SubPatternDoesntMatch => (), // keep trying m => return m, } @@ -754,9 +767,13 @@ impl Pattern { if !match *token { AnyChar | AnyWithin(..) | AnyExcept(..) - if (options.require_literal_separator && is_sep) || - (follows_separator && options.require_literal_leading_dot && - c == '.') => false, + if (options.require_literal_separator && is_sep) + || (follows_separator + && options.require_literal_leading_dot + && c == '.') => + { + false + } AnyChar => true, AnyWithin(ref specifiers) => in_char_specifiers(&specifiers, c, options), AnyExcept(ref specifiers) => !in_char_specifiers(&specifiers, c, options), @@ -782,11 +799,13 @@ impl Pattern { // Fills `todo` with paths under `path` to be matched by `patterns[idx]`, // special-casing patterns to match `.` and `..`, and avoiding `readdir()` // calls when there are no metacharacters in the pattern. -fn fill_todo(todo: &mut Vec>, - patterns: &[Pattern], - idx: usize, - path: &Path, - options: MatchOptions) { +fn fill_todo( + todo: &mut Vec>, + patterns: &[Pattern], + idx: usize, + path: &Path, + options: MatchOptions, +) { // convert a pattern that's just many Char(_) to a string fn pattern_as_str(pattern: &Pattern) -> Option { let mut s = String::new(); @@ -834,15 +853,15 @@ fn fill_todo(todo: &mut Vec>, None if is_dir => { let dirs = fs::read_dir(path).and_then(|d| { d.map(|e| { - e.map(|e| { - if curdir { - PathBuf::from(e.path().file_name().unwrap()) - } else { - e.path() - } - }) - }) - .collect::, _>>() + e.map(|e| { + if curdir { + PathBuf::from(e.path().file_name().unwrap()) + } else { + e.path() + } + }) + }) + .collect::, _>>() }); match dirs { Ok(mut children) => { @@ -892,7 +911,6 @@ fn parse_char_specifiers(s: &[char]) -> Vec { } fn in_char_specifiers(specifiers: &[CharSpecifier], c: char, options: MatchOptions) -> bool { - for &specifier in specifiers.iter() { match specifier { SingleChar(sc) => { @@ -901,10 +919,8 @@ fn in_char_specifiers(specifiers: &[CharSpecifier], c: char, options: MatchOptio } } CharRange(start, end) => { - // FIXME: work with non-ascii chars properly (issue #1347) if !options.case_sensitive && c.is_ascii() && start.is_ascii() && end.is_ascii() { - let start = start.to_ascii_lowercase(); let end = end.to_ascii_lowercase(); @@ -943,7 +959,6 @@ fn chars_eq(a: char, b: char, case_sensitive: bool) -> bool { } } - /// Configuration options to modify the behaviour of `Pattern::matches_with(..)`. #[allow(missing_copy_implementations)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] @@ -992,8 +1007,8 @@ impl MatchOptions { #[cfg(test)] mod test { + use super::{glob, MatchOptions, Pattern}; use std::path::Path; - use super::{glob, Pattern, MatchOptions}; #[test] fn test_pattern_from_str() { @@ -1031,7 +1046,7 @@ mod test { // this test assumes that there is a /root directory and that // the user running this test is not root or otherwise doesn't // have permission to read its contents - #[cfg(all(unix, not(target_os="macos")))] + #[cfg(all(unix, not(target_os = "macos")))] #[test] fn test_iteration_errors() { use std::io; @@ -1067,11 +1082,14 @@ mod test { // check windows absolute paths with host/device components let root_with_device = current_dir() - .ok() - .and_then(|p| p.prefix().map(|p| p.join("*"))) - .unwrap(); + .ok() + .and_then(|p| p.prefix().map(|p| p.join("*"))) + .unwrap(); // FIXME (#9639): This needs to handle non-utf8 paths - assert!(glob(root_with_device.as_os_str().to_str().unwrap()).unwrap().next().is_some()); + assert!(glob(root_with_device.as_os_str().to_str().unwrap()) + .unwrap() + .next() + .is_some()); } win() } @@ -1083,11 +1101,15 @@ mod test { assert!(!Pattern::new("a*b*c").unwrap().matches("abcd")); assert!(Pattern::new("a*b*c").unwrap().matches("a_b_c")); assert!(Pattern::new("a*b*c").unwrap().matches("a___b___c")); - assert!(Pattern::new("abc*abc*abc").unwrap().matches("abcabcabcabcabcabcabc")); - assert!(!Pattern::new("abc*abc*abc").unwrap().matches("abcabcabcabcabcabcabca")); + assert!(Pattern::new("abc*abc*abc") + .unwrap() + .matches("abcabcabcabcabcabcabc")); + assert!(!Pattern::new("abc*abc*abc") + .unwrap() + .matches("abcabcabcabcabcabcabca")); assert!(Pattern::new("a*a*a*a*a*a*a*a*a") - .unwrap() - .matches("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); + .unwrap() + .matches("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); assert!(Pattern::new("a*b[xyz]c*d").unwrap().matches("abxcdbxcddd")); } @@ -1109,7 +1131,6 @@ mod test { assert!(pat.matches(".asdf")); assert!(pat.matches("/x/.asdf")); - // collapse consecutive wildcards let pat = Pattern::new("some/**/**/needle.txt").unwrap(); assert!(pat.matches("some/needle.txt")); @@ -1148,7 +1169,6 @@ mod test { #[test] fn test_range_pattern() { - let pat = Pattern::new("a[0-9]b").unwrap(); for i in 0..10 { assert!(pat.matches(&format!("a{}b", i))); @@ -1168,7 +1188,10 @@ mod test { assert!(pat.matches(&c.to_string())); } for c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ".chars() { - let options = MatchOptions { case_sensitive: false, ..MatchOptions::new() }; + let options = MatchOptions { + case_sensitive: false, + ..MatchOptions::new() + }; assert!(pat.matches_with(&c.to_string(), options)); } assert!(pat.matches("1")); @@ -1221,7 +1244,6 @@ mod test { #[test] fn test_pattern_matches_case_insensitive() { - let pat = Pattern::new("aBcDeFg").unwrap(); let options = MatchOptions { case_sensitive: false, @@ -1237,7 +1259,6 @@ mod test { #[test] fn test_pattern_matches_case_insensitive_range() { - let pat_within = Pattern::new("[a]").unwrap(); let pat_except = Pattern::new("[!a]").unwrap(); @@ -1263,7 +1284,6 @@ mod test { #[test] fn test_pattern_matches_require_literal_separator() { - let options_require_literal = MatchOptions { case_sensitive: true, require_literal_separator: true, @@ -1275,34 +1295,35 @@ mod test { require_literal_leading_dot: false, }; - assert!(Pattern::new("abc/def").unwrap().matches_with("abc/def", options_require_literal)); + assert!(Pattern::new("abc/def") + .unwrap() + .matches_with("abc/def", options_require_literal)); assert!(!Pattern::new("abc?def") - .unwrap() - .matches_with("abc/def", options_require_literal)); + .unwrap() + .matches_with("abc/def", options_require_literal)); assert!(!Pattern::new("abc*def") - .unwrap() - .matches_with("abc/def", options_require_literal)); + .unwrap() + .matches_with("abc/def", options_require_literal)); assert!(!Pattern::new("abc[/]def") - .unwrap() - .matches_with("abc/def", options_require_literal)); + .unwrap() + .matches_with("abc/def", options_require_literal)); assert!(Pattern::new("abc/def") - .unwrap() - .matches_with("abc/def", options_not_require_literal)); + .unwrap() + .matches_with("abc/def", options_not_require_literal)); assert!(Pattern::new("abc?def") - .unwrap() - .matches_with("abc/def", options_not_require_literal)); + .unwrap() + .matches_with("abc/def", options_not_require_literal)); assert!(Pattern::new("abc*def") - .unwrap() - .matches_with("abc/def", options_not_require_literal)); + .unwrap() + .matches_with("abc/def", options_not_require_literal)); assert!(Pattern::new("abc[/]def") - .unwrap() - .matches_with("abc/def", options_not_require_literal)); + .unwrap() + .matches_with("abc/def", options_not_require_literal)); } #[test] fn test_pattern_matches_require_literal_leading_dot() { - let options_require_literal_leading_dot = MatchOptions { case_sensitive: true, require_literal_separator: false, @@ -1314,33 +1335,59 @@ mod test { require_literal_leading_dot: false, }; - let f = |options| Pattern::new("*.txt").unwrap().matches_with(".hello.txt", options); + let f = |options| { + Pattern::new("*.txt") + .unwrap() + .matches_with(".hello.txt", options) + }; assert!(f(options_not_require_literal_leading_dot)); assert!(!f(options_require_literal_leading_dot)); - let f = |options| Pattern::new(".*.*").unwrap().matches_with(".hello.txt", options); + let f = |options| { + Pattern::new(".*.*") + .unwrap() + .matches_with(".hello.txt", options) + }; assert!(f(options_not_require_literal_leading_dot)); assert!(f(options_require_literal_leading_dot)); - let f = |options| Pattern::new("aaa/bbb/*").unwrap().matches_with("aaa/bbb/.ccc", options); + let f = |options| { + Pattern::new("aaa/bbb/*") + .unwrap() + .matches_with("aaa/bbb/.ccc", options) + }; assert!(f(options_not_require_literal_leading_dot)); assert!(!f(options_require_literal_leading_dot)); let f = |options| { - Pattern::new("aaa/bbb/*").unwrap().matches_with("aaa/bbb/c.c.c.", options) + Pattern::new("aaa/bbb/*") + .unwrap() + .matches_with("aaa/bbb/c.c.c.", options) }; assert!(f(options_not_require_literal_leading_dot)); assert!(f(options_require_literal_leading_dot)); - let f = |options| Pattern::new("aaa/bbb/.*").unwrap().matches_with("aaa/bbb/.ccc", options); + let f = |options| { + Pattern::new("aaa/bbb/.*") + .unwrap() + .matches_with("aaa/bbb/.ccc", options) + }; assert!(f(options_not_require_literal_leading_dot)); assert!(f(options_require_literal_leading_dot)); - let f = |options| Pattern::new("aaa/?bbb").unwrap().matches_with("aaa/.bbb", options); + let f = |options| { + Pattern::new("aaa/?bbb") + .unwrap() + .matches_with("aaa/.bbb", options) + }; assert!(f(options_not_require_literal_leading_dot)); assert!(!f(options_require_literal_leading_dot)); - let f = |options| Pattern::new("aaa/[.]bbb").unwrap().matches_with("aaa/.bbb", options); + let f = |options| { + Pattern::new("aaa/[.]bbb") + .unwrap() + .matches_with("aaa/.bbb", options) + }; assert!(f(options_not_require_literal_leading_dot)); assert!(!f(options_require_literal_leading_dot)); diff --git a/tests/glob-std.rs b/tests/glob-std.rs index c426418..085eb6d 100644 --- a/tests/glob-std.rs +++ b/tests/glob-std.rs @@ -17,8 +17,8 @@ extern crate tempdir; use glob::glob; use std::env; -use std::path::PathBuf; use std::fs; +use std::path::PathBuf; use tempdir::TempDir; #[test] @@ -79,63 +79,91 @@ fn main() { mk_file("r/three/c.md", false); // all recursive entities - assert_eq!(glob_vec("r/**"), vec!( - PathBuf::from("r/another"), - PathBuf::from("r/one"), - PathBuf::from("r/one/another"), - PathBuf::from("r/one/another/deep"), - PathBuf::from("r/three"), - PathBuf::from("r/two"))); + assert_eq!( + glob_vec("r/**"), + vec!( + PathBuf::from("r/another"), + PathBuf::from("r/one"), + PathBuf::from("r/one/another"), + PathBuf::from("r/one/another/deep"), + PathBuf::from("r/three"), + PathBuf::from("r/two") + ) + ); // collapse consecutive recursive patterns - assert_eq!(glob_vec("r/**/**"), vec!( - PathBuf::from("r/another"), - PathBuf::from("r/one"), - PathBuf::from("r/one/another"), - PathBuf::from("r/one/another/deep"), - PathBuf::from("r/three"), - PathBuf::from("r/two"))); - - assert_eq!(glob_vec("r/**/*"), vec!( - PathBuf::from("r/another"), - PathBuf::from("r/another/a.md"), - PathBuf::from("r/current_dir.md"), - PathBuf::from("r/one"), - PathBuf::from("r/one/a.md"), - PathBuf::from("r/one/another"), - PathBuf::from("r/one/another/a.md"), - PathBuf::from("r/one/another/deep"), - PathBuf::from("r/one/another/deep/spelunking.md"), - PathBuf::from("r/three"), - PathBuf::from("r/three/c.md"), - PathBuf::from("r/two"), - PathBuf::from("r/two/b.md"))); + assert_eq!( + glob_vec("r/**/**"), + vec!( + PathBuf::from("r/another"), + PathBuf::from("r/one"), + PathBuf::from("r/one/another"), + PathBuf::from("r/one/another/deep"), + PathBuf::from("r/three"), + PathBuf::from("r/two") + ) + ); + + assert_eq!( + glob_vec("r/**/*"), + vec!( + PathBuf::from("r/another"), + PathBuf::from("r/another/a.md"), + PathBuf::from("r/current_dir.md"), + PathBuf::from("r/one"), + PathBuf::from("r/one/a.md"), + PathBuf::from("r/one/another"), + PathBuf::from("r/one/another/a.md"), + PathBuf::from("r/one/another/deep"), + PathBuf::from("r/one/another/deep/spelunking.md"), + PathBuf::from("r/three"), + PathBuf::from("r/three/c.md"), + PathBuf::from("r/two"), + PathBuf::from("r/two/b.md") + ) + ); // followed by a wildcard - assert_eq!(glob_vec("r/**/*.md"), vec!( - PathBuf::from("r/another/a.md"), - PathBuf::from("r/current_dir.md"), - PathBuf::from("r/one/a.md"), - PathBuf::from("r/one/another/a.md"), - PathBuf::from("r/one/another/deep/spelunking.md"), - PathBuf::from("r/three/c.md"), - PathBuf::from("r/two/b.md"))); + assert_eq!( + glob_vec("r/**/*.md"), + vec!( + PathBuf::from("r/another/a.md"), + PathBuf::from("r/current_dir.md"), + PathBuf::from("r/one/a.md"), + PathBuf::from("r/one/another/a.md"), + PathBuf::from("r/one/another/deep/spelunking.md"), + PathBuf::from("r/three/c.md"), + PathBuf::from("r/two/b.md") + ) + ); // followed by a precise pattern - assert_eq!(glob_vec("r/one/**/a.md"), vec!( - PathBuf::from("r/one/a.md"), - PathBuf::from("r/one/another/a.md"))); + assert_eq!( + glob_vec("r/one/**/a.md"), + vec!( + PathBuf::from("r/one/a.md"), + PathBuf::from("r/one/another/a.md") + ) + ); // followed by another recursive pattern // collapses consecutive recursives into one - assert_eq!(glob_vec("r/one/**/**/a.md"), vec!( - PathBuf::from("r/one/a.md"), - PathBuf::from("r/one/another/a.md"))); + assert_eq!( + glob_vec("r/one/**/**/a.md"), + vec!( + PathBuf::from("r/one/a.md"), + PathBuf::from("r/one/another/a.md") + ) + ); // followed by two precise patterns - assert_eq!(glob_vec("r/**/another/a.md"), vec!( - PathBuf::from("r/another/a.md"), - PathBuf::from("r/one/another/a.md"))); + assert_eq!( + glob_vec("r/**/another/a.md"), + vec!( + PathBuf::from("r/another/a.md"), + PathBuf::from("r/one/another/a.md") + ) + ); assert_eq!(glob_vec(""), Vec::::new()); assert_eq!(glob_vec("."), vec!(PathBuf::from("."))); @@ -155,20 +183,32 @@ fn main() { assert_eq!(glob_vec("aaa\\apple"), vec!(PathBuf::from("aaa/apple"))); } - assert_eq!(glob_vec("???/"), vec!( - PathBuf::from("aaa"), - PathBuf::from("bbb"), - PathBuf::from("ccc"), - PathBuf::from("xyz"))); - - assert_eq!(glob_vec("aaa/tomato/tom?to.txt"), vec!( - PathBuf::from("aaa/tomato/tomato.txt"), - PathBuf::from("aaa/tomato/tomoto.txt"))); - - assert_eq!(glob_vec("xyz/?"), vec!( - PathBuf::from("xyz/x"), - PathBuf::from("xyz/y"), - PathBuf::from("xyz/z"))); + assert_eq!( + glob_vec("???/"), + vec!( + PathBuf::from("aaa"), + PathBuf::from("bbb"), + PathBuf::from("ccc"), + PathBuf::from("xyz") + ) + ); + + assert_eq!( + glob_vec("aaa/tomato/tom?to.txt"), + vec!( + PathBuf::from("aaa/tomato/tomato.txt"), + PathBuf::from("aaa/tomato/tomoto.txt") + ) + ); + + assert_eq!( + glob_vec("xyz/?"), + vec!( + PathBuf::from("xyz/x"), + PathBuf::from("xyz/y"), + PathBuf::from("xyz/z") + ) + ); assert_eq!(glob_vec("a*"), vec!(PathBuf::from("aaa"))); assert_eq!(glob_vec("*a*"), vec!(PathBuf::from("aaa"))); @@ -179,23 +219,39 @@ fn main() { assert_eq!(glob_vec("*a*a*a*"), vec!(PathBuf::from("aaa"))); assert_eq!(glob_vec("aaa*/"), vec!(PathBuf::from("aaa"))); - assert_eq!(glob_vec("aaa/*"), vec!( - PathBuf::from("aaa/apple"), - PathBuf::from("aaa/orange"), - PathBuf::from("aaa/tomato"))); - - assert_eq!(glob_vec("aaa/*a*"), vec!( - PathBuf::from("aaa/apple"), - PathBuf::from("aaa/orange"), - PathBuf::from("aaa/tomato"))); - - assert_eq!(glob_vec("*/*/*.txt"), vec!( - PathBuf::from("aaa/tomato/tomato.txt"), - PathBuf::from("aaa/tomato/tomoto.txt"))); - - assert_eq!(glob_vec("*/*/t[aob]m?to[.]t[!y]t"), vec!( - PathBuf::from("aaa/tomato/tomato.txt"), - PathBuf::from("aaa/tomato/tomoto.txt"))); + assert_eq!( + glob_vec("aaa/*"), + vec!( + PathBuf::from("aaa/apple"), + PathBuf::from("aaa/orange"), + PathBuf::from("aaa/tomato") + ) + ); + + assert_eq!( + glob_vec("aaa/*a*"), + vec!( + PathBuf::from("aaa/apple"), + PathBuf::from("aaa/orange"), + PathBuf::from("aaa/tomato") + ) + ); + + assert_eq!( + glob_vec("*/*/*.txt"), + vec!( + PathBuf::from("aaa/tomato/tomato.txt"), + PathBuf::from("aaa/tomato/tomoto.txt") + ) + ); + + assert_eq!( + glob_vec("*/*/t[aob]m?to[.]t[!y]t"), + vec!( + PathBuf::from("aaa/tomato/tomato.txt"), + PathBuf::from("aaa/tomato/tomoto.txt") + ) + ); assert_eq!(glob_vec("./aaa"), vec!(PathBuf::from("aaa"))); assert_eq!(glob_vec("./*"), glob_vec("*")); @@ -219,60 +275,103 @@ fn main() { assert_eq!(glob_vec("aa[!a]"), Vec::::new()); assert_eq!(glob_vec("aa[!abc]"), Vec::::new()); - assert_eq!(glob_vec("bbb/specials/[[]"), vec!(PathBuf::from("bbb/specials/["))); - assert_eq!(glob_vec("bbb/specials/!"), vec!(PathBuf::from("bbb/specials/!"))); - assert_eq!(glob_vec("bbb/specials/[]]"), vec!(PathBuf::from("bbb/specials/]"))); + assert_eq!( + glob_vec("bbb/specials/[[]"), + vec!(PathBuf::from("bbb/specials/[")) + ); + assert_eq!( + glob_vec("bbb/specials/!"), + vec!(PathBuf::from("bbb/specials/!")) + ); + assert_eq!( + glob_vec("bbb/specials/[]]"), + vec!(PathBuf::from("bbb/specials/]")) + ); if env::consts::FAMILY != "windows" { - assert_eq!(glob_vec("bbb/specials/[*]"), vec!(PathBuf::from("bbb/specials/*"))); - assert_eq!(glob_vec("bbb/specials/[?]"), vec!(PathBuf::from("bbb/specials/?"))); + assert_eq!( + glob_vec("bbb/specials/[*]"), + vec!(PathBuf::from("bbb/specials/*")) + ); + assert_eq!( + glob_vec("bbb/specials/[?]"), + vec!(PathBuf::from("bbb/specials/?")) + ); } if env::consts::FAMILY == "windows" { - - assert_eq!(glob_vec("bbb/specials/[![]"), vec!( - PathBuf::from("bbb/specials/!"), - PathBuf::from("bbb/specials/]"))); - - assert_eq!(glob_vec("bbb/specials/[!]]"), vec!( - PathBuf::from("bbb/specials/!"), - PathBuf::from("bbb/specials/["))); - - assert_eq!(glob_vec("bbb/specials/[!!]"), vec!( - PathBuf::from("bbb/specials/["), - PathBuf::from("bbb/specials/]"))); - + assert_eq!( + glob_vec("bbb/specials/[![]"), + vec!( + PathBuf::from("bbb/specials/!"), + PathBuf::from("bbb/specials/]") + ) + ); + + assert_eq!( + glob_vec("bbb/specials/[!]]"), + vec!( + PathBuf::from("bbb/specials/!"), + PathBuf::from("bbb/specials/[") + ) + ); + + assert_eq!( + glob_vec("bbb/specials/[!!]"), + vec!( + PathBuf::from("bbb/specials/["), + PathBuf::from("bbb/specials/]") + ) + ); } else { - - assert_eq!(glob_vec("bbb/specials/[![]"), vec!( - PathBuf::from("bbb/specials/!"), - PathBuf::from("bbb/specials/*"), - PathBuf::from("bbb/specials/?"), - PathBuf::from("bbb/specials/]"))); - - assert_eq!(glob_vec("bbb/specials/[!]]"), vec!( - PathBuf::from("bbb/specials/!"), - PathBuf::from("bbb/specials/*"), - PathBuf::from("bbb/specials/?"), - PathBuf::from("bbb/specials/["))); - - assert_eq!(glob_vec("bbb/specials/[!!]"), vec!( - PathBuf::from("bbb/specials/*"), - PathBuf::from("bbb/specials/?"), - PathBuf::from("bbb/specials/["), - PathBuf::from("bbb/specials/]"))); - - assert_eq!(glob_vec("bbb/specials/[!*]"), vec!( - PathBuf::from("bbb/specials/!"), - PathBuf::from("bbb/specials/?"), - PathBuf::from("bbb/specials/["), - PathBuf::from("bbb/specials/]"))); - - assert_eq!(glob_vec("bbb/specials/[!?]"), vec!( - PathBuf::from("bbb/specials/!"), - PathBuf::from("bbb/specials/*"), - PathBuf::from("bbb/specials/["), - PathBuf::from("bbb/specials/]"))); - + assert_eq!( + glob_vec("bbb/specials/[![]"), + vec!( + PathBuf::from("bbb/specials/!"), + PathBuf::from("bbb/specials/*"), + PathBuf::from("bbb/specials/?"), + PathBuf::from("bbb/specials/]") + ) + ); + + assert_eq!( + glob_vec("bbb/specials/[!]]"), + vec!( + PathBuf::from("bbb/specials/!"), + PathBuf::from("bbb/specials/*"), + PathBuf::from("bbb/specials/?"), + PathBuf::from("bbb/specials/[") + ) + ); + + assert_eq!( + glob_vec("bbb/specials/[!!]"), + vec!( + PathBuf::from("bbb/specials/*"), + PathBuf::from("bbb/specials/?"), + PathBuf::from("bbb/specials/["), + PathBuf::from("bbb/specials/]") + ) + ); + + assert_eq!( + glob_vec("bbb/specials/[!*]"), + vec!( + PathBuf::from("bbb/specials/!"), + PathBuf::from("bbb/specials/?"), + PathBuf::from("bbb/specials/["), + PathBuf::from("bbb/specials/]") + ) + ); + + assert_eq!( + glob_vec("bbb/specials/[!?]"), + vec!( + PathBuf::from("bbb/specials/!"), + PathBuf::from("bbb/specials/*"), + PathBuf::from("bbb/specials/["), + PathBuf::from("bbb/specials/]") + ) + ); } } From ab51aaac0b5a5def89165cb1b01f93e9ca879ba6 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Tue, 5 Feb 2019 11:29:22 +1000 Subject: [PATCH 16/18] add an explicit version to check in CI --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index a039727..cebc669 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: rust rust: + - 1.23.0 - stable - beta - nightly From f73ddefe9350bf6417d5161118f1a456cc565d8d Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Mon, 4 Mar 2019 10:04:31 +1000 Subject: [PATCH 17/18] prepare for 0.3.0 release --- Cargo.toml | 4 ++-- README.md | 2 +- src/lib.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9b77144..05f59bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "glob" -version = "0.2.11" +version = "0.3.0" authors = ["The Rust Project Developers"] license = "MIT/Apache-2.0" homepage = "https://github.com/rust-lang/glob" repository = "https://github.com/rust-lang/glob" -documentation = "https://doc.rust-lang.org/glob" +documentation = "https://docs.rs/glob/0.3.0" description = """ Support for matching file paths against Unix shell style patterns. """ diff --git a/README.md b/README.md index be88d43..e61a976 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ To use `glob`, add this to your `Cargo.toml`: ```toml [dependencies] -glob = "0.2" +glob = "0.3.0" ``` And add this to your crate root: diff --git a/src/lib.rs b/src/lib.rs index 8e35e44..b28db9b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,7 +58,7 @@ #![doc( html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://www.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/glob/" + html_root_url = "https://docs.rs/glob/0.3.0" )] #![deny(missing_docs)] #![cfg_attr(all(test, windows), feature(std_misc))] From 3e2f6df04f9ef55654561506e0ba7f0158d74525 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 2 May 2019 17:28:28 +0200 Subject: [PATCH 18/18] Add doc-comment to test README examples --- Cargo.toml | 1 + src/lib.rs | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 05f59bc..176e306 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,3 +14,4 @@ categories = ["filesystem"] [dev-dependencies] tempdir = "0.3" +doc-comment = "0.3" diff --git a/src/lib.rs b/src/lib.rs index b28db9b..d9f2762 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,6 +63,13 @@ #![deny(missing_docs)] #![cfg_attr(all(test, windows), feature(std_misc))] +#[cfg(test)] +#[macro_use] +extern crate doc_comment; + +#[cfg(test)] +doctest!("../README.md"); + use std::cmp; use std::error::Error; use std::fmt;