]> git.maquefel.me Git - brevno-suite/hugo/commitdiff
Consolidate the glob case logic
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Fri, 23 Sep 2022 11:54:09 +0000 (13:54 +0200)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Fri, 23 Sep 2022 14:19:21 +0000 (16:19 +0200)
Looking at the code as a whole, we ended up with a little to much "buttons". It turns out that doing case insensitive matching (lower both pattern and strings to match) performs just fine. Or at least, it
gives the penalty to the people who uses mixed case filenames.

```
GetGlob/Default_cache-10                          10.6ns ± 2%    10.6ns ± 1%   ~     (p=0.657 n=4+4)
GetGlob/Filenames_cache,_lowercase_searchs-10     10.6ns ± 2%    10.6ns ± 0%   ~     (p=1.000 n=4+4)
GetGlob/Filenames_cache,_mixed_case_searchs-10    29.7ns ± 1%    29.6ns ± 1%   ~     (p=0.886 n=4+4)
GetGlob/GetGlob-10                                13.7ns ± 1%    13.7ns ± 0%   ~     (p=0.429 n=4+4)

name                                            old alloc/op   new alloc/op   delta
GetGlob/Default_cache-10                           0.00B          0.00B        ~     (all equal)
GetGlob/Filenames_cache,_lowercase_searchs-10      0.00B          0.00B        ~     (all equal)
GetGlob/Filenames_cache,_mixed_case_searchs-10     5.00B ± 0%     5.00B ± 0%   ~     (all equal)
GetGlob/GetGlob-10                                 0.00B          0.00B        ~     (all equal)

name                                            old allocs/op  new allocs/op  delta
GetGlob/Default_cache-10                            0.00           0.00        ~     (all equal)
GetGlob/Filenames_cache,_lowercase_searchs-10       0.00           0.00        ~     (all equal)
GetGlob/Filenames_cache,_mixed_case_searchs-10      1.00 ± 0%      1.00 ± 0%   ~     (all equal)
GetGlob/GetGlob-10
```

hugofs/glob.go
hugofs/glob/filename_filter.go
hugofs/glob/filename_filter_test.go
hugofs/glob/glob.go
hugofs/glob/glob_test.go
hugofs/glob_test.go
resources/resource_factories/create/create.go

