From 77824d704c124dc43b30352a03f1fbad13e54dfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Thu, 26 Dec 2024 13:47:10 +0100 Subject: [PATCH] Fix same resource file published more than once This may still happen, though, in low memory situations or very big sites, but I'm not sure it's worth spending time on fixing that. Writing the same file more than once isn't harmful, the negative effect is the false path warning. We may find a way to detect that situation if this becomes a real problem. Fixes #13164 --- hugofs/rootmapping_fs.go | 3 +- resources/resource_cache.go | 12 +++++ resources/resource_factories/create/create.go | 45 ++++++++----------- .../hugo__path-warnings_issue13164.txt | 15 +++++++ 4 files changed, 48 insertions(+), 27 deletions(-) create mode 100644 testscripts/commands/hugo__path-warnings_issue13164.txt diff --git a/hugofs/rootmapping_fs.go b/hugofs/rootmapping_fs.go index 02e541a05..388493174 100644 --- a/hugofs/rootmapping_fs.go +++ b/hugofs/rootmapping_fs.go @@ -311,12 +311,13 @@ func (fs *RootMappingFs) Open(name string) (afero.File, error) { // Stat returns the os.FileInfo structure describing a given file. If there is // an error, it will be of type *os.PathError. +// If multiple roots are found, the last one will be used. func (fs *RootMappingFs) Stat(name string) (os.FileInfo, error) { fis, err := fs.doStat(name) if err != nil { return nil, err } - return fis[0], nil + return fis[len(fis)-1], nil } type ComponentPath struct { diff --git a/resources/resource_cache.go b/resources/resource_cache.go index a3ba9aa26..898cd4c31 100644 --- a/resources/resource_cache.go +++ b/resources/resource_cache.go @@ -36,6 +36,11 @@ func newResourceCache(rs *Spec, memCache *dynacache.Cache) *ResourceCache { "/res1", dynacache.OptionsPartition{ClearWhen: dynacache.ClearOnChange, Weight: 40}, ), + cacheResourceFile: dynacache.GetOrCreatePartition[string, resource.Resource]( + memCache, + "/res2", + dynacache.OptionsPartition{ClearWhen: dynacache.ClearOnChange, Weight: 40}, + ), CacheResourceRemote: dynacache.GetOrCreatePartition[string, resource.Resource]( memCache, "/resr", @@ -58,6 +63,7 @@ type ResourceCache struct { sync.RWMutex cacheResource *dynacache.Partition[string, resource.Resource] + cacheResourceFile *dynacache.Partition[string, resource.Resource] CacheResourceRemote *dynacache.Partition[string, resource.Resource] cacheResources *dynacache.Partition[string, resource.Resources] cacheResourceTransformation *dynacache.Partition[string, *resourceAdapterInner] @@ -79,6 +85,12 @@ func (c *ResourceCache) GetOrCreate(key string, f func() (resource.Resource, err }) } +func (c *ResourceCache) GetOrCreateFile(key string, f func() (resource.Resource, error)) (resource.Resource, error) { + return c.cacheResourceFile.GetOrCreate(key, func(key string) (resource.Resource, error) { + return f() + }) +} + func (c *ResourceCache) GetOrCreateResources(key string, f func() (resource.Resources, error)) (resource.Resources, error) { return c.cacheResources.GetOrCreate(key, func(key string) (resource.Resources, error) { return f() diff --git a/resources/resource_factories/create/create.go b/resources/resource_factories/create/create.go index 7dd26f4c0..581c0a854 100644 --- a/resources/resource_factories/create/create.go +++ b/resources/resource_factories/create/create.go @@ -143,19 +143,7 @@ func (c *Client) Get(pathname string) (resource.Resource, error) { return nil, err } - meta := fi.(hugofs.FileMetaInfo).Meta() - pi := meta.PathInfo - - return c.rs.NewResource(resources.ResourceSourceDescriptor{ - LazyPublish: true, - OpenReadSeekCloser: func() (hugio.ReadSeekCloser, error) { - return c.rs.BaseFs.Assets.Fs.Open(filename) - }, - Path: pi, - GroupIdentity: pi, - TargetPath: pathname, - SourceFilenameOrPath: meta.Filename, - }) + return c.getOrCreateFileResource(fi.(hugofs.FileMetaInfo)) }) } @@ -181,6 +169,23 @@ func (c *Client) GetMatch(pattern string) (resource.Resource, error) { return res[0], err } +func (c *Client) getOrCreateFileResource(info hugofs.FileMetaInfo) (resource.Resource, error) { + meta := info.Meta() + return c.rs.ResourceCache.GetOrCreateFile(filepath.ToSlash(meta.Filename), func() (resource.Resource, error) { + return c.rs.NewResource(resources.ResourceSourceDescriptor{ + LazyPublish: true, + OpenReadSeekCloser: func() (hugio.ReadSeekCloser, error) { + return meta.Open() + }, + NameNormalized: meta.PathInfo.Path(), + NameOriginal: meta.PathInfo.Unnormalized().Path(), + GroupIdentity: meta.PathInfo, + TargetPath: meta.PathInfo.Unnormalized().Path(), + SourceFilenameOrPath: meta.Filename, + }) + }) +} + func (c *Client) match(name, pattern string, matchFunc func(r resource.Resource) bool, firstOnly bool) (resource.Resources, error) { pattern = glob.NormalizePath(pattern) partitions := glob.FilterGlobParts(strings.Split(pattern, "/")) @@ -191,19 +196,7 @@ func (c *Client) match(name, pattern string, matchFunc func(r resource.Resource) var res resource.Resources handle := func(info hugofs.FileMetaInfo) (bool, error) { - meta := info.Meta() - - r, err := c.rs.NewResource(resources.ResourceSourceDescriptor{ - LazyPublish: true, - OpenReadSeekCloser: func() (hugio.ReadSeekCloser, error) { - return meta.Open() - }, - NameNormalized: meta.PathInfo.Path(), - NameOriginal: meta.PathInfo.Unnormalized().Path(), - GroupIdentity: meta.PathInfo, - TargetPath: meta.PathInfo.Unnormalized().Path(), - SourceFilenameOrPath: meta.Filename, - }) + r, err := c.getOrCreateFileResource(info) if err != nil { return true, err } diff --git a/testscripts/commands/hugo__path-warnings_issue13164.txt b/testscripts/commands/hugo__path-warnings_issue13164.txt new file mode 100644 index 000000000..1342c287a --- /dev/null +++ b/testscripts/commands/hugo__path-warnings_issue13164.txt @@ -0,0 +1,15 @@ +hugo --printPathWarnings + +! stderr 'Duplicate target paths' + +-- hugo.toml -- +disableKinds = ['page','rss','section','sitemap','taxonomy','term'] +-- assets/foo.txt -- +foo +-- layouts/index.html -- +A: {{ (resources.Get "foo.txt").RelPermalink }} +B: {{ (resources.GetMatch "foo.txt").RelPermalink }} +C: {{ (index (resources.Match "foo.txt") 0).RelPermalink }} +D: {{ (index (resources.ByType "text") 0).RelPermalink }} +-- layouts/unused/single.html -- +{{ .Title }}