Skip to content

Commit

Permalink
Implement defer
Browse files Browse the repository at this point in the history
  • Loading branch information
bep committed Jun 9, 2024
1 parent 1cdd3d0 commit 277bc71
Show file tree
Hide file tree
Showing 17 changed files with 543 additions and 80 deletions.
1 change: 0 additions & 1 deletion cache/httpcache/httpcache.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ func (c *Config) Compile() (ConfigCompiled, error) {
}

// PollConfig holds the configuration for polling remote resources to detect changes in watch mode.
// TODO1 make sure this enabled only in watch mode.
type PollConfig struct {
// What remote resources to apply this configuration to.
For GlobMatcher
Expand Down
3 changes: 3 additions & 0 deletions common/herrors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ func ImproveIfNilPointer(inErr error) (outErr error) {
call := m[1]
field := m[2]
parts := strings.Split(call, ".")
if len(parts) < 2 {
return
}
receiverName := parts[len(parts)-2]
receiver := strings.Join(parts[:len(parts)-1], ".")
s := fmt.Sprintf("– %s is nil; wrap it in if or with: {{ with %s }}{{ .%s }}{{ end }}", receiverName, receiver, field)
Expand Down
41 changes: 32 additions & 9 deletions common/hugio/hasBytesWriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,35 @@ import (
"bytes"
)

// HasBytesWriter is a writer that will set Match to true if the given pattern
// is found in the stream.
// HasBytesWriter is a writer will match against a slice of patterns.
type HasBytesWriter struct {
Match bool
Pattern []byte
Patterns []*HasBytesPattern

i int
done bool
buff []byte
}

type HasBytesPattern struct {
Match bool
Pattern []byte
}

func (h *HasBytesWriter) patternLen() int {
l := 0
for _, p := range h.Patterns {
l += len(p.Pattern)
}
return l
}

func (h *HasBytesWriter) Write(p []byte) (n int, err error) {
if h.done {
return len(p), nil
}

if len(h.buff) == 0 {
h.buff = make([]byte, len(h.Pattern)*2)
h.buff = make([]byte, h.patternLen()*2)
}

for i := range p {
Expand All @@ -46,11 +57,23 @@ func (h *HasBytesWriter) Write(p []byte) (n int, err error) {
h.i = len(h.buff) / 2
}

if bytes.Contains(h.buff, h.Pattern) {
h.Match = true
h.done = true
return len(p), nil
for _, pp := range h.Patterns {
if bytes.Contains(h.buff, pp.Pattern) {
pp.Match = true
done := true
for _, ppp := range h.Patterns {
if !ppp.Match {
done = false
break
}
}
if done {
h.done = true
}
return len(p), nil
}
}

}

return len(p), nil
Expand Down
13 changes: 8 additions & 5 deletions common/hugio/hasBytesWriter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@ func TestHasBytesWriter(t *testing.T) {
var b bytes.Buffer

h := &HasBytesWriter{
Pattern: []byte("__foo"),
Patterns: []*HasBytesPattern{
{Pattern: []byte("__foo")},
},
}

return h, io.MultiWriter(&b, h)
}

Expand All @@ -46,19 +49,19 @@ func TestHasBytesWriter(t *testing.T) {
for i := 0; i < 22; i++ {
h, w := neww()
fmt.Fprintf(w, rndStr()+"abc __foobar"+rndStr())
c.Assert(h.Match, qt.Equals, true)
c.Assert(h.Patterns[0].Match, qt.Equals, true)

h, w = neww()
fmt.Fprintf(w, rndStr()+"abc __f")
fmt.Fprintf(w, "oo bar"+rndStr())
c.Assert(h.Match, qt.Equals, true)
c.Assert(h.Patterns[0].Match, qt.Equals, true)

h, w = neww()
fmt.Fprintf(w, rndStr()+"abc __moo bar")
c.Assert(h.Match, qt.Equals, false)
c.Assert(h.Patterns[0].Match, qt.Equals, false)
}

h, w := neww()
fmt.Fprintf(w, "__foo")
c.Assert(h.Match, qt.Equals, true)
c.Assert(h.Patterns[0].Match, qt.Equals, true)
}
20 changes: 20 additions & 0 deletions common/maps/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,26 @@ func (c *Cache[K, T]) ForEeach(f func(K, T)) {
}
}

func (c *Cache[K, T]) Drain() map[K]T {
c.Lock()
m := c.m
c.m = make(map[K]T)
c.Unlock()
return m
}

func (c *Cache[K, T]) Len() int {
c.RLock()
defer c.RUnlock()
return len(c.m)
}

func (c *Cache[K, T]) Reset() {
c.Lock()
c.m = make(map[K]T)
c.Unlock()
}

// SliceCache is a simple thread safe cache backed by a map.
type SliceCache[T any] struct {
m map[string][]T
Expand Down
59 changes: 53 additions & 6 deletions deps/deps.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/gohugoio/hugo/cache/filecache"
"github.com/gohugoio/hugo/common/hexec"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/common/types"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/config/allconfig"
Expand Down Expand Up @@ -161,20 +162,29 @@ func (d *Deps) Init() error {
}

if d.PathSpec == nil {
hashBytesReceiverFunc := func(name string, match bool) {
if !match {
return
hashBytesReceiverFunc := func(name string, match []byte) {
s := string(match)
switch s {
case postpub.PostProcessPrefix:
d.BuildState.AddFilenameWithPostPrefix(name)
case tpl.HugoDeferredTemplatePrefix:
d.BuildState.DeferredExecutions.FilenamesWithPostPrefix.Set(name, true)
}
d.BuildState.AddFilenameWithPostPrefix(name)
}

// Skip binary files.
mediaTypes := d.Conf.GetConfigSection("mediaTypes").(media.Types)
hashBytesSHouldCheck := func(name string) bool {
hashBytesShouldCheck := func(name string) bool {
ext := strings.TrimPrefix(filepath.Ext(name), ".")
return mediaTypes.IsTextSuffix(ext)
}
d.Fs.PublishDir = hugofs.NewHasBytesReceiver(d.Fs.PublishDir, hashBytesSHouldCheck, hashBytesReceiverFunc, []byte(postpub.PostProcessPrefix))
d.Fs.PublishDir = hugofs.NewHasBytesReceiver(
d.Fs.PublishDir,
hashBytesShouldCheck,
hashBytesReceiverFunc,
[]byte(tpl.HugoDeferredTemplatePrefix),
[]byte(postpub.PostProcessPrefix))

pathSpec, err := helpers.NewPathSpec(d.Fs, d.Conf, d.Log)
if err != nil {
return err
Expand Down Expand Up @@ -371,10 +381,41 @@ type BuildState struct {
// A set of filenames in /public that
// contains a post-processing prefix.
filenamesWithPostPrefix map[string]bool

filenamesWithDefferedExecution map[string]bool

DeferredExecutions *DeferredExecutions

// Deferred executions grouped by rendering context.
DeferredExecutionsGroupedByRenderingContext map[tpl.RenderingContext]*DeferredExecutions
}

type DeferredExecutions struct {
// A set of filenames in /public that
// contains a post-processing prefix.
FilenamesWithPostPrefix *maps.Cache[string, bool]

// Maps a placeholder to a deferred execution.
Executions *maps.Cache[string, *tpl.DeferredExecution]
}

var _ identity.SignalRebuilder = (*BuildState)(nil)

func (b *BuildState) StartRenderingStage(r tpl.RenderingContext) {
if b.DeferredExecutionsGroupedByRenderingContext == nil {
b.DeferredExecutionsGroupedByRenderingContext = make(map[tpl.RenderingContext]*DeferredExecutions)
}
b.DeferredExecutions = &DeferredExecutions{
Executions: maps.NewCache[string, *tpl.DeferredExecution](),
FilenamesWithPostPrefix: maps.NewCache[string, bool](),
}
}

func (b *BuildState) StopRenderingStage(r tpl.RenderingContext) {
b.DeferredExecutionsGroupedByRenderingContext[r] = b.DeferredExecutions
b.DeferredExecutions = nil
}

func (b *BuildState) SignalRebuild(ids ...identity.Identity) {
b.OnSignalRebuild(ids...)
}
Expand All @@ -399,6 +440,12 @@ func (b *BuildState) GetFilenamesWithPostPrefix() []string {
return filenames
}

func (b *BuildState) AddDeferredExecution(id string, d *tpl.DeferredExecution) {
b.mu.Lock()
defer b.mu.Unlock()
b.DeferredExecutions.Executions.Set(id, d)
}

func (b *BuildState) Incr() int {
return int(atomic.AddUint64(&b.counter, uint64(1)))
}
23 changes: 16 additions & 7 deletions hugofs/hasbytes_fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ var (
type hasBytesFs struct {
afero.Fs
shouldCheck func(name string) bool
hasBytesCallback func(name string, match bool)
pattern []byte
hasBytesCallback func(name string, match []byte)
patterns [][]byte
}

func NewHasBytesReceiver(delegate afero.Fs, shouldCheck func(name string) bool, hasBytesCallback func(name string, match bool), pattern []byte) afero.Fs {
return &hasBytesFs{Fs: delegate, shouldCheck: shouldCheck, hasBytesCallback: hasBytesCallback, pattern: pattern}
func NewHasBytesReceiver(delegate afero.Fs, shouldCheck func(name string) bool, hasBytesCallback func(name string, match []byte), patterns ...[]byte) afero.Fs {
return &hasBytesFs{Fs: delegate, shouldCheck: shouldCheck, hasBytesCallback: hasBytesCallback, patterns: patterns}
}

func (fs *hasBytesFs) UnwrapFilesystem() afero.Fs {
Expand All @@ -60,10 +60,15 @@ func (fs *hasBytesFs) wrapFile(f afero.File) afero.File {
if !fs.shouldCheck(f.Name()) {
return f
}
patterns := make([]*hugio.HasBytesPattern, len(fs.patterns))
for i, p := range fs.patterns {
patterns[i] = &hugio.HasBytesPattern{Pattern: p}
}

return &hasBytesFile{
File: f,
hbw: &hugio.HasBytesWriter{
Pattern: fs.pattern,
Patterns: patterns,
},
hasBytesCallback: fs.hasBytesCallback,
}
Expand All @@ -74,7 +79,7 @@ func (fs *hasBytesFs) Name() string {
}

type hasBytesFile struct {
hasBytesCallback func(name string, match bool)
hasBytesCallback func(name string, match []byte)
hbw *hugio.HasBytesWriter
afero.File
}
Expand All @@ -88,6 +93,10 @@ func (h *hasBytesFile) Write(p []byte) (n int, err error) {
}

func (h *hasBytesFile) Close() error {
h.hasBytesCallback(h.Name(), h.hbw.Match)
for _, p := range h.hbw.Patterns {
if p.Match {
h.hasBytesCallback(h.Name(), p.Pattern)
}
}
return h.File.Close()
}
Loading

0 comments on commit 277bc71

Please sign in to comment.