mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
Fix Processed images count regression for multiple languages
Fixes #11002
This commit is contained in:
parent
43f1282e73
commit
fd099331ec
8 changed files with 83 additions and 24 deletions
5
deps/deps.go
vendored
5
deps/deps.go
vendored
|
@ -189,10 +189,13 @@ func (d *Deps) Init() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
var common *resources.SpecCommon
|
var common *resources.SpecCommon
|
||||||
|
var imageCache *resources.ImageCache
|
||||||
if d.ResourceSpec != nil {
|
if d.ResourceSpec != nil {
|
||||||
common = d.ResourceSpec.SpecCommon
|
common = d.ResourceSpec.SpecCommon
|
||||||
|
imageCache = d.ResourceSpec.ImageCache
|
||||||
}
|
}
|
||||||
resourceSpec, err := resources.NewSpec(d.PathSpec, common, d.BuildState, d.Log, d, d.ExecHelper)
|
|
||||||
|
resourceSpec, err := resources.NewSpec(d.PathSpec, common, imageCache, d.BuildState, d.Log, d, d.ExecHelper)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create resource spec: %w", err)
|
return fmt.Errorf("failed to create resource spec: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -370,12 +370,15 @@ var commonTestScriptsParam = testscript.Params{
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSetupFunc() func(env *testscript.Env) error {
|
func testSetupFunc() func(env *testscript.Env) error {
|
||||||
|
sourceDir, _ := os.Getwd()
|
||||||
return func(env *testscript.Env) error {
|
return func(env *testscript.Env) error {
|
||||||
var keyVals []string
|
var keyVals []string
|
||||||
keyVals = append(keyVals, "HUGO_TESTRUN", "true")
|
keyVals = append(keyVals, "HUGO_TESTRUN", "true")
|
||||||
hugoCachedDir := filepath.Join(env.WorkDir, "hugocache")
|
hugoCachedDir := filepath.Join(env.WorkDir, "hugocache")
|
||||||
keyVals = append(keyVals, "HUGO_CACHEDIR", hugoCachedDir)
|
keyVals = append(keyVals, "HUGO_CACHEDIR", hugoCachedDir)
|
||||||
|
|
||||||
|
keyVals = append(keyVals, "SOURCE", sourceDir)
|
||||||
|
|
||||||
goVersion := runtime.Version()
|
goVersion := runtime.Version()
|
||||||
// Strip all but the major and minor version.
|
// Strip all but the major and minor version.
|
||||||
goVersion = regexp.MustCompile(`^go(\d+\.\d+)`).FindStringSubmatch(goVersion)[1]
|
goVersion = regexp.MustCompile(`^go(\d+\.\d+)`).FindStringSubmatch(goVersion)[1]
|
||||||
|
|
|
@ -126,7 +126,7 @@ func (i *imageResource) getExif() *exif.ExifInfo {
|
||||||
return enc.Encode(i.meta)
|
return enc.Encode(i.meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, i.metaInitErr = i.getSpec().imageCache.fileCache.ReadOrCreate(key, read, create)
|
_, i.metaInitErr = i.getSpec().ImageCache.fileCache.ReadOrCreate(key, read, create)
|
||||||
})
|
})
|
||||||
|
|
||||||
if i.metaInitErr != nil {
|
if i.metaInitErr != nil {
|
||||||
|
@ -296,7 +296,7 @@ const imageProcWorkers = 1
|
||||||
var imageProcSem = make(chan bool, imageProcWorkers)
|
var imageProcSem = make(chan bool, imageProcWorkers)
|
||||||
|
|
||||||
func (i *imageResource) doWithImageConfig(conf images.ImageConfig, f func(src image.Image) (image.Image, error)) (images.ImageResource, error) {
|
func (i *imageResource) doWithImageConfig(conf images.ImageConfig, f func(src image.Image) (image.Image, error)) (images.ImageResource, error) {
|
||||||
img, err := i.getSpec().imageCache.getOrCreate(i, conf, func() (*imageResource, image.Image, error) {
|
img, err := i.getSpec().ImageCache.getOrCreate(i, conf, func() (*imageResource, image.Image, error) {
|
||||||
imageProcSem <- true
|
imageProcSem <- true
|
||||||
defer func() {
|
defer func() {
|
||||||
<-imageProcSem
|
<-imageProcSem
|
||||||
|
|
|
@ -26,16 +26,27 @@ import (
|
||||||
"github.com/gohugoio/hugo/helpers"
|
"github.com/gohugoio/hugo/helpers"
|
||||||
)
|
)
|
||||||
|
|
||||||
type imageCache struct {
|
// ImageCache is a cache for image resources. The backing caches are shared between all sites.
|
||||||
|
type ImageCache struct {
|
||||||
pathSpec *helpers.PathSpec
|
pathSpec *helpers.PathSpec
|
||||||
|
|
||||||
fileCache *filecache.Cache
|
fileCache *filecache.Cache
|
||||||
|
|
||||||
|
*imageCacheStore
|
||||||
|
}
|
||||||
|
|
||||||
|
type imageCacheStore struct {
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
store map[string]*resourceAdapter
|
store map[string]*resourceAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *imageCache) deleteIfContains(s string) {
|
// WithPathSpec returns a copy of the ImageCache with the given PathSpec set.
|
||||||
|
func (c ImageCache) WithPathSpec(ps *helpers.PathSpec) *ImageCache {
|
||||||
|
c.pathSpec = ps
|
||||||
|
return &c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ImageCache) deleteIfContains(s string) {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
defer c.mu.Unlock()
|
defer c.mu.Unlock()
|
||||||
s = c.normalizeKeyBase(s)
|
s = c.normalizeKeyBase(s)
|
||||||
|
@ -48,21 +59,21 @@ func (c *imageCache) deleteIfContains(s string) {
|
||||||
|
|
||||||
// The cache key is a lowercase path with Unix style slashes and it always starts with
|
// The cache key is a lowercase path with Unix style slashes and it always starts with
|
||||||
// a leading slash.
|
// a leading slash.
|
||||||
func (c *imageCache) normalizeKey(key string) string {
|
func (c *ImageCache) normalizeKey(key string) string {
|
||||||
return "/" + c.normalizeKeyBase(key)
|
return "/" + c.normalizeKeyBase(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *imageCache) normalizeKeyBase(key string) string {
|
func (c *ImageCache) normalizeKeyBase(key string) string {
|
||||||
return strings.Trim(strings.ToLower(filepath.ToSlash(key)), "/")
|
return strings.Trim(strings.ToLower(filepath.ToSlash(key)), "/")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *imageCache) clear() {
|
func (c *ImageCache) clear() {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
defer c.mu.Unlock()
|
defer c.mu.Unlock()
|
||||||
c.store = make(map[string]*resourceAdapter)
|
c.store = make(map[string]*resourceAdapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *imageCache) getOrCreate(
|
func (c *ImageCache) getOrCreate(
|
||||||
parent *imageResource, conf images.ImageConfig,
|
parent *imageResource, conf images.ImageConfig,
|
||||||
createImage func() (*imageResource, image.Image, error)) (*resourceAdapter, error) {
|
createImage func() (*imageResource, image.Image, error)) (*resourceAdapter, error) {
|
||||||
relTarget := parent.relTargetPathFromConfig(conf)
|
relTarget := parent.relTargetPathFromConfig(conf)
|
||||||
|
@ -163,6 +174,6 @@ func (c *imageCache) getOrCreate(
|
||||||
return imgAdapter, nil
|
return imgAdapter, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newImageCache(fileCache *filecache.Cache, ps *helpers.PathSpec) *imageCache {
|
func newImageCache(fileCache *filecache.Cache, ps *helpers.PathSpec) *ImageCache {
|
||||||
return &imageCache{fileCache: fileCache, pathSpec: ps, store: make(map[string]*resourceAdapter)}
|
return &ImageCache{fileCache: fileCache, pathSpec: ps, imageCacheStore: &imageCacheStore{store: make(map[string]*resourceAdapter)}}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ import (
|
||||||
func NewSpec(
|
func NewSpec(
|
||||||
s *helpers.PathSpec,
|
s *helpers.PathSpec,
|
||||||
common *SpecCommon, // may be nil
|
common *SpecCommon, // may be nil
|
||||||
|
imageCache *ImageCache, // may be nil
|
||||||
incr identity.Incrementer,
|
incr identity.Incrementer,
|
||||||
logger loggers.Logger,
|
logger loggers.Logger,
|
||||||
errorHandler herrors.ErrorSender,
|
errorHandler herrors.ErrorSender,
|
||||||
|
@ -90,11 +91,6 @@ func NewSpec(
|
||||||
PostProcessResources: make(map[string]postpub.PostPublishedResource),
|
PostProcessResources: make(map[string]postpub.PostPublishedResource),
|
||||||
JSConfigBuilder: jsconfig.NewBuilder(),
|
JSConfigBuilder: jsconfig.NewBuilder(),
|
||||||
},
|
},
|
||||||
imageCache: newImageCache(
|
|
||||||
fileCaches.ImageCache(),
|
|
||||||
|
|
||||||
s,
|
|
||||||
),
|
|
||||||
ResourceCache: &ResourceCache{
|
ResourceCache: &ResourceCache{
|
||||||
fileCache: fileCaches.AssetsCache(),
|
fileCache: fileCaches.AssetsCache(),
|
||||||
cache: make(map[string]any),
|
cache: make(map[string]any),
|
||||||
|
@ -103,11 +99,22 @@ func NewSpec(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if imageCache == nil {
|
||||||
|
imageCache = newImageCache(
|
||||||
|
fileCaches.ImageCache(),
|
||||||
|
s,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
imageCache = imageCache.WithPathSpec(s)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
rs := &Spec{
|
rs := &Spec{
|
||||||
PathSpec: s,
|
PathSpec: s,
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
ErrorSender: errorHandler,
|
ErrorSender: errorHandler,
|
||||||
imaging: imaging,
|
imaging: imaging,
|
||||||
|
ImageCache: imageCache,
|
||||||
ExecHelper: execHelper,
|
ExecHelper: execHelper,
|
||||||
|
|
||||||
Permalinks: permalinks,
|
Permalinks: permalinks,
|
||||||
|
@ -128,6 +135,8 @@ type Spec struct {
|
||||||
|
|
||||||
Permalinks page.PermalinkExpander
|
Permalinks page.PermalinkExpander
|
||||||
|
|
||||||
|
ImageCache *ImageCache
|
||||||
|
|
||||||
// Holds default filter settings etc.
|
// Holds default filter settings etc.
|
||||||
imaging *images.ImageProcessor
|
imaging *images.ImageProcessor
|
||||||
|
|
||||||
|
@ -139,7 +148,6 @@ type Spec struct {
|
||||||
// The parts of Spec that's comoon for all sites.
|
// The parts of Spec that's comoon for all sites.
|
||||||
type SpecCommon struct {
|
type SpecCommon struct {
|
||||||
incr identity.Incrementer
|
incr identity.Incrementer
|
||||||
imageCache *imageCache
|
|
||||||
ResourceCache *ResourceCache
|
ResourceCache *ResourceCache
|
||||||
FileCaches filecache.Caches
|
FileCaches filecache.Caches
|
||||||
|
|
||||||
|
@ -171,13 +179,13 @@ func (r *Spec) BuildConfig() config.BuildConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Spec) CacheStats() string {
|
func (r *Spec) CacheStats() string {
|
||||||
r.imageCache.mu.RLock()
|
r.ImageCache.mu.RLock()
|
||||||
defer r.imageCache.mu.RUnlock()
|
defer r.ImageCache.mu.RUnlock()
|
||||||
|
|
||||||
s := fmt.Sprintf("Cache entries: %d", len(r.imageCache.store))
|
s := fmt.Sprintf("Cache entries: %d", len(r.ImageCache.store))
|
||||||
|
|
||||||
count := 0
|
count := 0
|
||||||
for k := range r.imageCache.store {
|
for k := range r.ImageCache.store {
|
||||||
if count > 5 {
|
if count > 5 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -189,12 +197,12 @@ func (r *Spec) CacheStats() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Spec) ClearCaches() {
|
func (r *Spec) ClearCaches() {
|
||||||
r.imageCache.clear()
|
r.ImageCache.clear()
|
||||||
r.ResourceCache.clear()
|
r.ResourceCache.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Spec) DeleteBySubstring(s string) {
|
func (r *Spec) DeleteBySubstring(s string) {
|
||||||
r.imageCache.deleteIfContains(s)
|
r.ImageCache.deleteIfContains(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Spec) String() string {
|
func (s *Spec) String() string {
|
||||||
|
|
|
@ -43,7 +43,7 @@ func NewTestResourceSpec() (*resources.Spec, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
spec, err := resources.NewSpec(s, nil, nil, nil, nil, nil)
|
spec, err := resources.NewSpec(s, nil, nil, nil, nil, nil, nil)
|
||||||
return spec, err
|
return spec, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
BIN
resources/testdata/pix.gif
vendored
Normal file
BIN
resources/testdata/pix.gif
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 42 B |
34
testscripts/commands/hugo__processingstats.txt
Normal file
34
testscripts/commands/hugo__processingstats.txt
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
cp $SOURCE/resources/testdata/pix.gif content/en/bundle1/pix.gif
|
||||||
|
cp $SOURCE/resources/testdata/pix.gif content/en/bundle2/pix.gif
|
||||||
|
cp $SOURCE/resources/testdata/pix.gif content/fr/bundle1/pix.gif
|
||||||
|
|
||||||
|
hugo
|
||||||
|
|
||||||
|
stdout 'Pages.*3.*2'
|
||||||
|
stdout 'Processed images.*2.*1'
|
||||||
|
|
||||||
|
-- content/en/bundle1/index.md --
|
||||||
|
-- content/en/bundle2/index.md --
|
||||||
|
-- content/fr/bundle1/index.md --
|
||||||
|
-- hugo.toml --
|
||||||
|
disableKinds = ["taxonomy", "term", "RSS", "sitemap", "robotsTXT", "404"]
|
||||||
|
baseURL = "https://example.com/"
|
||||||
|
[languages]
|
||||||
|
[languages.en]
|
||||||
|
languageName = "English"
|
||||||
|
weight = 1
|
||||||
|
title = "English Title"
|
||||||
|
contentDir = "content/en"
|
||||||
|
[languages.fr]
|
||||||
|
languageName = "French"
|
||||||
|
weight = 2
|
||||||
|
title = "French Title"
|
||||||
|
contentDir = "content/fr"
|
||||||
|
-- layouts/index.html --
|
||||||
|
Home.
|
||||||
|
-- layouts/_default/single.html --
|
||||||
|
Single.
|
||||||
|
{{ range .Resources }}
|
||||||
|
{{ $img := .Resize "3x" }}
|
||||||
|
Resized: {{ $img.RelPermalink }}
|
||||||
|
{{ end }}
|
Loading…
Reference in a new issue