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

Merged
merged 1 commit into from
Dec 12, 2024
Merged
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
6 changes: 5 additions & 1 deletion commands/hugobuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -920,7 +920,11 @@ func (c *hugoBuilder) handleEvents(watcher *watcher.Batcher,

changed := c.changeDetector.changed()
if c.changeDetector != nil {
lrl.Logf("build changed %d files", len(changed))
if len(changed) >= 10 {
lrl.Logf("build changed %d files", len(changed))
} else {
lrl.Logf("build changed %d files: %q", len(changed), changed)
}
if len(changed) == 0 {
// Nothing has changed.
return
Expand Down
6 changes: 4 additions & 2 deletions commands/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"path"
"path/filepath"
"regexp"
"sort"
"strconv"
"strings"
"sync"
Expand Down Expand Up @@ -210,16 +211,17 @@ func (f *fileChangeDetector) changed() []string {
}
}

return f.filterIrrelevant(c)
return f.filterIrrelevantAndSort(c)
}

func (f *fileChangeDetector) filterIrrelevant(in []string) []string {
func (f *fileChangeDetector) filterIrrelevantAndSort(in []string) []string {
var filtered []string
for _, v := range in {
if !f.irrelevantRe.MatchString(v) {
filtered = append(filtered, v)
}
}
sort.Strings(filtered)
return filtered
}

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
2 changes: 1 addition & 1 deletion common/herrors/file_error.go
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ func extractPosition(e error) (pos text.Position) {
case godartsass.SassError:
span := v.Span
start := span.Start
filename, _ := paths.UrlToFilename(span.Url)
filename, _ := paths.UrlStringToFilename(span.Url)
pos.Filename = filename
pos.Offset = start.Offset
pos.ColumnNumber = start.Column
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
108 changes: 93 additions & 15 deletions common/paths/url.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2021 The Hugo Authors. All rights reserved.
// Copyright 2024 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -18,6 +18,7 @@ import (
"net/url"
"path"
"path/filepath"
"runtime"
"strings"
)

Expand Down Expand Up @@ -159,9 +160,77 @@ func Uglify(in string) string {
return path.Clean(in)
}

// URLEscape escapes unicode letters.
func URLEscape(uri string) string {
// escape unicode letters
u, err := url.Parse(uri)
if err != nil {
panic(err)
}
return u.String()
}

// TrimExt trims the extension from a path..
func TrimExt(in string) string {
return strings.TrimSuffix(in, path.Ext(in))
}

// From https://github.com/golang/go/blob/e0c76d95abfc1621259864adb3d101cf6f1f90fc/src/cmd/go/internal/web/url.go#L45
func UrlFromFilename(filename string) (*url.URL, error) {
if !filepath.IsAbs(filename) {
return nil, fmt.Errorf("filepath must be absolute")
}

// If filename has a Windows volume name, convert the volume to a host and prefix
// per https://blogs.msdn.microsoft.com/ie/2006/12/06/file-uris-in-windows/.
if vol := filepath.VolumeName(filename); vol != "" {
if strings.HasPrefix(vol, `\\`) {
filename = filepath.ToSlash(filename[2:])
i := strings.IndexByte(filename, '/')

if i < 0 {
// A degenerate case.
// \\host.example.com (without a share name)
// becomes
// file://host.example.com/
return &url.URL{
Scheme: "file",
Host: filename,
Path: "/",
}, nil
}

// \\host.example.com\Share\path\to\file
// becomes
// file://host.example.com/Share/path/to/file
return &url.URL{
Scheme: "file",
Host: filename[:i],
Path: filepath.ToSlash(filename[i:]),
}, nil
}

// C:\path\to\file
// becomes
// file:///C:/path/to/file
return &url.URL{
Scheme: "file",
Path: "/" + filepath.ToSlash(filename),
}, nil
}

// /path/to/file
// becomes
// file:///path/to/file
return &url.URL{
Scheme: "file",
Path: filepath.ToSlash(filename),
}, nil
}

// UrlToFilename converts the URL s to a filename.
// If ParseRequestURI fails, the input is just converted to OS specific slashes and returned.
func UrlToFilename(s string) (string, bool) {
func UrlStringToFilename(s string) (string, bool) {
u, err := url.ParseRequestURI(s)
if err != nil {
return filepath.FromSlash(s), false
Expand All @@ -171,25 +240,34 @@ func UrlToFilename(s string) (string, bool) {

if p == "" {
p, _ = url.QueryUnescape(u.Opaque)
return filepath.FromSlash(p), true
return filepath.FromSlash(p), false
}

if runtime.GOOS != "windows" {
return p, true
}

if len(p) == 0 || p[0] != '/' {
return filepath.FromSlash(p), false
}

p = filepath.FromSlash(p)

if u.Host != "" {
// C:\data\file.txt
p = strings.ToUpper(u.Host) + ":" + p
if len(u.Host) == 1 {
// file://c/Users/...
return strings.ToUpper(u.Host) + ":" + p, true
}

return p, true
}
if u.Host != "" && u.Host != "localhost" {
if filepath.VolumeName(u.Host) != "" {
return "", false
}
return `\\` + u.Host + p, true
}

// URLEscape escapes unicode letters.
func URLEscape(uri string) string {
// escape unicode letters
u, err := url.Parse(uri)
if err != nil {
panic(err)
if vol := filepath.VolumeName(p[1:]); vol == "" || strings.HasPrefix(vol, `\\`) {
return "", false
}
return u.String()

return p[1:], true
}
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
Loading
Loading