Skip to content

Commit 0bfd2fd

Browse files
committed
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 gohugoio#13164
1 parent ec0caae commit 0bfd2fd

File tree

4 files changed

+48
-27
lines changed

4 files changed

+48
-27
lines changed

hugofs/rootmapping_fs.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -311,12 +311,13 @@ func (fs *RootMappingFs) Open(name string) (afero.File, error) {
311311

312312
// Stat returns the os.FileInfo structure describing a given file. If there is
313313
// an error, it will be of type *os.PathError.
314+
// If multiple roots are found, the last one will be used.
314315
func (fs *RootMappingFs) Stat(name string) (os.FileInfo, error) {
315316
fis, err := fs.doStat(name)
316317
if err != nil {
317318
return nil, err
318319
}
319-
return fis[0], nil
320+
return fis[len(fis)-1], nil
320321
}
321322

322323
type ComponentPath struct {

resources/resource_cache.go

+12
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ func newResourceCache(rs *Spec, memCache *dynacache.Cache) *ResourceCache {
3636
"/res1",
3737
dynacache.OptionsPartition{ClearWhen: dynacache.ClearOnChange, Weight: 40},
3838
),
39+
cacheResourceFile: dynacache.GetOrCreatePartition[string, resource.Resource](
40+
memCache,
41+
"/res2",
42+
dynacache.OptionsPartition{ClearWhen: dynacache.ClearOnChange, Weight: 40},
43+
),
3944
CacheResourceRemote: dynacache.GetOrCreatePartition[string, resource.Resource](
4045
memCache,
4146
"/resr",
@@ -58,6 +63,7 @@ type ResourceCache struct {
5863
sync.RWMutex
5964

6065
cacheResource *dynacache.Partition[string, resource.Resource]
66+
cacheResourceFile *dynacache.Partition[string, resource.Resource]
6167
CacheResourceRemote *dynacache.Partition[string, resource.Resource]
6268
cacheResources *dynacache.Partition[string, resource.Resources]
6369
cacheResourceTransformation *dynacache.Partition[string, *resourceAdapterInner]
@@ -79,6 +85,12 @@ func (c *ResourceCache) GetOrCreate(key string, f func() (resource.Resource, err
7985
})
8086
}
8187

88+
func (c *ResourceCache) GetOrCreateFile(key string, f func() (resource.Resource, error)) (resource.Resource, error) {
89+
return c.cacheResourceFile.GetOrCreate(key, func(key string) (resource.Resource, error) {
90+
return f()
91+
})
92+
}
93+
8294
func (c *ResourceCache) GetOrCreateResources(key string, f func() (resource.Resources, error)) (resource.Resources, error) {
8395
return c.cacheResources.GetOrCreate(key, func(key string) (resource.Resources, error) {
8496
return f()

resources/resource_factories/create/create.go

+19-26
Original file line numberDiff line numberDiff line change
@@ -143,19 +143,7 @@ func (c *Client) Get(pathname string) (resource.Resource, error) {
143143
return nil, err
144144
}
145145

146-
meta := fi.(hugofs.FileMetaInfo).Meta()
147-
pi := meta.PathInfo
148-
149-
return c.rs.NewResource(resources.ResourceSourceDescriptor{
150-
LazyPublish: true,
151-
OpenReadSeekCloser: func() (hugio.ReadSeekCloser, error) {
152-
return c.rs.BaseFs.Assets.Fs.Open(filename)
153-
},
154-
Path: pi,
155-
GroupIdentity: pi,
156-
TargetPath: pathname,
157-
SourceFilenameOrPath: meta.Filename,
158-
})
146+
return c.getOrCreateFileResource(fi.(hugofs.FileMetaInfo))
159147
})
160148
}
161149

@@ -181,6 +169,23 @@ func (c *Client) GetMatch(pattern string) (resource.Resource, error) {
181169
return res[0], err
182170
}
183171

172+
func (c *Client) getOrCreateFileResource(info hugofs.FileMetaInfo) (resource.Resource, error) {
173+
meta := info.Meta()
174+
return c.rs.ResourceCache.GetOrCreateFile(filepath.ToSlash(meta.Filename), func() (resource.Resource, error) {
175+
return c.rs.NewResource(resources.ResourceSourceDescriptor{
176+
LazyPublish: true,
177+
OpenReadSeekCloser: func() (hugio.ReadSeekCloser, error) {
178+
return meta.Open()
179+
},
180+
NameNormalized: meta.PathInfo.Path(),
181+
NameOriginal: meta.PathInfo.Unnormalized().Path(),
182+
GroupIdentity: meta.PathInfo,
183+
TargetPath: meta.PathInfo.Unnormalized().Path(),
184+
SourceFilenameOrPath: meta.Filename,
185+
})
186+
})
187+
}
188+
184189
func (c *Client) match(name, pattern string, matchFunc func(r resource.Resource) bool, firstOnly bool) (resource.Resources, error) {
185190
pattern = glob.NormalizePath(pattern)
186191
partitions := glob.FilterGlobParts(strings.Split(pattern, "/"))
@@ -191,19 +196,7 @@ func (c *Client) match(name, pattern string, matchFunc func(r resource.Resource)
191196
var res resource.Resources
192197

193198
handle := func(info hugofs.FileMetaInfo) (bool, error) {
194-
meta := info.Meta()
195-
196-
r, err := c.rs.NewResource(resources.ResourceSourceDescriptor{
197-
LazyPublish: true,
198-
OpenReadSeekCloser: func() (hugio.ReadSeekCloser, error) {
199-
return meta.Open()
200-
},
201-
NameNormalized: meta.PathInfo.Path(),
202-
NameOriginal: meta.PathInfo.Unnormalized().Path(),
203-
GroupIdentity: meta.PathInfo,
204-
TargetPath: meta.PathInfo.Unnormalized().Path(),
205-
SourceFilenameOrPath: meta.Filename,
206-
})
199+
r, err := c.getOrCreateFileResource(info)
207200
if err != nil {
208201
return true, err
209202
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
hugo --printPathWarnings
2+
3+
! stderr 'Duplicate target paths'
4+
5+
-- hugo.toml --
6+
disableKinds = ['page','rss','section','sitemap','taxonomy','term']
7+
-- assets/foo.txt --
8+
foo
9+
-- layouts/index.html --
10+
A: {{ (resources.Get "foo.txt").RelPermalink }}
11+
B: {{ (resources.GetMatch "foo.txt").RelPermalink }}
12+
C: {{ (index (resources.Match "foo.txt") 0).RelPermalink }}
13+
D: {{ (index (resources.ByType "text") 0).RelPermalink }}
14+
-- layouts/unused/single.html --
15+
{{ .Title }}

0 commit comments

Comments
 (0)