From da9faf1ffea2c13be9258b30d0f3c3ab0f310015 Mon Sep 17 00:00:00 2001 From: albertony <12441419+albertony@users.noreply.github.com> Date: Sat, 10 Aug 2024 17:41:12 +0200 Subject: [PATCH] Make filtering rules for help and listremotes more lenient --- cmd/help.go | 2 +- cmd/listremotes/listremotes.go | 2 +- fs/filter/glob.go | 14 +++++- fs/filter/glob_test.go | 92 +++++++--------------------------- 4 files changed, 33 insertions(+), 77 deletions(-) diff --git a/cmd/help.go b/cmd/help.go index 010f65bf9..94f399793 100644 --- a/cmd/help.go +++ b/cmd/help.go @@ -74,7 +74,7 @@ var helpFlags = &cobra.Command{ Root.SetUsageTemplate(docFlagsTemplate) } else { if len(args) > 0 { - re, err := filter.GlobStringToRegexp(args[0], false) + re, err := filter.GlobStringToRegexp(args[0], false, true) if err != nil { log.Fatalf("Invalid flag filter: %v", err) } diff --git a/cmd/listremotes/listremotes.go b/cmd/listremotes/listremotes.go index 416157b11..4f3bf2128 100644 --- a/cmd/listremotes/listremotes.go +++ b/cmd/listremotes/listremotes.go @@ -146,7 +146,7 @@ according to regular rclone filtering pattern syntax. "description": filterDescription, } { if v != "" { - filterRe, err := filter.GlobStringToRegexp(v, false) + filterRe, err := filter.GlobStringToRegexp(v, false, true) if err != nil { return fmt.Errorf("invalid %s filter argument: %w", k, err) } diff --git a/fs/filter/glob.go b/fs/filter/glob.go index de48da6d7..40c0c56e2 100644 --- a/fs/filter/glob.go +++ b/fs/filter/glob.go @@ -17,8 +17,18 @@ func GlobPathToRegexp(glob string, ignoreCase bool) (*regexp.Regexp, error) { } // 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 diff --git a/fs/filter/glob_test.go b/fs/filter/glob_test.go index 04a07581d..a20a77775 100644 --- a/fs/filter/glob_test.go +++ b/fs/filter/glob_test.go @@ -8,67 +8,6 @@ import ( ) 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 { in string want string @@ -111,19 +50,26 @@ func TestGlobStringToRegexpWithoutAnchors(t *testing.T) { {`{{(?i)regexp}}`, `((?i)regexp)`, ``}, } { for _, ignoreCase := range []bool{false, true} { - gotRe, err := globToRegexp(test.in, false, false, ignoreCase) - if test.error == "" { - require.NoError(t, err, test.in) - prefix := "" - if ignoreCase { - prefix = "(?i)" + for _, addAnchors := range []bool{false, true} { + gotRe, err := GlobStringToRegexp(test.in, addAnchors, ignoreCase) + if test.error == "" { + require.NoError(t, err, test.in) + prefix := "" + 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) } } }