mirror of
https://github.com/gohugoio/hugo.git
synced 2025-08-25 22:00:58 +02:00
@@ -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
|
||||
|
||||
}
|
@@ -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
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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) {
|
||||
|
@@ -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")
|
||||
}
|
||||
|
Reference in New Issue
Block a user