ref: 43f9df0194d229805d80b13c9e38a7a0fec12cf4
parent: 1021714449a05ef85b2fdfaf65b354cbdee44f23
author: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
date: Fri Dec 21 05:05:57 EST 2018
Prevent resource publishing for transformed inline resources That is, if only `.Content` is accessed. This means that, for a transformed resource to be published to `/public`, you need to access either `.RelPermalink` or `Permalink`. Fixes #4944
--- a/hugolib/resource_chain_test.go
+++ b/hugolib/resource_chain_test.go
@@ -168,6 +168,8 @@
func TestResourceChain(t *testing.T) {t.Parallel()
+ assert := require.New(t)
+
tests := []struct {name string
shouldRun func() bool
@@ -199,7 +201,7 @@
b.AssertFileContent("public/index.html", `T5 RelPermalink: /sass/styles3.css|`) b.AssertFileContent("public/index.html", `T6: http://example.com/styles/bundle1.css`)- b.AssertFileContent("public/styles/templ.min.css", `.home{color:blue}`)+ assert.False(b.CheckExists("public/styles/templ.min.css")) b.AssertFileContent("public/styles/bundle1.css", `.home{color:blue}body{color:#333}`)}},
@@ -311,6 +313,30 @@
}, func(b *sitesBuilder) { b.AssertFileContent("public/index.html", `T1: https://example.com/hugo/rocks/hugo.txt|/hugo/rocks/hugo.txt`)+ }},
+
+ // https://github.com/gohugoio/hugo/issues/4944
+ {"Prevent resource publish on .Content only", func() bool { return true }, func(b *sitesBuilder) {+ b.WithTemplates("home.html", `+{{ $cssInline := "body { color: green; }" | resources.FromString "inline.css" | minify }}+{{ $cssPublish1 := "body { color: blue; }" | resources.FromString "external1.css" | minify }}+{{ $cssPublish2 := "body { color: orange; }" | resources.FromString "external2.css" | minify }}+
+Inline: {{ $cssInline.Content }}+Publish 1: {{ $cssPublish1.Content }} {{ $cssPublish1.RelPermalink }}+Publish 2: {{ $cssPublish2.Permalink }}+`)
+
+ }, func(b *sitesBuilder) {+ b.AssertFileContent("public/index.html",+ `Inline: body{color:green}`,+ "Publish 1: body{color:blue} /external1.min.css",+ "Publish 2: http://example.com/external2.min.css",
+ )
+ assert.True(b.CheckExists("public/external2.min.css"), "Referenced content should be copied to /public")+ assert.True(b.CheckExists("public/external1.min.css"), "Referenced content should be copied to /public")+
+ assert.False(b.CheckExists("public/inline.min.css"), "Inline content should not be copied to /public")}},
{"template", func() bool { return true }, func(b *sitesBuilder) {}, func(b *sitesBuilder) {--- a/resource/transform.go
+++ b/resource/transform.go
@@ -183,6 +183,11 @@
transformInit sync.Once
transformErr error
+ // We delay publishing until either .RelPermalink or .Permalink
+ // is invoked.
+ publishInit sync.Once
+ published bool
+
// The transformed values
content string
contentInit sync.Once
@@ -220,7 +225,7 @@
}
func (r *transformedResource) Content() (interface{}, error) {- if err := r.initTransform(true); err != nil {+ if err := r.initTransform(true, false); err != nil {return nil, err
}
if err := r.initContent(); err != nil {@@ -230,7 +235,7 @@
}
func (r *transformedResource) Data() interface{} {- if err := r.initTransform(false); err != nil {+ if err := r.initTransform(false, false); err != nil {return noData
}
return r.MetaData
@@ -237,7 +242,7 @@
}
func (r *transformedResource) MediaType() media.Type {- if err := r.initTransform(false); err != nil {+ if err := r.initTransform(false, false); err != nil { return media.Type{}}
m, _ := r.cache.rs.MediaTypes.GetByType(r.MediaTypeV)
@@ -245,7 +250,7 @@
}
func (r *transformedResource) Permalink() string {- if err := r.initTransform(false); err != nil {+ if err := r.initTransform(false, true); err != nil {return ""
}
return r.linker.permalinkFor(r.Target)
@@ -252,7 +257,7 @@
}
func (r *transformedResource) RelPermalink() string {- if err := r.initTransform(false); err != nil {+ if err := r.initTransform(false, true); err != nil {return ""
}
return r.linker.relPermalinkFor(r.Target)
@@ -271,11 +276,11 @@
return err
}
-func (r *transformedResource) transform(setContent bool) (err error) {+func (r *transformedResource) openPublishFileForWriting(relTargetPath string) (io.WriteCloser, error) {+ return helpers.OpenFilesForWriting(r.cache.rs.PublishFs, r.linker.relTargetPathsFor(relTargetPath)...)
+}
- openPublishFileForWriting := func(relTargetPath string) (io.WriteCloser, error) {- return helpers.OpenFilesForWriting(r.cache.rs.PublishFs, r.linker.relTargetPathsFor(relTargetPath)...)
- }
+func (r *transformedResource) transform(setContent, publish bool) (err error) {// This can be the last resource in a chain.
// Rewind and create a processing chain.
@@ -345,7 +350,7 @@
tctx := &ResourceTransformationCtx{Data: r.transformedResourceMetadata.MetaData,
- OpenResourcePublisher: openPublishFileForWriting,
+ OpenResourcePublisher: r.openPublishFileForWriting,
}
tctx.InMediaType = first.MediaType()
@@ -426,15 +431,19 @@
r.MediaTypeV = tctx.OutMediaType.Type()
}
- publicw, err := openPublishFileForWriting(r.Target)
- if err != nil {- r.transformErr = err
- return
- }
- defer publicw.Close()
+ var publishwriters []io.WriteCloser
- publishwriters := []io.WriteCloser{publicw}+ if publish {+ publicw, err := r.openPublishFileForWriting(r.Target)
+ if err != nil {+ r.transformErr = err
+ return err
+ }
+ defer publicw.Close()
+ publishwriters = append(publishwriters, publicw)
+ }
+
if transformedContentr == nil {// Also write it to the cache
fi, metaw, err := r.cache.writeMeta(key, r.transformedResourceMetadata)
@@ -474,13 +483,49 @@
return nil
}
-func (r *transformedResource) initTransform(setContent bool) error {+func (r *transformedResource) initTransform(setContent, publish bool) error { r.transformInit.Do(func() {- if err := r.transform(setContent); err != nil {+ r.published = publish
+ if err := r.transform(setContent, publish); err != nil {r.transformErr = err
r.cache.rs.Logger.ERROR.Println("error: failed to transform resource:", err)}
+
})
+
+ if !publish {+ return r.transformErr
+ }
+
+ r.publishInit.Do(func() {+ if r.published {+ return
+ }
+
+ r.published = true
+
+ // Copy the file from cache to /public
+ _, src, err := r.cache.fileCache.Get(r.sourceFilename)
+
+ if err == nil {+ defer src.Close()
+
+ var dst io.WriteCloser
+ dst, err = r.openPublishFileForWriting(r.Target)
+ if err == nil {+ defer dst.Close()
+ io.Copy(dst, src)
+ }
+ }
+
+ if err != nil {+ r.transformErr = err
+ r.cache.rs.Logger.ERROR.Println("error: failed to publish resource:", err)+ return
+ }
+
+ })
+
return r.transformErr
}
--
⑨