mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-14 20:37:55 -05:00
hugofs: Fix glob case-sensitivity bug
On Linux, `hugofs.Glob` does not hit any directories which includes uppercase letters. (This does not happen on macOS.) Since `resources.GetMatch/Match` uses `Glob`, ``` {{ resources.GetMatch "Foo/bar.css" }} ``` this does not match `assets/Foo/bar.css` . On the other hand, you can get it with ``` {{ resources.Get "Foo/bar.css" }} ```
This commit is contained in:
parent
f3560aa0e1
commit
281554ee97
4 changed files with 54 additions and 23 deletions
|
@ -26,14 +26,14 @@ 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.NormalizePath(pattern)
|
||||
pattern = glob.NormalizePathCaseSensitive(pattern)
|
||||
if pattern == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
g, err := glob.GetGlob(pattern)
|
||||
g, err := glob.GetFilenamesGlob(pattern)
|
||||
if err != nil {
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
hasSuperAsterisk := strings.Contains(pattern, "**")
|
||||
|
|
|
@ -30,15 +30,13 @@ const filepathSeparator = string(os.PathSeparator)
|
|||
var (
|
||||
isWindows = runtime.GOOS == "windows"
|
||||
defaultGlobCache = &globCache{
|
||||
isCaseSensitive: false,
|
||||
isWindows: isWindows,
|
||||
cache: make(map[string]globErr),
|
||||
isWindows: isWindows,
|
||||
cache: make(map[string]globErr),
|
||||
}
|
||||
|
||||
filenamesGlobCache = &globCache{
|
||||
isCaseSensitive: false, // As long as the search strings are all lower case, this does not allocate.
|
||||
isWindows: isWindows,
|
||||
cache: make(map[string]globErr),
|
||||
isWindows: isWindows,
|
||||
cache: make(map[string]globErr),
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -49,8 +47,7 @@ type globErr struct {
|
|||
|
||||
type globCache struct {
|
||||
// Config
|
||||
isCaseSensitive bool
|
||||
isWindows bool
|
||||
isWindows bool
|
||||
|
||||
// Cache
|
||||
sync.RWMutex
|
||||
|
@ -72,19 +69,12 @@ func (gc *globCache) GetGlob(pattern string) (glob.Glob, error) {
|
|||
var err error
|
||||
|
||||
pattern = filepath.ToSlash(pattern)
|
||||
|
||||
if gc.isCaseSensitive {
|
||||
g, err = glob.Compile(pattern, '/')
|
||||
} else {
|
||||
g, err = glob.Compile(strings.ToLower(pattern), '/')
|
||||
|
||||
}
|
||||
g, err = glob.Compile(strings.ToLower(pattern), '/')
|
||||
|
||||
eg = globErr{
|
||||
globDecorator{
|
||||
g: g,
|
||||
isCaseSensitive: gc.isCaseSensitive,
|
||||
isWindows: gc.isWindows},
|
||||
g: g,
|
||||
isWindows: gc.isWindows},
|
||||
err,
|
||||
}
|
||||
|
||||
|
@ -117,14 +107,50 @@ func (g globDecorator) Match(s string) bool {
|
|||
return g.g.Match(s)
|
||||
}
|
||||
|
||||
type globDecoratorDouble struct {
|
||||
lowerCase glob.Glob
|
||||
originalCase glob.Glob
|
||||
}
|
||||
|
||||
func (g globDecoratorDouble) Match(s string) bool {
|
||||
return g.lowerCase.Match(s) || g.originalCase.Match(s)
|
||||
}
|
||||
|
||||
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))), "/.")
|
||||
}
|
||||
|
||||
func NormalizePathCaseSensitive(p string) string {
|
||||
return strings.Trim(path.Clean(filepath.ToSlash(p)), "/.")
|
||||
}
|
||||
|
||||
// ResolveRootDir takes a normalized path on the form "assets/**.json" and
|
||||
// determines any root dir, i.e. any start path without any wildcards.
|
||||
func ResolveRootDir(p string) string {
|
||||
|
|
|
@ -49,12 +49,17 @@ func TestGlob(t *testing.T) {
|
|||
create("jsonfiles/sub/d3.json")
|
||||
create("jsonfiles/d1.xml")
|
||||
create("a/b/c/e/f.json")
|
||||
create("UPPER/sub/style.css")
|
||||
create("root/UPPER/sub/style.css")
|
||||
|
||||
c.Assert(collect("**.json"), qt.HasLen, 5)
|
||||
c.Assert(collect("**"), qt.HasLen, 6)
|
||||
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)
|
||||
|
||||
}
|
||||
|
|
|
@ -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.NormalizePath(pattern)
|
||||
pattern = glob.NormalizePathCaseSensitive(pattern)
|
||||
partitions := glob.FilterGlobParts(strings.Split(pattern, "/"))
|
||||
if len(partitions) == 0 {
|
||||
partitions = []string{resources.CACHE_OTHER}
|
||||
|
|
Loading…
Reference in a new issue