summaryrefslogtreecommitdiffstats
path: root/resources
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2019-08-12 16:43:37 +0200
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2019-08-13 11:44:20 +0200
commitb64617fe4f90da030bcf4a9c5a4913393ce96b14 (patch)
tree07240dbf51bb4afef9ea063f2310c1617be6bb0a /resources
parent17ca8f0c4c636752fb9da2ad551679275dc03dd3 (diff)
Add resources.Match and resources.GetMatch
Fix #6190
Diffstat (limited to 'resources')
-rw-r--r--resources/internal/glob.go48
-rw-r--r--resources/resource/resources.go6
-rw-r--r--resources/resource_cache.go28
-rw-r--r--resources/resource_factories/create/create.go68
-rw-r--r--resources/resource_metadata.go4
5 files changed, 92 insertions, 62 deletions
diff --git a/resources/internal/glob.go b/resources/internal/glob.go
deleted file mode 100644
index a87a23f13..000000000
--- a/resources/internal/glob.go
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2019 The Hugo Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package internal
-
-import (
- "strings"
- "sync"
-
- "github.com/gobwas/glob"
-)
-
-var (
- globCache = make(map[string]glob.Glob)
- globMu sync.RWMutex
-)
-
-func GetGlob(pattern string) (glob.Glob, error) {
- var g glob.Glob
-
- globMu.RLock()
- g, found := globCache[pattern]
- globMu.RUnlock()
- if !found {
- var err error
- g, err = glob.Compile(strings.ToLower(pattern), '/')
- if err != nil {
- return nil, err
- }
-
- globMu.Lock()
- globCache[pattern] = g
- globMu.Unlock()
- }
-
- return g, nil
-
-}
diff --git a/resources/resource/resources.go b/resources/resource/resources.go
index 5c661c24e..ac5dd0b2b 100644
--- a/resources/resource/resources.go
+++ b/resources/resource/resources.go
@@ -17,7 +17,7 @@ import (
"fmt"
"strings"
- "github.com/gohugoio/hugo/resources/internal"
+ "github.com/gohugoio/hugo/hugofs/glob"
)
// Resources represents a slice of resources, which can be a mix of different types.
@@ -44,7 +44,7 @@ func (r Resources) ByType(tp string) Resources {
// GetMatch finds the first Resource matching the given pattern, or nil if none found.
// See Match for a more complete explanation about the rules used.
func (r Resources) GetMatch(pattern string) Resource {
- g, err := internal.GetGlob(pattern)
+ g, err := glob.GetGlob(pattern)
if err != nil {
return nil
}
@@ -68,7 +68,7 @@ func (r Resources) GetMatch(pattern string) Resource {
// path relative to the bundle root with Unix style slashes (/) and no leading slash, e.g. "images/logo.png".
// See https://github.com/gobwas/glob for the full rules set.
func (r Resources) Match(pattern string) Resources {
- g, err := internal.GetGlob(pattern)
+ g, err := glob.GetGlob(pattern)
if err != nil {
return nil
}
diff --git a/resources/resource_cache.go b/resources/resource_cache.go
index 8ff63beb0..656d4f826 100644
--- a/resources/resource_cache.go
+++ b/resources/resource_cache.go
@@ -37,7 +37,9 @@ type ResourceCache struct {
rs *Spec
sync.RWMutex
- cache map[string]resource.Resource
+
+ // Either resource.Resource or resource.Resources.
+ cache map[string]interface{}
fileCache *filecache.Cache
@@ -61,7 +63,7 @@ func newResourceCache(rs *Spec) *ResourceCache {
return &ResourceCache{
rs: rs,
fileCache: rs.FileCaches.AssetsCache(),
- cache: make(map[string]resource.Resource),
+ cache: make(map[string]interface{}),
nlocker: locker.NewLocker(),
}
}
@@ -70,7 +72,7 @@ func (c *ResourceCache) clear() {
c.Lock()
defer c.Unlock()
- c.cache = make(map[string]resource.Resource)
+ c.cache = make(map[string]interface{})
c.nlocker = locker.NewLocker()
}
@@ -84,7 +86,7 @@ func (c *ResourceCache) cleanKey(key string) string {
return strings.TrimPrefix(path.Clean(key), "/")
}
-func (c *ResourceCache) get(key string) (resource.Resource, bool) {
+func (c *ResourceCache) get(key string) (interface{}, bool) {
c.RLock()
defer c.RUnlock()
r, found := c.cache[key]
@@ -92,6 +94,22 @@ func (c *ResourceCache) get(key string) (resource.Resource, bool) {
}
func (c *ResourceCache) GetOrCreate(partition, key string, f func() (resource.Resource, error)) (resource.Resource, error) {
+ r, err := c.getOrCreate(partition, key, func() (interface{}, error) { return f() })
+ if r == nil || err != nil {
+ return nil, err
+ }
+ return r.(resource.Resource), nil
+}
+
+func (c *ResourceCache) GetOrCreateResources(partition, key string, f func() (resource.Resources, error)) (resource.Resources, error) {
+ r, err := c.getOrCreate(partition, key, func() (interface{}, error) { return f() })
+ if r == nil || err != nil {
+ return nil, err
+ }
+ return r.(resource.Resources), nil
+}
+
+func (c *ResourceCache) getOrCreate(partition, key string, f func() (interface{}, error)) (interface{}, error) {
key = c.cleanKey(path.Join(partition, key))
// First check in-memory cache.
r, found := c.get(key)
@@ -174,7 +192,7 @@ func (c *ResourceCache) writeMeta(key string, meta transformedResourceMetadata)
}
-func (c *ResourceCache) set(key string, r resource.Resource) {
+func (c *ResourceCache) set(key string, r interface{}) {
c.Lock()
defer c.Unlock()
c.cache[key] = r
diff --git a/resources/resource_factories/create/create.go b/resources/resource_factories/create/create.go
index 36a29e733..e42843c75 100644
--- a/resources/resource_factories/create/create.go
+++ b/resources/resource_factories/create/create.go
@@ -16,9 +16,12 @@
package create
import (
+ "path"
"path/filepath"
- "github.com/spf13/afero"
+ "github.com/gohugoio/hugo/hugofs/glob"
+
+ "github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/common/hugio"
"github.com/gohugoio/hugo/resources"
@@ -36,18 +39,75 @@ func New(rs *resources.Spec) *Client {
return &Client{rs: rs}
}
-// Get creates a new Resource by opening the given filename in the given filesystem.
-func (c *Client) Get(fs afero.Fs, filename string) (resource.Resource, error) {
+// Get creates a new Resource by opening the given filename in the assets filesystem.
+func (c *Client) Get(filename string) (resource.Resource, error) {
filename = filepath.Clean(filename)
return c.rs.ResourceCache.GetOrCreate(resources.ResourceKeyPartition(filename), filename, func() (resource.Resource, error) {
return c.rs.New(resources.ResourceSourceDescriptor{
- Fs: fs,
+ Fs: c.rs.BaseFs.Assets.Fs,
LazyPublish: true,
SourceFilename: filename})
})
}
+// Match gets the resources matching the given pattern from the assets filesystem.
+func (c *Client) Match(pattern string) (resource.Resources, error) {
+ return c.match(pattern, false)
+}
+
+// GetMatch gets first resource matching the given pattern from the assets filesystem.
+func (c *Client) GetMatch(pattern string) (resource.Resource, error) {
+ res, err := c.match(pattern, true)
+ if err != nil || len(res) == 0 {
+ return nil, err
+ }
+ return res[0], err
+}
+
+func (c *Client) match(pattern string, firstOnly bool) (resource.Resources, error) {
+ var partition string
+ if firstOnly {
+ partition = "__get-match"
+ } else {
+ partition = "__match"
+ }
+
+ // TODO(bep) match will be improved as part of https://github.com/gohugoio/hugo/issues/6199
+ partition = path.Join(resources.CACHE_OTHER, partition)
+ key := glob.NormalizePath(pattern)
+
+ return c.rs.ResourceCache.GetOrCreateResources(partition, key, func() (resource.Resources, error) {
+ var res resource.Resources
+
+ handle := func(info hugofs.FileMetaInfo) (bool, error) {
+ meta := info.Meta()
+ r, err := c.rs.New(resources.ResourceSourceDescriptor{
+ LazyPublish: true,
+ OpenReadSeekCloser: func() (hugio.ReadSeekCloser, error) {
+ return meta.Open()
+ },
+ RelTargetFilename: meta.Path()})
+
+ if err != nil {
+ return true, err
+ }
+
+ res = append(res, r)
+
+ return firstOnly, nil
+
+ }
+
+ if err := hugofs.Glob(c.rs.BaseFs.Assets.Fs, pattern, handle); err != nil {
+ return nil, err
+ }
+
+ return res, nil
+
+ })
+}
+
// FromString creates a new Resource from a string with the given relative target path.
func (c *Client) FromString(targetPath, content string) (resource.Resource, error) {
return c.rs.ResourceCache.GetOrCreate(resources.CACHE_OTHER, targetPath, func() (resource.Resource, error) {
diff --git a/resources/resource_metadata.go b/resources/resource_metadata.go
index e019133d7..adb9d6867 100644
--- a/resources/resource_metadata.go
+++ b/resources/resource_metadata.go
@@ -17,7 +17,7 @@ import (
"fmt"
"strconv"
- "github.com/gohugoio/hugo/resources/internal"
+ "github.com/gohugoio/hugo/hugofs/glob"
"github.com/gohugoio/hugo/resources/resource"
"github.com/pkg/errors"
@@ -70,7 +70,7 @@ func AssignMetadata(metadata []map[string]interface{}, resources ...resource.Res
srcKey := strings.ToLower(cast.ToString(src))
- glob, err := internal.GetGlob(srcKey)
+ glob, err := glob.GetGlob(srcKey)
if err != nil {
return errors.Wrap(err, "failed to match resource with metadata")
}