s.Assert(s.H.init.translations.InitCount(), qt.Equals, count)
}
+func (s *IntegrationTestBuilder) AssertFileCount(dirname string, expected int) {
+ s.Helper()
+ fs := s.fs.WorkingDirReadOnly
+ count := 0
+ afero.Walk(fs, dirname, func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ if info.IsDir() {
+ return nil
+ }
+ count++
+ return nil
+ })
+ s.Assert(count, qt.Equals, expected)
+
+}
+
func (s *IntegrationTestBuilder) AssertFileContent(filename string, matches ...string) {
s.Helper()
content := strings.TrimSpace(s.FileContent(filename))
b.Assert(err.Error(), qt.Contains, `error calling Width: this method is only available for raster images. To determine if an image is SVG, you can do {{ if eq .MediaType.SubType "svg" }}{{ end }}`)
}
+
+// Issue 10255.
+func TestNoPublishOfUnusedProcessedImage(t *testing.T) {
+ t.Parallel()
+
+ workingDir := t.TempDir()
+
+ files := `
+-- assets/images/pixel.png --
+iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==
+-- layouts/index.html --
+{{ $image := resources.Get "images/pixel.png" }}
+{{ $image = $image.Resize "400x" }}
+{{ $image = $image.Resize "300x" }}
+{{ $image = $image.Resize "200x" }}
+{{ $image = $image.Resize "100x" }}
+{{ $image = $image.Crop "50x50" }}
+{{ $image = $image.Filter (images.GaussianBlur 6) }}
+{{ ($image | fingerprint).Permalink }}
+
+
+`
+
+ for i := 0; i < 3; i++ {
+
+ b := hugolib.NewIntegrationTestBuilder(
+ hugolib.IntegrationTestConfig{
+ T: t,
+ TxtarString: files,
+ NeedsOsFS: true,
+ WorkingDir: workingDir,
+ }).Build()
+
+ b.AssertFileCount("resources/_gen/images", 6)
+ b.AssertFileCount("public/images", 1)
+ b.Build()
+ }
+
+}
specProvider
getResourcePaths() *resourcePathDescriptor
getTargetFilenames() []string
- openDestinationsForWriting() (io.WriteCloser, error)
openPublishFileForWriting(relTargetPath string) (io.WriteCloser, error)
relTargetPathForRel(rel string, addBaseTargetPath, isAbs, isURL bool) string
type fileInfo interface {
getSourceFilename() string
setSourceFilename(string)
+ setSourfeFilenameIsHash(bool)
setSourceFs(afero.Fs)
getFileInfo() hugofs.FileMetaInfo
hash() (string, error)
func (l *genericResource) Publish() error {
var err error
l.publishInit.Do(func() {
+ targetFilenames := l.getTargetFilenames()
+ if l.sourceFilenameIsHash {
+ // This is a processed image. We want to avoid copying it if it hasn't changed.
+ var changedFilenames []string
+ for _, targetFilename := range targetFilenames {
+ if _, err := l.getSpec().BaseFs.PublishFs.Stat(targetFilename); err == nil {
+ continue
+ }
+ changedFilenames = append(changedFilenames, targetFilename)
+ }
+ if len(changedFilenames) == 0 {
+ return
+ }
+ targetFilenames = changedFilenames
+ }
var fr hugio.ReadSeekCloser
fr, err = l.ReadSeekCloser()
if err != nil {
defer fr.Close()
var fw io.WriteCloser
- fw, err = helpers.OpenFilesForWriting(l.spec.BaseFs.PublishFs, l.getTargetFilenames()...)
+ fw, err = helpers.OpenFilesForWriting(l.spec.BaseFs.PublishFs, targetFilenames...)
if err != nil {
return
}
return &l
}
-// 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 exists at the destination.
- for _, targetFilename := range targetFilenames {
- if _, err := l.getSpec().BaseFs.PublishFs.Stat(targetFilename); err == nil {
- continue
- }
-
- changedFilenames = append(changedFilenames, targetFilename)
- }
-
- if len(changedFilenames) == 0 {
- return
- }
-
- w, err = helpers.OpenFilesForWriting(l.getSpec().BaseFs.PublishFs, changedFilenames...)
- })
-
- return
-}
-
func (r *genericResource) openPublishFileForWriting(relTargetPath string) (io.WriteCloser, error) {
return helpers.OpenFilesForWriting(r.spec.BaseFs.PublishFs, r.relTargetPathsFor(relTargetPath)...)
}
// the path to the file on the real filesystem.
sourceFilename string
+ // For performance. This means that whenever the content changes, the filename changes.
+ sourceFilenameIsHash bool
+
fi hugofs.FileMetaInfo
// A hash of the source content. Is only calculated in caching situations.
fi.sourceFilename = s
}
+func (fi *resourceFileInfo) setSourfeFilenameIsHash(b bool) {
+ fi.sourceFilenameIsHash = b
+}
+
func (fi *resourceFileInfo) getSourceFs() afero.Fs {
return fi.sourceFs
}