diff --git a/hugolib/resource_chain_test.go b/hugolib/resource_chain_test.go index fd1ee7e5e..138e7a4a2 100644 --- a/hugolib/resource_chain_test.go +++ b/hugolib/resource_chain_test.go @@ -284,7 +284,7 @@ Edited content. } } -func TestResourceChain(t *testing.T) { +func TestResourceChains(t *testing.T) { t.Parallel() c := qt.New(t) @@ -389,6 +389,23 @@ T3: Content: {{ $combinedJs.Content }}|{{ $combinedJs.RelPermalink }} ; (function F {})()`) }}, + + {"concat and fingerprint", func() bool { return true }, func(b *sitesBuilder) { + b.WithTemplates("home.html", ` +{{ $a := "A" | resources.FromString "a.txt"}} +{{ $b := "B" | resources.FromString "b.txt"}} +{{ $c := "C" | resources.FromString "c.txt"}} +{{ $combined := slice $a $b $c | resources.Concat "bundle/concat.txt" }} +{{ $fingerprinted := $combined | fingerprint }} +Fingerprinted: {{ $fingerprinted.RelPermalink }} +`) + }, func(b *sitesBuilder) { + + b.AssertFileContent("public/index.html", "Fingerprinted: /bundle/concat.b5d4045c3f466fa91fe2cc6abe79232a1a57cdf104f7a26e716e0a1e2789df78.txt") + b.AssertFileContent("public/bundle/concat.b5d4045c3f466fa91fe2cc6abe79232a1a57cdf104f7a26e716e0a1e2789df78.txt", "ABC") + + }}, + {"fromstring", func() bool { return true }, func(b *sitesBuilder) { b.WithTemplates("home.html", ` {{ $r := "Hugo Rocks!" | resources.FromString "rocks/hugo.txt" }} diff --git a/resources/resource_factories/bundler/bundler.go b/resources/resource_factories/bundler/bundler.go index c310efa33..1ea92bea3 100644 --- a/resources/resource_factories/bundler/bundler.go +++ b/resources/resource_factories/bundler/bundler.go @@ -15,7 +15,6 @@ package bundler import ( - "bytes" "fmt" "io" "path" @@ -43,6 +42,19 @@ type multiReadSeekCloser struct { sources []hugio.ReadSeekCloser } +func toReaders(sources []hugio.ReadSeekCloser) []io.Reader { + readers := make([]io.Reader, len(sources)) + for i, r := range sources { + readers[i] = r + } + return readers +} + +func newMultiReadSeekCloser(sources ...hugio.ReadSeekCloser) *multiReadSeekCloser { + mr := io.MultiReader(toReaders(sources)...) + return &multiReadSeekCloser{mr, sources} +} + func (r *multiReadSeekCloser) Read(p []byte) (n int, err error) { return r.mr.Read(p) } @@ -54,6 +66,9 @@ func (r *multiReadSeekCloser) Seek(offset int64, whence int) (newOffset int64, e return } } + + r.mr = io.MultiReader(toReaders(r.sources)...) + return } @@ -98,31 +113,24 @@ func (c *Client) Concat(targetPath string, r resource.Resources) (resource.Resou rcsources = append(rcsources, rc) } - var readers []io.Reader - // Arbitrary JavaScript files require a barrier between them to be safely concatenated together. // Without this, the last line of one file can affect the first line of the next file and change how both files are interpreted. if resolvedm.MainType == media.JavascriptType.MainType && resolvedm.SubType == media.JavascriptType.SubType { - readers = make([]io.Reader, 2*len(rcsources)-1) + readers := make([]hugio.ReadSeekCloser, 2*len(rcsources)-1) j := 0 for i := 0; i < len(rcsources); i++ { if i > 0 { - readers[j] = bytes.NewBufferString("\n;\n") + readers[j] = hugio.NewReadSeekerNoOpCloserFromString("\n;\n") j++ } readers[j] = rcsources[i] j++ } - } else { - readers = make([]io.Reader, len(rcsources)) - for i := 0; i < len(rcsources); i++ { - readers[i] = rcsources[i] - } + return newMultiReadSeekCloser(readers...), nil } - mr := io.MultiReader(readers...) + return newMultiReadSeekCloser(rcsources...), nil - return &multiReadSeekCloser{mr: mr, sources: rcsources}, nil } composite, err := c.rs.New( diff --git a/resources/resource_factories/bundler/bundler_test.go b/resources/resource_factories/bundler/bundler_test.go new file mode 100644 index 000000000..16a5215ba --- /dev/null +++ b/resources/resource_factories/bundler/bundler_test.go @@ -0,0 +1,41 @@ +// Copyright 2019 The Hugo Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package bundler + +import ( + "testing" + + "github.com/gohugoio/hugo/helpers" + + qt "github.com/frankban/quicktest" + "github.com/gohugoio/hugo/common/hugio" +) + +func TestMultiReadSeekCloser(t *testing.T) { + c := qt.New(t) + + rc := newMultiReadSeekCloser( + hugio.NewReadSeekerNoOpCloserFromString("A"), + hugio.NewReadSeekerNoOpCloserFromString("B"), + hugio.NewReadSeekerNoOpCloserFromString("C"), + ) + + for i := 0; i < 3; i++ { + s1 := helpers.ReaderToString(rc) + c.Assert(s1, qt.Equals, "ABC") + _, err := rc.Seek(0, 0) + c.Assert(err, qt.IsNil) + } + +}