Avoid writing the same processed image to /public twice
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Fri, 6 Sep 2019 07:28:43 +0000 (09:28 +0200)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Fri, 6 Sep 2019 09:04:57 +0000 (11:04 +0200)
Fixes #6307

hugolib/image_test.go
hugolib/testhelpers_test.go
resources/resource.go

index 4db57e4a5a5954430d5fee843ec6bedfbb008a43..a13338afc0f86b81f6b6d70613b4c1305e12529c 100644 (file)
@@ -211,4 +211,7 @@ SUNSET2: {{ $resized2.RelPermalink }}/{{ $resized2.Width }}/Lat: {{ $resized2.Ex
        b.AssertFileContent("resources/_gen/images/sunset_17701188623491591036.json",
                "DateTimeDigitized|time.Time", "PENTAX")
 
+       // TODO(bep) add this as a default assertion after Build()?
+       b.AssertNoDuplicateWrites()
+
 }
index 6e62a24427ac60f597fbbe49d1b38b1222289b18..6e00a8ee02d71f4431f01a2de5c21f7b564b8f59 100644 (file)
@@ -486,6 +486,8 @@ func (s *sitesBuilder) CreateSitesE() error {
                return errors.Wrap(err, "failed to load config")
        }
 
+       s.Fs.Destination = hugofs.NewCreateCountingFs(s.Fs.Destination)
+
        depsCfg := s.depsCfg
        depsCfg.Fs = s.Fs
        depsCfg.Cfg = s.Cfg
@@ -680,6 +682,12 @@ func (s *sitesBuilder) AssertImage(width, height int, filename string) {
        s.Assert(cfg.Height, qt.Equals, height)
 }
 
+func (s *sitesBuilder) AssertNoDuplicateWrites() {
+       s.Helper()
+       d := s.Fs.Destination.(hugofs.DuplicatesReporter)
+       s.Assert(d.ReportDuplicates(), qt.Equals, "")
+}
+
 func (s *sitesBuilder) FileContent(filename string) string {
        s.T.Helper()
        filename = filepath.FromSlash(filename)
index 637f8e8fd7339960b2d8333120bb0a432d3830fb..7e755bdbcce61d34c4ea42fdbbd30dbdc385d92a 100644 (file)
@@ -233,19 +233,26 @@ func (l *genericResource) Permalink() string {
 }
 
 func (l *genericResource) Publish() error {
-       fr, err := l.ReadSeekCloser()
-       if err != nil {
-               return err
-       }
-       defer fr.Close()
+       var err error
+       l.publishInit.Do(func() {
+               var fr hugio.ReadSeekCloser
+               fr, err = l.ReadSeekCloser()
+               if err != nil {
+                       return
+               }
+               defer fr.Close()
 
-       fw, err := helpers.OpenFilesForWriting(l.spec.BaseFs.PublishFs, l.getTargetFilenames()...)
-       if err != nil {
-               return err
-       }
-       defer fw.Close()
+               var fw io.WriteCloser
+               fw, err = helpers.OpenFilesForWriting(l.spec.BaseFs.PublishFs, l.getTargetFilenames()...)
+               if err != nil {
+                       return
+               }
+               defer fw.Close()
+
+               _, err = io.Copy(fw, fr)
+
+       })
 
-       _, err = io.Copy(fw, fr)
        return err
 }
 
@@ -400,26 +407,34 @@ func (l genericResource) clone() *genericResource {
        return &l
 }
 
-// returns an opened file or nil if nothing to write.
-func (l *genericResource) openDestinationsForWriting() (io.WriteCloser, error) {
-       targetFilenames := l.getTargetFilenames()
-       var changedFilenames []string
+// returns an opened file or nil if nothing to write (it may already be published).
+func (l *genericResource) openDestinationsForWriting() (w io.WriteCloser, err error) {
+
+       l.publishInit.Do(func() {
+               targetFilenames := l.getTargetFilenames()
+               var changedFilenames []string
+
+               // Fast path:
+               // This is a processed version of the original;
+               // check if it already existis at the destination.
+               for _, targetFilename := range targetFilenames {
+                       if _, err := l.getSpec().BaseFs.PublishFs.Stat(targetFilename); err == nil {
+                               continue
+                       }
 
-       // Fast path:
-       // This is a processed version of the original;
-       // check if it already existis at the destination.
-       for _, targetFilename := range targetFilenames {
-               if _, err := l.getSpec().BaseFs.PublishFs.Stat(targetFilename); err == nil {
-                       continue
+                       changedFilenames = append(changedFilenames, targetFilename)
                }
-               changedFilenames = append(changedFilenames, targetFilename)
-       }
 
-       if len(changedFilenames) == 0 {
-               return nil, nil
-       }
+               if len(changedFilenames) == 0 {
+                       return
+               }
+
+               w, err = helpers.OpenFilesForWriting(l.getSpec().BaseFs.PublishFs, changedFilenames...)
+
+       })
+
+       return
 
-       return helpers.OpenFilesForWriting(l.getSpec().BaseFs.PublishFs, changedFilenames...)
 }
 
 func (r *genericResource) openPublishFileForWriting(relTargetPath string) (io.WriteCloser, error) {
@@ -524,6 +539,8 @@ type permalinker interface {
 type resourceContent struct {
        content     string
        contentInit sync.Once
+
+       publishInit sync.Once
 }
 
 type resourceFileInfo struct {