summaryrefslogtreecommitdiffstats
path: root/globset
diff options
context:
space:
mode:
authorAndrew Gallant <jamslam@gmail.com>2019-01-23 19:15:02 -0500
committerAndrew Gallant <jamslam@gmail.com>2019-01-23 19:15:02 -0500
commitaeaa5fc1b13bd5b903ef5660d3a6cb26b6745945 (patch)
tree17e30a965d00f0e1878a163cddc5cb70bb8ff352 /globset
parent7048a06c311317810db1c67c2828a4327eac4a60 (diff)
globset: fix repeated use of **
This fixes a bug where repeated use of ** didn't behave as it should. In particular, each use of `**` added a new requirement directory depth requirement. For example, something like `**/**/b` would match `foo/bar/b`, but it wouldn't match `foo/b` even though it should. In particular, `**` semantics demand "infinite" depth, so repeated uses of `**` should just coalesce as if only one was given. We do this coalescing in the parser. It's a little tricky because we treat `**/a`, `a/**` and `a/**/b` as distinct tokens with their own regex conversions. We also test the crap out of it. Fixes #1174
Diffstat (limited to 'globset')
-rw-r--r--globset/src/glob.rs58
1 files changed, 45 insertions, 13 deletions
diff --git a/globset/src/glob.rs b/globset/src/glob.rs
index cbbc7bad..53d44e15 100644
--- a/globset/src/glob.rs
+++ b/globset/src/glob.rs
@@ -850,27 +850,44 @@ impl<'a> Parser<'a> {
}
return Ok(());
}
- self.pop_token()?;
+
if !prev.map(is_separator).unwrap_or(false) {
if self.stack.len() <= 1
|| (prev != Some(',') && prev != Some('{')) {
return Err(self.error(ErrorKind::InvalidRecursive));
}
}
- match self.chars.peek() {
- None => {
- assert!(self.bump().is_none());
- self.push_token(Token::RecursiveSuffix)
+ let is_suffix =
+ match self.chars.peek() {
+ None => {
+ assert!(self.bump().is_none());
+ true
+ }
+ Some(&',') | Some(&'}') if self.stack.len() >= 2 => {
+ true
+ }
+ Some(&c) if is_separator(c) => {
+ assert!(self.bump().map(is_separator).unwrap_or(false));
+ false
+ }
+ _ => return Err(self.error(ErrorKind::InvalidRecursive)),
+ };
+ match self.pop_token()? {
+ Token::RecursivePrefix => {
+ self.push_token(Token::RecursivePrefix)?;
}
- Some(&',') | Some(&'}') if self.stack.len() >= 2 => {
- self.push_token(Token::RecursiveSuffix)
+ Token::RecursiveSuffix => {
+ self.push_token(Token::RecursiveSuffix)?;
}
- Some(&c) if is_separator(c) => {
- assert!(self.bump().map(is_separator).unwrap_or(false));
- self.push_token(Token::RecursiveZeroOrMore)
+ _ => {
+ if is_suffix {
+ self.push_token(Token::RecursiveSuffix)?;
+ } else {
+ self.push_token(Token::RecursiveZeroOrMore)?;
+ }
}
- _ => Err(self.error(ErrorKind::InvalidRecursive)),
}
+ Ok(())
}
fn parse_class(&mut self) -> Result<(), Error> {
@@ -1194,8 +1211,23 @@ mod tests {
toregex!(re8, "[*]", r"^[\*]$");
toregex!(re9, "[+]", r"^[\+]$");
toregex!(re10, "+", r"^\+$");
- toregex!(re11, "**", r"^.*$");
- toregex!(re12, "☃", r"^\xe2\x98\x83$");
+ toregex!(re11, "☃", r"^\xe2\x98\x83$");
+ toregex!(re12, "**", r"^.*$");
+ toregex!(re13, "**/", r"^.*$");
+ toregex!(re14, "**/*", r"^(?:/?|.*/).*$");
+ toregex!(re15, "**/**", r"^.*$");
+ toregex!(re16, "**/**/*", r"^(?:/?|.*/).*$");
+ toregex!(re17, "**/**/**", r"^.*$");
+ toregex!(re18, "**/**/**/*", r"^(?:/?|.*/).*$");
+ toregex!(re19, "a/**", r"^a(?:/?|/.*)$");
+ toregex!(re20, "a/**/**", r"^a(?:/?|/.*)$");
+ toregex!(re21, "a/**/**/**", r"^a(?:/?|/.*)$");
+ toregex!(re22, "a/**/b", r"^a(?:/|/.*/)b$");
+ toregex!(re23, "a/**/**/b", r"^a(?:/|/.*/)b$");
+ toregex!(re24, "a/**/**/**/b", r"^a(?:/|/.*/)b$");
+ toregex!(re25, "**/b", r"^(?:/?|.*/)b$");
+ toregex!(re26, "**/**/b", r"^(?:/?|.*/)b$");
+ toregex!(re27, "**/**/**/b", r"^(?:/?|.*/)b$");
matches!(match1, "a", "a");
matches!(match2, "a*b", "a_b");