"sort"
"strconv"
"strings"
- "sync"
"sync/atomic"
"time"
}
po.renderState = 0
- po.p.resourcesPublishInit = &sync.Once{}
if r == identity.FinderFoundOneOfMany || po.f.Name == output.HTTPStatus404HTMLFormat.Name {
// Will force a re-render even in fast render mode.
po.renderOnce = false
handleChange := func(pathInfo *paths.Path, delete, isDir bool) {
switch pathInfo.Component() {
case files.ComponentFolderContent:
- logger.Println("Source changed", pathInfo.Path())
isContentDataFile := pathInfo.IsContentData()
if !isContentDataFile {
if ids := h.pageTrees.collectAndMarkStaleIdentities(pathInfo); len(ids) > 0 {
"path/filepath"
"strconv"
"strings"
- "sync"
"sync/atomic"
"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/media"
"github.com/gohugoio/hugo/output"
"github.com/gohugoio/hugo/related"
+ "github.com/gohugoio/hugo/resources"
"github.com/gohugoio/hugo/tpl/tplimpl"
"github.com/spf13/afero"
*pageCommon
resource.Staler
- dependencyManager identity.Manager
- resourcesPublishInit *sync.Once
+ dependencyManager identity.Manager
}
func (p *pageState) incrPageOutputTemplateVariation() {
}
func (p *pageState) renderResources() error {
- var initErr error
+ for _, r := range p.Resources() {
- p.resourcesPublishInit.Do(func() {
- for _, r := range p.Resources() {
- if _, ok := r.(page.Page); ok {
+ if _, ok := r.(page.Page); ok {
+ if p.s.h.buildCounter.Load() == 0 {
// Pages gets rendered with the owning page but we count them here.
p.s.PathSpec.ProcessingStats.Incr(&p.s.PathSpec.ProcessingStats.Pages)
- continue
}
+ continue
+ }
- if _, isWrapper := r.(resource.ResourceWrapper); isWrapper {
- // Skip resources that are wrapped.
- // These gets published on its own.
- continue
- }
+ if resources.IsPublished(r) {
+ continue
+ }
- src, ok := r.(resource.Source)
- if !ok {
- initErr = fmt.Errorf("resource %T does not support resource.Source", r)
- return
- }
+ if _, isWrapper := r.(resource.ResourceWrapper); isWrapper {
+ // Skip resources that are wrapped.
+ // These gets published on its own.
+ continue
+ }
- if err := src.Publish(); err != nil {
- if !herrors.IsNotExist(err) {
- p.s.Log.Errorf("Failed to publish Resource for page %q: %s", p.pathOrTitle(), err)
- }
- } else {
- p.s.PathSpec.ProcessingStats.Incr(&p.s.PathSpec.ProcessingStats.Files)
+ src, ok := r.(resource.Source)
+ if !ok {
+ return fmt.Errorf("resource %T does not support resource.Source", r)
+ }
+
+ if err := src.Publish(); err != nil {
+ if !herrors.IsNotExist(err) {
+ p.s.Log.Errorf("Failed to publish Resource for page %q: %s", p.pathOrTitle(), err)
}
+ } else {
+ p.s.PathSpec.ProcessingStats.Incr(&p.s.PathSpec.ProcessingStats.Files)
}
- })
+ }
- return initErr
+ return nil
}
func (p *pageState) AlternativeOutputFormats() page.OutputFormats {
import (
"fmt"
"strings"
- "sync"
"sync/atomic"
"github.com/gohugoio/hugo/hugofs/files"
pid: pid,
pageOutput: nopPageOutput,
pageOutputTemplateVariationsState: &atomic.Uint32{},
- resourcesPublishInit: &sync.Once{},
Staler: m,
dependencyManager: m.s.Conf.NewIdentityManager(m.Path()),
pageCommon: &pageCommon{
// But that is a harder problem to tackle.
b.AssertFileContent("public/tags/index.html", "All. Tag1|Tag2|")
}
+
+func TestRebuildEditNonReferencedResourceIssue13748(t *testing.T) {
+ t.Parallel()
+
+ files := `
+-- hugo.toml --
+baseURL = "https://example.com"
+disableLiveReload = true
+-- content/mybundle/index.md --
+-- content/mybundle/resource.txt --
+This is a resource file.
+-- layouts/all.html --
+All.
+`
+ b := TestRunning(t, files)
+
+ b.AssertFileContent("public/mybundle/resource.txt", "This is a resource file.")
+ b.EditFileReplaceAll("content/mybundle/resource.txt", "This is a resource file.", "This is an edited resource file.").Build()
+ b.AssertFileContent("public/mybundle/resource.txt", "This is an edited resource file.")
+}
"sync/atomic"
"github.com/gohugoio/hugo/identity"
+ "github.com/gohugoio/hugo/lazy"
"github.com/gohugoio/hugo/resources/internal"
"github.com/gohugoio/hugo/common/hashing"
_ identity.DependencyManagerProvider = (*genericResource)(nil)
_ identity.Identity = (*genericResource)(nil)
_ fileInfo = (*genericResource)(nil)
+ _ isPublishedProvider = (*genericResource)(nil)
)
type ResourceSourceDescriptor struct {
fileInfo
mediaTypeAssigner
targetPather
+ isPublishedProvider
ReadSeekCloser() (hugio.ReadSeekCloser, error)
// genericResource represents a generic linkable resource.
type genericResource struct {
- publishInit *sync.Once
+ publishInit *lazy.OnceMore
key string
keyInit *sync.Once
return err
}
+func (l *genericResource) isPublished() bool {
+ return l.publishInit.Done()
+}
+
func (l *genericResource) RelPermalink() string {
return l.spec.PathSpec.GetBasePath(false) + paths.PathEscape(l.paths.TargetLink())
}
}
func (l genericResource) clone() *genericResource {
- l.publishInit = &sync.Once{}
+ l.publishInit = &lazy.OnceMore{}
l.keyInit = &sync.Once{}
return &l
}
TargetPath() string
}
+type isPublishedProvider interface {
+ isPublished() bool
+}
+
type resourceHash struct {
value uint64
size int64
return InternalResourceTargetPath(r)
}
+// isPublished returns true if the resource is published.
+func IsPublished(r resource.Resource) bool {
+ return r.(isPublishedProvider).isPublished()
+}
+
type targetPathProvider interface {
// targetPath is the relative path to this resource.
// In most cases this will be the same as the RelPermalink(),
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/config/allconfig"
+ "github.com/gohugoio/hugo/lazy"
"github.com/gohugoio/hugo/output"
"github.com/gohugoio/hugo/resources/internal"
"github.com/gohugoio/hugo/resources/jsconfig"
gr := &genericResource{
Staler: &AtomicStaler{},
h: &resourceHash{},
- publishInit: &sync.Once{},
+ publishInit: &lazy.OnceMore{},
keyInit: &sync.Once{},
includeHashInKey: isImage,
paths: rp,
_ identity.DependencyManagerProvider = (*resourceAdapter)(nil)
_ identity.IdentityGroupProvider = (*resourceAdapter)(nil)
_ resource.NameNormalizedProvider = (*resourceAdapter)(nil)
+ _ isPublishedProvider = (*resourceAdapter)(nil)
)
// These are transformations that need special support in Hugo that may not
return r.target.Publish()
}
+func (r *resourceAdapter) isPublished() bool {
+ r.init(false, false)
+ return r.target.isPublished()
+}
+
func (r *resourceAdapter) ReadSeekCloser() (hugio.ReadSeekCloser, error) {
r.init(false, false)
return r.target.ReadSeekCloser()