mirror of
https://github.com/rclone/rclone.git
synced 2026-07-10 07:45:09 -04:00
filter: support nested {} alternates in glob filters - fixes #7220
This commit is contained in:
committed by
Nick Craig-Wood
parent
b59a17e5e8
commit
294e985e2e
@@ -83,7 +83,7 @@ func globToRegexp(glob string, pathMode bool, addAnchors bool, ignoreCase bool)
|
||||
buf := re.Bytes()
|
||||
buf[len(buf)-1] = c
|
||||
}
|
||||
inBraces := false
|
||||
braceDepth := 0
|
||||
inBrackets := 0
|
||||
slashed := false
|
||||
inRegexp := false // inside {{ ... }}
|
||||
@@ -152,25 +152,27 @@ func globToRegexp(glob string, pathMode bool, addAnchors bool, ignoreCase bool)
|
||||
case ']':
|
||||
return nil, fmt.Errorf("mismatched ']' in glob %q", glob)
|
||||
case '{':
|
||||
if inBraces {
|
||||
if last == '{' {
|
||||
inRegexp = true
|
||||
inBraces = false
|
||||
} else {
|
||||
return nil, fmt.Errorf("can't nest '{' '}' in glob %q", glob)
|
||||
}
|
||||
if braceDepth > 0 && last == '{' {
|
||||
// {{ starts a raw regexp section. The '(' written by
|
||||
// the first '{' wraps the regexp, so undo its depth.
|
||||
// (An escaped \{ does not open a brace, so braceDepth
|
||||
// guards against treating \{{ as a regexp section.)
|
||||
inRegexp = true
|
||||
braceDepth--
|
||||
} else {
|
||||
inBraces = true
|
||||
// Open a brace group. These may nest, so each level
|
||||
// emits its own balanced '(' ... ')'.
|
||||
braceDepth++
|
||||
_ = re.WriteByte('(')
|
||||
}
|
||||
case '}':
|
||||
if !inBraces {
|
||||
if braceDepth <= 0 {
|
||||
return nil, fmt.Errorf("mismatched '{' and '}' in glob %q", glob)
|
||||
}
|
||||
_ = re.WriteByte(')')
|
||||
inBraces = false
|
||||
braceDepth--
|
||||
case ',':
|
||||
if inBraces {
|
||||
if braceDepth > 0 {
|
||||
_ = re.WriteByte('|')
|
||||
} else {
|
||||
_, _ = re.WriteRune(c)
|
||||
@@ -189,7 +191,7 @@ func globToRegexp(glob string, pathMode bool, addAnchors bool, ignoreCase bool)
|
||||
if inBrackets > 0 {
|
||||
return nil, fmt.Errorf("mismatched '[' and ']' in glob %q", glob)
|
||||
}
|
||||
if inBraces {
|
||||
if braceDepth != 0 {
|
||||
return nil, fmt.Errorf("mismatched '{' and '}' in glob %q", glob)
|
||||
}
|
||||
if inRegexp {
|
||||
@@ -209,7 +211,8 @@ var (
|
||||
// Can't deal with
|
||||
// / or ** in {}
|
||||
// {{ regexp }}
|
||||
tooHardRe = regexp.MustCompile(`({[^{}]*(\*\*|/)[^{}]*})|\{\{|\}\}`)
|
||||
// nested {} (the inner braces are opaque to the directory split below)
|
||||
tooHardRe = regexp.MustCompile(`({[^{}]*(\*\*|/)[^{}]*})|\{\{|\}\}|\{[^{}]*\{`)
|
||||
|
||||
// Squash all /
|
||||
squashSlash = regexp.MustCompile(`/{2,}`)
|
||||
|
||||
@@ -24,6 +24,8 @@ func TestGlobStringToRegexp(t *testing.T) {
|
||||
{`'.' '+' '(' ')' '|' '^' '$'`, `'\.' '\+' '\(' '\)' '\|' '\^' '\$'`, ``},
|
||||
{`*.jpg`, `.*\.jpg`, ``},
|
||||
{`a{b,c,d}e`, `a(b|c|d)e`, ``},
|
||||
{`a{b,{c,d}}e`, `a(b|(c|d))e`, ``},
|
||||
{`{a,{b,c},{d,{e,f}}}`, `(a|(b|c)|(d|(e|f)))`, ``},
|
||||
{`potato**`, ``, `too many stars`},
|
||||
{`potato**sausage`, ``, `too many stars`},
|
||||
{`*.p[lm]`, `.*\.p[lm]`, ``},
|
||||
@@ -32,7 +34,7 @@ func TestGlobStringToRegexp(t *testing.T) {
|
||||
{`***`, ``, `too many stars`},
|
||||
{`ab]c`, ``, `mismatched ']'`},
|
||||
{`ab[c`, ``, `mismatched '[' and ']'`},
|
||||
{`ab{x{cd`, ``, `can't nest`},
|
||||
{`ab{x{cd`, ``, `mismatched '{' and '}'`},
|
||||
{`ab{}}cd`, ``, `mismatched '{' and '}'`},
|
||||
{`ab}c`, ``, `mismatched '{' and '}'`},
|
||||
{`ab{c`, ``, `mismatched '{' and '}'`},
|
||||
@@ -92,6 +94,8 @@ func TestGlobPathToRegexp(t *testing.T) {
|
||||
{`'.' '+' '(' ')' '|' '^' '$'`, `(^|/)'\.' '\+' '\(' '\)' '\|' '\^' '\$'$`, ``},
|
||||
{`*.jpg`, `(^|/)[^/]*\.jpg$`, ``},
|
||||
{`a{b,c,d}e`, `(^|/)a(b|c|d)e$`, ``},
|
||||
{`a{b,{c,d}}e`, `(^|/)a(b|(c|d))e$`, ``},
|
||||
{`{a,b/{c,d}/**}`, `(^|/)(a|b/(c|d)/.*)$`, ``},
|
||||
{`potato**`, `(^|/)potato.*$`, ``},
|
||||
{`potato**sausage`, `(^|/)potato.*sausage$`, ``},
|
||||
{`*.p[lm]`, `(^|/)[^/]*\.p[lm]$`, ``},
|
||||
@@ -100,7 +104,7 @@ func TestGlobPathToRegexp(t *testing.T) {
|
||||
{`***`, ``, `too many stars`},
|
||||
{`ab]c`, ``, `mismatched ']'`},
|
||||
{`ab[c`, ``, `mismatched '[' and ']'`},
|
||||
{`ab{x{cd`, ``, `can't nest`},
|
||||
{`ab{x{cd`, ``, `mismatched '{' and '}'`},
|
||||
{`ab{}}cd`, ``, `mismatched '{' and '}'`},
|
||||
{`ab}c`, ``, `mismatched '{' and '}'`},
|
||||
{`ab{c`, ``, `mismatched '{' and '}'`},
|
||||
@@ -158,6 +162,7 @@ func TestGlobToDirGlobs(t *testing.T) {
|
||||
{`a/b`, []string{"a/"}},
|
||||
{`a/b/*.{jpg,png,gif}`, []string{"a/b/", "a/"}},
|
||||
{`/a/{jpg,png,gif}/*.{jpg,png,gif}`, []string{"/a/{jpg,png,gif}/", "/a/", "/"}},
|
||||
{`a/{b,{c,d}}/*.jpg`, []string{"/**"}},
|
||||
{`a/{a,a*b,a**c}/d/`, []string{"/**"}},
|
||||
{`/a/{a,a*b,a/c,d}/d/`, []string{"/**"}},
|
||||
{`/a/{{.*}}/d/`, []string{"/**"}},
|
||||
|
||||
Reference in New Issue
Block a user