index e691cdc10545c0ccff4f4c3733bce9f2adda202e..1b649a283610609535b4a5bb9e5ac5da7ed47532 100644 (file)
@@ -26,19 +26,20 @@ import (
 // Glob walks the fs and passes all matches to the handle func.
 // The handle func can return true to signal a stop.
 func Glob(fs afero.Fs, pattern string, handle func(fi FileMetaInfo) (bool, error)) error {
-       pattern = glob.NormalizePathCaseSensitive(pattern)
+       pattern = glob.NormalizePathNoLower(pattern)
        if pattern == "" {
                return nil
        }
+       root := glob.ResolveRootDir(pattern)
+       pattern = strings.ToLower(pattern)
 
-       g, err := glob.GetFilenamesGlob(pattern)
+       g, err := glob.GetGlob(pattern)
        if err != nil {
                return err
        }
 
        hasSuperAsterisk := strings.Contains(pattern, "**")
        levels := strings.Count(pattern, "/")
-       root := glob.ResolveRootDir(pattern)
 
        // Signals that we're done.
        done := errors.New("done")
index c4b582bd5c5a916bf1dd1785a6d1dbcde9f3dd3c..8e8af554ba4e318439a8249706fda81b04c01c30 100644 (file)
@@ -49,7 +49,7 @@ func NewFilenameFilter(inclusions, exclusions []string) (*FilenameFilter, error)
 
        for _, include := range inclusions {
                include = normalizeFilenameGlobPattern(include)
-               g, err := filenamesGlobCache.GetGlob(include)
+               g, err := GetGlob(include)
                if err != nil {
                        return nil, err
                }
@@ -60,9 +60,9 @@ func NewFilenameFilter(inclusions, exclusions []string) (*FilenameFilter, error)
                // gets included.
                dir := path.Dir(include)
                parts := strings.Split(dir, "/")
-               for i, _ := range parts {
+               for i := range parts {
                        pattern := "/" + filepath.Join(parts[:i+1]...)
-                       g, err := filenamesGlobCache.GetGlob(pattern)
+                       g, err := GetGlob(pattern)
                        if err != nil {
                                return nil, err
                        }
@@ -72,7 +72,7 @@ func NewFilenameFilter(inclusions, exclusions []string) (*FilenameFilter, error)
 
        for _, exclude := range exclusions {
                exclude = normalizeFilenameGlobPattern(exclude)
-               g, err := filenamesGlobCache.GetGlob(exclude)
+               g, err := GetGlob(exclude)
                if err != nil {
                        return nil, err
                }
index 1fce5b135efc956c042ad04f6ef1684f895cb9c7..b74982ef3b1cd9e97949037d0515ac8fb955cfcd 100644 (file)
@@ -42,6 +42,11 @@ func TestFilenameFilter(t *testing.T) {
        c.Assert(excludeAllButFooJSON.Match(filepath.FromSlash("/a/b/"), true), qt.Equals, true)
        c.Assert(excludeAllButFooJSON.Match(filepath.FromSlash("/"), true), qt.Equals, true)
        c.Assert(excludeAllButFooJSON.Match(filepath.FromSlash("/b"), true), qt.Equals, false)
+
+       excludeAllButFooJSONMixedCasePattern, err := NewFilenameFilter([]string{"/**/Foo.json"}, nil)
+       c.Assert(excludeAllButFooJSONMixedCasePattern.Match(filepath.FromSlash("/a/b/c/d/e/foo.json"), false), qt.Equals, true)
+       c.Assert(excludeAllButFooJSONMixedCasePattern.Match(filepath.FromSlash("/a/b/c/d/e/FOO.json"), false), qt.Equals, true)
+
        c.Assert(err, qt.IsNil)
 
        nopFilter, err := NewFilenameFilter(nil, nil)
index 87619802e6f2ebdb1408b8db6127a1463b3ed418..841824bcc3ba932fe22f4f07cf5d1c211d2d0c92 100644 (file)
@@ -33,11 +33,6 @@ var (
                isWindows: isWindows,
                cache:     make(map[string]globErr),
        }
-
-       filenamesGlobCache = &globCache{
-               isWindows: isWindows,
-               cache:     make(map[string]globErr),
-       }
 )
 
 type globErr struct {
@@ -86,10 +81,6 @@ func (gc *globCache) GetGlob(pattern string) (glob.Glob, error) {
 }
 
 type globDecorator struct {
-       // Whether both pattern and the strings to match will be matched
-       // by their original case.
-       isCaseSensitive bool
-
        // On Windows we may get filenames with Windows slashes to match,
        // which wee need to normalize.
        isWindows bool
@@ -101,14 +92,12 @@ func (g globDecorator) Match(s string) bool {
        if g.isWindows {
                s = filepath.ToSlash(s)
        }
-       if !g.isCaseSensitive {
-               s = strings.ToLower(s)
-       }
+       s = strings.ToLower(s)
        return g.g.Match(s)
 }
 
 type globDecoratorDouble struct {
-       lowerCase   glob.Glob
+       lowerCase    glob.Glob
        originalCase glob.Glob
 }
 
@@ -120,34 +109,11 @@ func GetGlob(pattern string) (glob.Glob, error) {
        return defaultGlobCache.GetGlob(pattern)
 }
 
-func GetFilenamesGlob(pattern string) (glob.Glob, error) {
-       lowered := strings.ToLower(pattern)
-       hasUpperCase := pattern != lowered
-       gLowered, err := filenamesGlobCache.GetGlob(lowered)
-       if err != nil {
-               return nil, err
-       }
-
-       if !hasUpperCase {
-               return gLowered, nil
-       }
-
-       gSensitive, err := filenamesGlobCache.GetGlob(pattern)
-       if err != nil {
-               return nil, err
-       }
-       return globDecoratorDouble{
-               lowerCase:   gLowered,
-               originalCase: gSensitive,
-       }, nil
-
-}
-
 func NormalizePath(p string) string {
-       return strings.Trim(path.Clean(filepath.ToSlash(strings.ToLower(p))), "/.")
+       return strings.ToLower(NormalizePathNoLower(p))
 }
 
-func NormalizePathCaseSensitive(p string) string {
+func NormalizePathNoLower(p string) string {
        return strings.Trim(path.Clean(filepath.ToSlash(p)), "/.")
 }
 
index 66efe9e53cf22366ca2c2cbfa12bd05a1c3b9d73..d40e16edce749cd2f74d4079f4b47c7d09526f38 100644 (file)
@@ -66,7 +66,7 @@ func TestNormalizePath(t *testing.T) {
 }
 
 func TestGetGlob(t *testing.T) {
-       for _, cache := range []*globCache{defaultGlobCache, filenamesGlobCache} {
+       for _, cache := range []*globCache{defaultGlobCache} {
                c := qt.New(t)
                g, err := cache.GetGlob("**.JSON")
                c.Assert(err, qt.IsNil)
@@ -89,8 +89,8 @@ func BenchmarkGetGlob(b *testing.B) {
        }
 
        runBench("Default cache", defaultGlobCache, "abcde")
-       runBench("Filenames cache, lowercase searchs", filenamesGlobCache, "abcde")
-       runBench("Filenames cache, mixed case searchs", filenamesGlobCache, "abCDe")
+       runBench("Filenames cache, lowercase searchs", defaultGlobCache, "abcde")
+       runBench("Filenames cache, mixed case searchs", defaultGlobCache, "abCDe")
 
        b.Run("GetGlob", func(b *testing.B) {
                for i := 0; i < b.N; i++ {
index fbb276445d4d973e6c05b1ed783ec8162624cac7..a6ae85fc8031595375bbee93dafce52455d97a86 100644 (file)
@@ -52,14 +52,16 @@ func TestGlob(t *testing.T) {
        create("UPPER/sub/style.css")
        create("root/UPPER/sub/style.css")
 
+       c.Assert(collect(filepath.FromSlash("/jsonfiles/*.json")), qt.HasLen, 2)
+
        c.Assert(collect("**.json"), qt.HasLen, 5)
        c.Assert(collect("**"), qt.HasLen, 8)
        c.Assert(collect(""), qt.HasLen, 0)
        c.Assert(collect("jsonfiles/*.json"), qt.HasLen, 2)
        c.Assert(collect("*.json"), qt.HasLen, 1)
        c.Assert(collect("**.xml"), qt.HasLen, 1)
-       c.Assert(collect(filepath.FromSlash("/jsonfiles/*.json")), qt.HasLen, 2)
-       c.Assert(collect("UPPER/sub/style.css"), qt.HasLen, 1)
+
        c.Assert(collect("root/UPPER/sub/style.css"), qt.HasLen, 1)
+       c.Assert(collect("UPPER/sub/style.css"), qt.HasLen, 1)
 
 }
index 508c141f6b1a32d9dcd63d59938d20bc8d34be4c..075d257362bd6eeaa39dc3115581fc0e6f833c81 100644 (file)
@@ -93,7 +93,7 @@ func (c *Client) GetMatch(pattern string) (resource.Resource, error) {
 }
 
 func (c *Client) match(name, pattern string, matchFunc func(r resource.Resource) bool, firstOnly bool) (resource.Resources, error) {
-       pattern = glob.NormalizePathCaseSensitive(pattern)
+       pattern = glob.NormalizePath(pattern)
        partitions := glob.FilterGlobParts(strings.Split(pattern, "/"))
        if len(partitions) == 0 {
                partitions = []string{resources.CACHE_OTHER}