Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add js.Batch #12641

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions commands/commandeer.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ func (r *rootCommand) PreRun(cd, runner *simplecobra.Commandeer) error {
r.hugoSites = lazycache.New(lazycache.Options[configKey, *hugolib.HugoSites]{
MaxEntries: 1,
OnEvict: func(key configKey, value *hugolib.HugoSites) {
fmt.Println("Evicting HugoSites", key) // TODO1 remove me.
value.Close()
runtime.GC()
},
Expand Down
15 changes: 15 additions & 0 deletions common/herrors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,21 @@ func IsNotExist(err error) bool {
return false
}

// IsExist returns true if the error is a file exists error.
// Unlike os.IsExist, this also considers wrapped errors.
func IsExist(err error) bool {
if os.IsExist(err) {
return true
}

// os.IsExist does not consider wrapped errors.
if os.IsExist(errors.Unwrap(err)) {
return true
}

return false
}

var nilPointerErrRe = regexp.MustCompile(`at <(.*)>: error calling (.*?): runtime error: invalid memory address or nil pointer dereference`)

const deferredPrefix = "__hdeferred/"
Expand Down
21 changes: 21 additions & 0 deletions common/hreflect/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,27 @@ func AsTime(v reflect.Value, loc *time.Location) (time.Time, bool) {
return time.Time{}, false
}

// ToSliceAny converts the given value to a slice of any if possible.
func ToSliceAny(v any) ([]any, bool) {
if v == nil {
return nil, false
}
switch vv := v.(type) {
case []any:
return vv, true
default:
vvv := reflect.ValueOf(v)
if vvv.Kind() == reflect.Slice {
out := make([]any, vvv.Len())
for i := 0; i < vvv.Len(); i++ {
out[i] = vvv.Index(i).Interface()
}
return out, true
}
}
return nil, false
}

func CallMethodByName(cxt context.Context, name string, v reflect.Value) []reflect.Value {
fn := v.MethodByName(name)
var args []reflect.Value
Expand Down
13 changes: 13 additions & 0 deletions common/hreflect/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,19 @@ func TestIsContextType(t *testing.T) {
c.Assert(IsContextType(reflect.TypeOf(valueCtx)), qt.IsTrue)
}

func TestToSliceAny(t *testing.T) {
c := qt.New(t)

checkOK := func(in any, expected []any) {
out, ok := ToSliceAny(in)
c.Assert(ok, qt.Equals, true)
c.Assert(out, qt.DeepEquals, expected)
}

checkOK([]any{1, 2, 3}, []any{1, 2, 3})
checkOK([]int{1, 2, 3}, []any{1, 2, 3})
}

func BenchmarkIsContextType(b *testing.B) {
type k string
b.Run("value", func(b *testing.B) {
Expand Down
7 changes: 5 additions & 2 deletions common/maps/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,14 @@ func (c *Cache[K, T]) set(key K, value T) {
}

// ForEeach calls the given function for each key/value pair in the cache.
func (c *Cache[K, T]) ForEeach(f func(K, T)) {
// If the function returns false, the iteration stops.
func (c *Cache[K, T]) ForEeach(f func(K, T) bool) {
c.RLock()
defer c.RUnlock()
for k, v := range c.m {
f(k, v)
if !f(k, v) {
return
}
}
}

Expand Down
7 changes: 7 additions & 0 deletions common/types/closer.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ type Closer interface {
Close() error
}

// CloserFunc is a convenience type to create a Closer from a function.
type CloserFunc func() error

func (f CloserFunc) Close() error {
return f()
}

type CloseAdder interface {
Add(Closer)
}
Expand Down
4 changes: 2 additions & 2 deletions config/allconfig/configlanguage.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,11 @@ func (c ConfigLanguage) Watching() bool {
return c.m.Base.Internal.Watch
}

func (c ConfigLanguage) NewIdentityManager(name string) identity.Manager {
func (c ConfigLanguage) NewIdentityManager(name string, opts ...identity.ManagerOption) identity.Manager {
if !c.Watching() {
return identity.NopManager
}
return identity.NewManager(name)
return identity.NewManager(name, opts...)
}

func (c ConfigLanguage) ContentTypes() config.ContentTypesProvider {
Expand Down
2 changes: 1 addition & 1 deletion config/configProvider.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ type AllProvider interface {
BuildDrafts() bool
Running() bool
Watching() bool
NewIdentityManager(name string) identity.Manager
NewIdentityManager(name string, opts ...identity.ManagerOption) identity.Manager
FastRenderMode() bool
PrintUnusedTemplates() bool
EnableMissingTranslationPlaceholders() bool
Expand Down
15 changes: 15 additions & 0 deletions deps/deps.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"io"
"os"
"path/filepath"
"sort"
"strings"
Expand Down Expand Up @@ -268,6 +269,20 @@ func (d *Deps) Compile(prototype *Deps) error {
return nil
}

// MkdirTemp returns a temporary directory path that will be cleaned up on exit.
func (d Deps) MkdirTemp(pattern string) (string, error) {
filename, err := os.MkdirTemp("", pattern)
if err != nil {
return "", err
}
d.BuildClosers.Add(types.CloserFunc(
func() error {
return os.RemoveAll(filename)
}))

return filename, nil
}

type globalErrHandler struct {
logger loggers.Logger

Expand Down
4 changes: 4 additions & 0 deletions hugolib/hugo_sites.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ func (h *HugoSites) ShouldSkipFileChangeEvent(ev fsnotify.Event) bool {
return h.skipRebuildForFilenames[ev.Name]
}

func (h *HugoSites) Close() error {
return h.Deps.Close()
}

func (h *HugoSites) isRebuild() bool {
return h.buildCounter.Load() > 0
}
Expand Down
3 changes: 2 additions & 1 deletion hugolib/hugo_sites_build.go
Original file line number Diff line number Diff line change
Expand Up @@ -520,8 +520,9 @@ func (s *Site) executeDeferredTemplates(de *deps.DeferredExecutions) error {
},
})

de.FilenamesWithPostPrefix.ForEeach(func(filename string, _ bool) {
de.FilenamesWithPostPrefix.ForEeach(func(filename string, _ bool) bool {
g.Enqueue(filename)
return true
})

return g.Wait()
Expand Down
21 changes: 18 additions & 3 deletions hugolib/integrationtest_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,13 @@ func TestOptWithNFDOnDarwin() TestOpt {
}
}

// TestOptWithOSFs enables the real file system.
func TestOptWithOSFs() TestOpt {
return func(c *IntegrationTestConfig) {
c.NeedsOsFS = true
}
}

// TestOptWithWorkingDir allows setting any config optiona as a function al option.
func TestOptWithConfig(fn func(c *IntegrationTestConfig)) TestOpt {
return func(c *IntegrationTestConfig) {
Expand Down Expand Up @@ -284,8 +291,9 @@ func (s *IntegrationTestBuilder) negate(match string) (string, bool) {
func (s *IntegrationTestBuilder) AssertFileContent(filename string, matches ...string) {
s.Helper()
content := strings.TrimSpace(s.FileContent(filename))

for _, m := range matches {
cm := qt.Commentf("File: %s Match %s", filename, m)
cm := qt.Commentf("File: %s Match %s\nContent:\n%s", filename, m, content)
lines := strings.Split(m, "\n")
for _, match := range lines {
match = strings.TrimSpace(match)
Expand All @@ -295,7 +303,8 @@ func (s *IntegrationTestBuilder) AssertFileContent(filename string, matches ...s
var negate bool
match, negate = s.negate(match)
if negate {
s.Assert(content, qt.Not(qt.Contains), match, cm)
if !s.Assert(content, qt.Not(qt.Contains), match, cm) {
}
continue
}
s.Assert(content, qt.Contains, match, cm)
Expand All @@ -313,7 +322,8 @@ func (s *IntegrationTestBuilder) AssertFileContentExact(filename string, matches
s.Helper()
content := s.FileContent(filename)
for _, m := range matches {
s.Assert(content, qt.Contains, m, qt.Commentf(m))
cm := qt.Commentf("File: %s Match %s\nContent:\n%s", filename, m, content)
s.Assert(content, qt.Contains, m, cm)
}
}

Expand Down Expand Up @@ -450,6 +460,11 @@ func (s *IntegrationTestBuilder) Build() *IntegrationTestBuilder {
return s
}

func (s *IntegrationTestBuilder) Close() {
s.Helper()
s.Assert(s.H.Close(), qt.IsNil)
}

func (s *IntegrationTestBuilder) LogString() string {
return s.lastBuildLog
}
Expand Down
10 changes: 9 additions & 1 deletion hugolib/pages_capture.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,15 @@ func (c *pagesCollector) Collect() (collectErr error) {
id.p,
false,
func(fim hugofs.FileMetaInfo) bool {
return true
if id.isStructuralChange() {
return true
}
fimp := fim.Meta().PathInfo
if fimp == nil {
return true
}

return fimp.Path() == id.p.Path()
},
)
} else if id.p.IsBranchBundle() {
Expand Down
3 changes: 2 additions & 1 deletion hugolib/pagesfromdata/pagesfromgotmpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,10 +245,11 @@ func (b *BuildState) resolveDeletedPaths() {
return
}
var paths []string
b.sourceInfosPrevious.ForEeach(func(k string, _ *sourceInfo) {
b.sourceInfosPrevious.ForEeach(func(k string, _ *sourceInfo) bool {
if _, found := b.sourceInfosCurrent.Get(k); !found {
paths = append(paths, k)
}
return true
})

b.DeletedPaths = paths
Expand Down
12 changes: 12 additions & 0 deletions hugolib/rebuild_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,18 @@ Foo.

`

func TestRebuildEditLeafBundleHeaderOnly(t *testing.T) {
b := TestRunning(t, rebuildFilesSimple)
b.AssertFileContent("public/mysection/mysectionbundle/index.html",
"My Section Bundle Content Content.")

b.EditFileReplaceAll("content/mysection/mysectionbundle/index.md", "My Section Bundle Content.", "My Section Bundle Content Edited.").Build()
b.AssertFileContent("public/mysection/mysectionbundle/index.html",
"My Section Bundle Content Edited.")
b.AssertRenderCountPage(1)
b.AssertRenderCountContent(1)
}

func TestRebuildEditTextFileInLeafBundle(t *testing.T) {
b := TestRunning(t, rebuildFilesSimple)
b.AssertFileContent("public/mysection/mysectionbundle/index.html",
Expand Down
6 changes: 5 additions & 1 deletion hugolib/site.go
Original file line number Diff line number Diff line change
Expand Up @@ -1493,7 +1493,11 @@ func (s *Site) renderForTemplate(ctx context.Context, name, outputFormat string,
}

if err = s.Tmpl().ExecuteWithContext(ctx, templ, w, d); err != nil {
return fmt.Errorf("render of %q failed: %w", name, err)
filename := name
if p, ok := d.(*pageState); ok {
filename = p.pathOrTitle()
}
return fmt.Errorf("render of %q failed: %w", filename, err)
}
return
}
Expand Down
6 changes: 3 additions & 3 deletions identity/identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,8 @@ func FirstIdentity(v any) Identity {
var result Identity = Anonymous
WalkIdentitiesShallow(v, func(level int, id Identity) bool {
result = id
return true
return result != Anonymous
})

return result
}

Expand Down Expand Up @@ -308,19 +307,20 @@ type identityManager struct {

func (im *identityManager) AddIdentity(ids ...Identity) {
im.mu.Lock()
defer im.mu.Unlock()

for _, id := range ids {
if id == nil || id == Anonymous {
continue
}

if _, found := im.ids[id]; !found {
if im.onAddIdentity != nil {
im.onAddIdentity(id)
}
im.ids[id] = true
}
}
im.mu.Unlock()
}

func (im *identityManager) AddIdentityForEach(ids ...ForEeachIdentityProvider) {
Expand Down
22 changes: 22 additions & 0 deletions internal/js/esbuild/batch-esm-runner.gotmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{{ range $i, $e := .Scripts -}}
{{ if eq .Export "*" }}
{{ printf "import %s as Script%d from %q;" .Export $i .Import }}
{{ else }}
{{ printf "import { %s as Script%d } from %q;" .Export $i .Import }}
{{ end }}
{{ end -}}
{{ range $i, $e := .Runners }}
{{ printf "import { %s as Run%d } from %q;" .Export $i .Import }}
{{ end }}
{{/* */}}
{{ if .Runners }}
let scripts = [];
{{ range $i, $e := .Scripts -}}
scripts.push({{ .RunnerJSON $i }});
{{ end -}}
{{/* */}}
{{ range $i, $e := .Runners }}
{{ $id := printf "Run%d" $i }}
{{ $id }}(scripts);
{{ end }}
{{ end }}
Loading
Loading