Make filtering rules for help and listremotes more lenient

This commit is contained in:
albertony 2024-08-10 17:41:12 +02:00
parent 303358eeda
commit da9faf1ffe
4 changed files with 33 additions and 77 deletions

View File

@ -74,7 +74,7 @@ var helpFlags = &cobra.Command{
Root.SetUsageTemplate(docFlagsTemplate) Root.SetUsageTemplate(docFlagsTemplate)
} else { } else {
if len(args) > 0 { if len(args) > 0 {
re, err := filter.GlobStringToRegexp(args[0], false) re, err := filter.GlobStringToRegexp(args[0], false, true)
if err != nil { if err != nil {
log.Fatalf("Invalid flag filter: %v", err) log.Fatalf("Invalid flag filter: %v", err)
} }

View File

@ -146,7 +146,7 @@ according to regular rclone filtering pattern syntax.
"description": filterDescription, "description": filterDescription,
} { } {
if v != "" { if v != "" {
filterRe, err := filter.GlobStringToRegexp(v, false) filterRe, err := filter.GlobStringToRegexp(v, false, true)
if err != nil { if err != nil {
return fmt.Errorf("invalid %s filter argument: %w", k, err) return fmt.Errorf("invalid %s filter argument: %w", k, err)
} }

View File

@ -17,8 +17,18 @@ func GlobPathToRegexp(glob string, ignoreCase bool) (*regexp.Regexp, error) {
} }
// GlobStringToRegexp converts an rsync style glob string to a regexp // GlobStringToRegexp converts an rsync style glob string to a regexp
func GlobStringToRegexp(glob string, ignoreCase bool) (*regexp.Regexp, error) { //
return globToRegexp(glob, false, true, ignoreCase) // Without adding of anchors but with ignoring of case, i.e. called
// `GlobStringToRegexp(glob, false, true)`, it takes a lenient approach
// where the glob "sum" would match "CheckSum", more similar to text
// search functions than strict glob filtering.
//
// With adding of anchors and not ignoring case, i.e. called
// `GlobStringToRegexp(glob, true, false)`, it uses a strict glob
// interpretation where the previous example would have to be changed to
// "*Sum" to match "CheckSum".
func GlobStringToRegexp(glob string, addAnchors bool, ignoreCase bool) (*regexp.Regexp, error) {
return globToRegexp(glob, false, addAnchors, ignoreCase)
} }
// globToRegexp converts an rsync style glob to a regexp // globToRegexp converts an rsync style glob to a regexp

View File

@ -8,67 +8,6 @@ import (
) )
func TestGlobStringToRegexp(t *testing.T) { func TestGlobStringToRegexp(t *testing.T) {
for _, test := range []struct {
in string
want string
error string
}{
{``, `^$`, ``},
{`potato`, `^potato$`, ``},
{`potato,sausage`, `^potato,sausage$`, ``},
{`/potato`, `^/potato$`, ``},
{`potato?sausage`, `^potato.sausage$`, ``},
{`potat[oa]`, `^potat[oa]$`, ``},
{`potat[a-z]or`, `^potat[a-z]or$`, ``},
{`potat[[:alpha:]]or`, `^potat[[:alpha:]]or$`, ``},
{`'.' '+' '(' ')' '|' '^' '$'`, `^'\.' '\+' '\(' '\)' '\|' '\^' '\$'$`, ``},
{`*.jpg`, `^.*\.jpg$`, ``},
{`a{b,c,d}e`, `^a(b|c|d)e$`, ``},
{`potato**`, ``, `too many stars`},
{`potato**sausage`, ``, `too many stars`},
{`*.p[lm]`, `^.*\.p[lm]$`, ``},
{`[\[\]]`, `^[\[\]]$`, ``},
{`***potato`, ``, `too many stars`},
{`***`, ``, `too many stars`},
{`ab]c`, ``, `mismatched ']'`},
{`ab[c`, ``, `mismatched '[' and ']'`},
{`ab{x{cd`, ``, `can't nest`},
{`ab{}}cd`, ``, `mismatched '{' and '}'`},
{`ab}c`, ``, `mismatched '{' and '}'`},
{`ab{c`, ``, `mismatched '{' and '}'`},
{`*.{jpg,png,gif}`, `^.*\.(jpg|png|gif)$`, ``},
{`[a--b]`, ``, `bad glob pattern`},
{`a\*b`, `^a\*b$`, ``},
{`a\\b`, `^a\\b$`, ``},
{`a{{.*}}b`, `^a(.*)b$`, ``},
{`a{{.*}`, ``, `mismatched '{{' and '}}'`},
{`{{regexp}}`, `^(regexp)$`, ``},
{`\{{{regexp}}`, `^\{(regexp)$`, ``},
{`/{{regexp}}`, `^/(regexp)$`, ``},
{`/{{\d{8}}}`, `^/(\d{8})$`, ``},
{`/{{\}}}`, `^/(\})$`, ``},
{`{{(?i)regexp}}`, `^((?i)regexp)$`, ``},
} {
for _, ignoreCase := range []bool{false, true} {
gotRe, err := GlobStringToRegexp(test.in, ignoreCase)
if test.error == "" {
require.NoError(t, err, test.in)
prefix := ""
if ignoreCase {
prefix = "(?i)"
}
got := gotRe.String()
assert.Equal(t, prefix+test.want, got, test.in)
} else {
require.Error(t, err, test.in)
assert.Contains(t, err.Error(), test.error, test.in)
assert.Nil(t, gotRe)
}
}
}
}
func TestGlobStringToRegexpWithoutAnchors(t *testing.T) {
for _, test := range []struct { for _, test := range []struct {
in string in string
want string want string
@ -111,19 +50,26 @@ func TestGlobStringToRegexpWithoutAnchors(t *testing.T) {
{`{{(?i)regexp}}`, `((?i)regexp)`, ``}, {`{{(?i)regexp}}`, `((?i)regexp)`, ``},
} { } {
for _, ignoreCase := range []bool{false, true} { for _, ignoreCase := range []bool{false, true} {
gotRe, err := globToRegexp(test.in, false, false, ignoreCase) for _, addAnchors := range []bool{false, true} {
if test.error == "" { gotRe, err := GlobStringToRegexp(test.in, addAnchors, ignoreCase)
require.NoError(t, err, test.in) if test.error == "" {
prefix := "" require.NoError(t, err, test.in)
if ignoreCase { prefix := ""
prefix = "(?i)" suffix := ""
if ignoreCase {
prefix += "(?i)"
}
if addAnchors {
prefix += "^"
suffix += "$"
}
got := gotRe.String()
assert.Equal(t, prefix+test.want+suffix, got, test.in)
} else {
require.Error(t, err, test.in)
assert.Contains(t, err.Error(), test.error, test.in)
assert.Nil(t, gotRe)
} }
got := gotRe.String()
assert.Equal(t, prefix+test.want, got, test.in)
} else {
require.Error(t, err, test.in)
assert.Contains(t, err.Error(), test.error, test.in)
assert.Nil(t, gotRe)
} }
} }
} }