shithub: hugo

Download patch

ref: 9442937d82005b369780edcc557e0d15d6bf0bad
parent: 901077c0364eaf3fe4f997c3026aa18cfc7781ed
author: Bjørn Erik Pedersen <[email protected]>
date: Fri Sep 6 05:28:43 EDT 2019

Avoid writing the same processed image to /public twice

Fixes #6307

--- a/hugolib/image_test.go
+++ b/hugolib/image_test.go
@@ -211,4 +211,7 @@
 	b.AssertFileContent("resources/_gen/images/sunset_17701188623491591036.json",
 		"DateTimeDigitized|time.Time", "PENTAX")
 
+	// TODO(bep) add this as a default assertion after Build()?
+	b.AssertNoDuplicateWrites()
+
 }
--- a/hugolib/testhelpers_test.go
+++ b/hugolib/testhelpers_test.go
@@ -486,6 +486,8 @@
 		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
@@ -678,6 +680,12 @@
 	cfg, err := jpeg.DecodeConfig(f)
 	s.Assert(cfg.Width, qt.Equals, width)
 	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 {
--- a/resources/resource.go
+++ b/resources/resource.go
@@ -233,19 +233,26 @@
 }
 
 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 @@
 	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) {
 
-	// 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
+	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
+			}
+
+			changedFilenames = append(changedFilenames, targetFilename)
 		}
-		changedFilenames = append(changedFilenames, targetFilename)
-	}
 
-	if len(changedFilenames) == 0 {
-		return nil, nil
-	}
+		if len(changedFilenames) == 0 {
+			return
+		}
 
-	return helpers.OpenFilesForWriting(l.getSpec().BaseFs.PublishFs, changedFilenames...)
+		w, err = helpers.OpenFilesForWriting(l.getSpec().BaseFs.PublishFs, changedFilenames...)
+
+	})
+
+	return
+
 }
 
 func (r *genericResource) openPublishFileForWriting(relTargetPath string) (io.WriteCloser, error) {
@@ -524,6 +539,8 @@
 type resourceContent struct {
 	content     string
 	contentInit sync.Once
+
+	publishInit sync.Once
 }
 
 type resourceFileInfo struct {