Skip to content

Commit f0eecc6

Browse files
committed
Fix non-ASCII path handling for Page resources
Fixes #4241
1 parent 768ec5d commit f0eecc6

File tree

7 files changed

+65
-33
lines changed

7 files changed

+65
-33
lines changed

‎hugolib/page.go‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,9 +228,9 @@ type Page struct {
228228
permalink string
229229
relPermalink string
230230

231-
// relPermalink without extension and any base path element from the baseURL.
231+
// relative target path without extension and any base path element from the baseURL.
232232
// This is used to construct paths in the page resources.
233-
relPermalinkBase string
233+
relTargetPathBase string
234234

235235
layoutDescriptor output.LayoutDescriptor
236236

@@ -989,8 +989,8 @@ func (p *Page) RelPermalink() string {
989989
return p.relPermalink
990990
}
991991

992-
func (p *Page) subResourceLinkFactory(base string) string {
993-
return path.Join(p.relPermalinkBase, base)
992+
func (p *Page) subResourceTargetPathFactory(base string) string {
993+
return path.Join(p.relTargetPathBase, base)
994994
}
995995

996996
func (p *Page) prepareForRender(cfg *BuildCfg) error {

‎hugolib/page_bundler_capture_test.go‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ D:
144144
__bundle/en/work/base/_index.md/resources/en/work/base/_1.png
145145
__bundle/en/work/base/a/b/index.md/resources/en/work/base/a/b/ab1.md
146146
__bundle/en/work/base/b/index.md/resources/en/work/base/b/1.md|en/work/base/b/2.md|en/work/base/b/c/logo.png|en/work/base/b/custom-mime.bep|en/work/base/b/sunset1.jpg|en/work/base/b/sunset2.jpg
147+
__bundle/en/work/base/c/index.md/resources/en/work/base/c/logo-은행.png
147148
C:
148149
/work/base/assets/pic1.png
149150
/work/base/assets/pic2.png

‎hugolib/page_bundler_handlers.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ func (c *contentHandlers) createResource() contentHandler {
319319
}
320320

321321
resource, err := c.s.resourceSpec.NewResourceFromFilename(
322-
ctx.parentPage.subResourceLinkFactory,
322+
ctx.parentPage.subResourceTargetPathFactory,
323323
c.s.absPublishDir(),
324324
ctx.source.Filename(), ctx.target)
325325

‎hugolib/page_bundler_test.go‎

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ func TestPageBundlerSite(t *testing.T) {
5151
cfg.Set("permalinks", map[string]string{
5252
"a": ":sections/:filename",
5353
"b": ":year/:slug/",
54+
"c": ":sections/:slug",
5455
})
5556

5657
cfg.Set("outputFormats", map[string]interface{}{
@@ -74,7 +75,7 @@ func TestPageBundlerSite(t *testing.T) {
7475
th := testHelper{s.Cfg, s.Fs, t}
7576

7677
// Singles (2), Below home (1), Bundle (1)
77-
assert.Len(s.RegularPages, 6)
78+
assert.Len(s.RegularPages, 7)
7879

7980
singlePage := s.getPage(KindPage, "a/1.md")
8081

@@ -99,6 +100,8 @@ func TestPageBundlerSite(t *testing.T) {
99100
assert.NotNil(leafBundle1)
100101
leafBundle2 := s.getPage(KindPage, "a/b/index.md")
101102
assert.NotNil(leafBundle2)
103+
unicodeBundle := s.getPage(KindPage, "c/index.md")
104+
assert.NotNil(unicodeBundle)
102105

103106
pageResources := leafBundle1.Resources.ByType(pageResourceType)
104107
assert.Len(pageResources, 2)
@@ -136,12 +139,18 @@ func TestPageBundlerSite(t *testing.T) {
136139

137140
assert.Equal("/a/b.html", leafBundle2.RelPermalink())
138141

142+
// 은행
143+
assert.Equal("/c/%EC%9D%80%ED%96%89.html", unicodeBundle.RelPermalink())
144+
th.assertFileContent(filepath.FromSlash("/work/public/c/은행.html"), "Content for 은행")
145+
th.assertFileContent(filepath.FromSlash("/work/public/c/은행/logo-은행.png"), "은행 PNG")
146+
139147
} else {
140148
assert.Equal("/2017/pageslug/", leafBundle1.RelPermalink())
141149
th.assertFileContent(filepath.FromSlash("/work/public/2017/pageslug/index.html"), "TheContent")
142150
th.assertFileContent(filepath.FromSlash("/work/public/cpath/2017/pageslug/cindex.html"), "TheContent")
143151

144152
assert.Equal("/a/b/", leafBundle2.RelPermalink())
153+
145154
}
146155

147156
})
@@ -261,6 +270,18 @@ Short Thumb Width: {{ $thumb.Width }}
261270
writeSource(t, fs, filepath.Join(workDir, "base", "b", "custom-mime.bep"), "bepsays")
262271
writeSource(t, fs, filepath.Join(workDir, "base", "b", "c", "logo.png"), "content")
263272

273+
// Bundle with 은행 slug
274+
// See https://github.com/gohugoio/hugo/issues/4241
275+
writeSource(t, fs, filepath.Join(workDir, "base", "c", "index.md"), `---
276+
title: "은행 은행"
277+
slug: 은행
278+
date: 2017-10-09
279+
---
280+
281+
Content for 은행.
282+
`)
283+
writeSource(t, fs, filepath.Join(workDir, "base", "c", "logo-은행.png"), "은행 PNG")
284+
264285
// Write a real image into one of the bundle above.
265286
src, err := os.Open("testdata/sunset.jpg")
266287
assert.NoError(err)

‎hugolib/page_paths.go‎

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ func (p *Page) initURLs() error {
129129
if len(p.outputFormats) == 0 {
130130
p.outputFormats = p.s.outputFormats[p.Kind]
131131
}
132-
rel := p.createRelativePermalink()
132+
target := filepath.ToSlash(p.createRelativeTargetPath())
133+
rel := p.s.PathSpec.URLizeFilename(target)
133134

134135
var err error
135136
f := p.outputFormats[0]
@@ -138,7 +139,7 @@ func (p *Page) initURLs() error {
138139
return err
139140
}
140141

141-
p.relPermalinkBase = strings.TrimSuffix(rel, f.MediaType.FullSuffix())
142+
p.relTargetPathBase = strings.TrimSuffix(target, f.MediaType.FullSuffix())
142143
p.relPermalink = p.s.PathSpec.PrependBasePath(rel)
143144
p.layoutDescriptor = p.createLayoutDescriptor()
144145
return nil
@@ -267,7 +268,7 @@ func createTargetPath(d targetPathDescriptor) string {
267268
return d.PathSpec.MakePathSanitized(pagePath)
268269
}
269270

270-
func (p *Page) createRelativePermalink() string {
271+
func (p *Page) createRelativeTargetPath() string {
271272

272273
if len(p.outputFormats) == 0 {
273274
if p.Kind == kindUnknown {
@@ -279,11 +280,15 @@ func (p *Page) createRelativePermalink() string {
279280
// Choose the main output format. In most cases, this will be HTML.
280281
f := p.outputFormats[0]
281282

282-
return p.createRelativePermalinkForOutputFormat(f)
283+
return p.createRelativeTargetPathForOutputFormat(f)
283284

284285
}
285286

286287
func (p *Page) createRelativePermalinkForOutputFormat(f output.Format) string {
288+
return p.s.PathSpec.URLizeFilename(p.createRelativeTargetPathForOutputFormat(f))
289+
}
290+
291+
func (p *Page) createRelativeTargetPathForOutputFormat(f output.Format) string {
287292
tp, err := p.createTargetPath(f, p.s.owner.IsMultihost())
288293

289294
if err != nil {
@@ -296,7 +301,7 @@ func (p *Page) createRelativePermalinkForOutputFormat(f output.Format) string {
296301
tp = strings.TrimSuffix(tp, f.BaseFilename())
297302
}
298303

299-
return p.s.PathSpec.URLizeFilename(tp)
304+
return tp
300305
}
301306

302307
func (p *Page) TargetPath() (outfile string) {

‎resource/image.go‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ type imageConfig struct {
185185
}
186186

187187
func (i *Image) isJPEG() bool {
188-
name := strings.ToLower(i.rel)
188+
name := strings.ToLower(i.relTargetPath)
189189
return strings.HasSuffix(name, ".jpg") || strings.HasSuffix(name, ".jpeg")
190190
}
191191

@@ -206,7 +206,7 @@ func (i *Image) doWithImageConfig(action, spec string, f func(src image.Image, c
206206
conf.Filter = imageFilters[conf.FilterStr]
207207
}
208208

209-
key := i.relPermalinkForRel(i.filenameFromConfig(conf), false)
209+
key := i.relTargetPathForRel(i.filenameFromConfig(conf), false)
210210

211211
return i.spec.imageCache.getOrCreate(i.spec, key, func(resourceCacheFilename string) (*Image, error) {
212212
ci := i.clone()
@@ -521,11 +521,11 @@ func (i *Image) clone() *Image {
521521
}
522522

523523
func (i *Image) setBasePath(conf imageConfig) {
524-
i.rel = i.filenameFromConfig(conf)
524+
i.relTargetPath = i.filenameFromConfig(conf)
525525
}
526526

527527
func (i *Image) filenameFromConfig(conf imageConfig) string {
528-
p1, p2 := helpers.FileAndExt(i.rel)
528+
p1, p2 := helpers.FileAndExt(i.relTargetPath)
529529
idStr := fmt.Sprintf("_hu%s_%d", i.hash, i.osFileInfo.Size())
530530

531531
// Do not change for no good reason.

‎resource/resource.go‎

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -112,27 +112,28 @@ func NewSpec(s *helpers.PathSpec, mimeTypes media.Types) (*Spec, error) {
112112
}
113113

114114
func (r *Spec) NewResourceFromFile(
115-
linker func(base string) string,
115+
targetPathBuilder func(base string) string,
116116
absPublishDir string,
117117
file source.File, relTargetFilename string) (Resource, error) {
118118

119-
return r.newResource(linker, absPublishDir, file.Filename(), file.FileInfo(), relTargetFilename)
119+
return r.newResource(targetPathBuilder, absPublishDir, file.Filename(), file.FileInfo(), relTargetFilename)
120120
}
121121

122+
// p.s.PathSpec.URLizeFilename
122123
func (r *Spec) NewResourceFromFilename(
123-
linker func(base string) string,
124+
targetPathBuilder func(base string) string,
124125
absPublishDir,
125126
absSourceFilename, relTargetFilename string) (Resource, error) {
126127

127128
fi, err := r.Fs.Source.Stat(absSourceFilename)
128129
if err != nil {
129130
return nil, err
130131
}
131-
return r.newResource(linker, absPublishDir, absSourceFilename, fi, relTargetFilename)
132+
return r.newResource(targetPathBuilder, absPublishDir, absSourceFilename, fi, relTargetFilename)
132133
}
133134

134135
func (r *Spec) newResource(
135-
linker func(base string) string,
136+
targetPathBuilder func(base string) string,
136137
absPublishDir,
137138
absSourceFilename string, fi os.FileInfo, relTargetFilename string) (Resource, error) {
138139

@@ -150,7 +151,7 @@ func (r *Spec) newResource(
150151
}
151152
}
152153

153-
gr := r.newGenericResource(linker, fi, absPublishDir, absSourceFilename, filepath.ToSlash(relTargetFilename), mimeType)
154+
gr := r.newGenericResource(targetPathBuilder, fi, absPublishDir, absSourceFilename, filepath.ToSlash(relTargetFilename), mimeType)
154155

155156
if mimeType == "image" {
156157
f, err := r.Fs.Source.Open(absSourceFilename)
@@ -203,7 +204,7 @@ func (r *Spec) CacheStats() string {
203204
// genericResource represents a generic linkable resource.
204205
type genericResource struct {
205206
// The relative path to this resource.
206-
rel string
207+
relTargetPath string
207208

208209
// Base is set when the output format's path has a offset, e.g. for AMP.
209210
base string
@@ -214,16 +215,16 @@ type genericResource struct {
214215
resourceType string
215216
osFileInfo os.FileInfo
216217

217-
spec *Spec
218-
link func(rel string) string
218+
spec *Spec
219+
targetPathBuilder func(rel string) string
219220
}
220221

221222
func (l *genericResource) Permalink() string {
222-
return l.spec.PermalinkForBaseURL(l.relPermalinkForRel(l.rel, false), l.spec.BaseURL.String())
223+
return l.spec.PermalinkForBaseURL(l.relPermalinkForRel(l.relTargetPath, false), l.spec.BaseURL.String())
223224
}
224225

225226
func (l *genericResource) RelPermalink() string {
226-
return l.relPermalinkForRel(l.rel, true)
227+
return l.relPermalinkForRel(l.relTargetPath, true)
227228
}
228229

229230
// Implement the Cloner interface.
@@ -233,8 +234,12 @@ func (l genericResource) WithNewBase(base string) Resource {
233234
}
234235

235236
func (l *genericResource) relPermalinkForRel(rel string, addBasePath bool) string {
236-
if l.link != nil {
237-
rel = l.link(rel)
237+
return l.spec.PathSpec.URLizeFilename(l.relTargetPathForRel(rel, addBasePath))
238+
}
239+
240+
func (l *genericResource) relTargetPathForRel(rel string, addBasePath bool) string {
241+
if l.targetPathBuilder != nil {
242+
rel = l.targetPathBuilder(rel)
238243
}
239244

240245
if l.base != "" {
@@ -249,7 +254,7 @@ func (l *genericResource) relPermalinkForRel(rel string, addBasePath bool) strin
249254
rel = "/" + rel
250255
}
251256

252-
return l.spec.PathSpec.URLizeFilename(rel)
257+
return rel
253258
}
254259

255260
func (l *genericResource) ResourceType() string {
@@ -273,27 +278,27 @@ func (l *genericResource) Publish() error {
273278
}
274279

275280
func (l *genericResource) target() string {
276-
target := l.relPermalinkForRel(l.rel, false)
281+
target := l.relTargetPathForRel(l.relTargetPath, false)
277282
if l.spec.PathSpec.Languages.IsMultihost() {
278283
target = path.Join(l.spec.PathSpec.Language.Lang, target)
279284
}
280285
return target
281286
}
282287

283288
func (r *Spec) newGenericResource(
284-
linker func(base string) string,
289+
targetPathBuilder func(base string) string,
285290
osFileInfo os.FileInfo,
286291
absPublishDir,
287292
absSourceFilename,
288293
baseFilename,
289294
resourceType string) *genericResource {
290295

291296
return &genericResource{
292-
link: linker,
297+
targetPathBuilder: targetPathBuilder,
293298
osFileInfo: osFileInfo,
294299
absPublishDir: absPublishDir,
295300
absSourceFilename: absSourceFilename,
296-
rel: baseFilename,
301+
relTargetPath: baseFilename,
297302
resourceType: resourceType,
298303
spec: r,
299304
}

0 commit comments

Comments
 (0)