server: Fix panic when the server browser error handler tried to use a config in a state of flux

I tried and failed to create a test for this, but I have tested this manually.,

Fixes #14470
This commit is contained in:
Bjørn Erik Pedersen
2026-02-05 20:11:48 +01:00
committed by GitHub
parent 73641aeca1
commit 9045797d5f
5 changed files with 42 additions and 5 deletions
+3
View File
@@ -331,6 +331,9 @@ func (r *rootCommand) ConfigFromProvider(key configKey, cfg config.Provider) (*c
}
func (r *rootCommand) HugFromConfig(conf *commonConfig) (*hugolib.HugoSites, error) {
if conf == nil {
return nil, fmt.Errorf("conf must be set")
}
k := configKey{counter: r.configVersionID.Load()}
h, _, err := r.hugoSites.GetOrCreate(k, func(key configKey) (*hugolib.HugoSites, error) {
depsCfg := r.newDepsConfig(conf)
+27 -3
View File
@@ -56,8 +56,9 @@ import (
type hugoBuilder struct {
r *rootCommand
confmu sync.Mutex
conf *commonConfig
confmu sync.Mutex
confOld *commonConfig
conf *commonConfig
// May be nil.
s *serverCommand
@@ -94,6 +95,27 @@ func (c *hugoBuilder) withConf(fn func(conf *commonConfig)) {
fn(c.conf)
}
func (c *hugoBuilder) withConfOrOldConf(fn func(conf *commonConfig)) {
c.confmu.Lock()
defer c.confmu.Unlock()
if c.conf != nil {
fn(c.conf)
} else if c.confOld != nil {
fn(c.confOld)
}
}
func (c *hugoBuilder) withConfOrOldConfE(fn func(conf *commonConfig) error) error {
c.confmu.Lock()
defer c.confmu.Unlock()
if c.conf != nil {
return fn(c.conf)
} else if c.confOld != nil {
return fn(c.confOld)
}
return errConfigNotSet
}
type hugoBuilderErrState struct {
mu sync.Mutex
paused bool
@@ -1095,6 +1117,7 @@ func (c *hugoBuilder) loadConfig(cd *simplecobra.Commandeer, running bool) error
}
c.conf = conf
c.confOld = conf
if c.onConfigLoaded != nil {
if err := c.onConfigLoaded(false); err != nil {
return err
@@ -1158,8 +1181,9 @@ func (c *hugoBuilder) reloadConfig() error {
c.r.resetLogs()
c.r.configVersionID.Add(1)
if err := c.withConfE(func(conf *commonConfig) error {
if err := c.withConfOrOldConfE(func(conf *commonConfig) error {
oldConf := conf
c.conf = nil
newConf, err := c.r.ConfigFromConfig(configKey{counter: c.r.configVersionID.Load()}, conf)
if err != nil {
return err
+1 -1
View File
@@ -282,7 +282,7 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, net.Listener, string
}
port = 1313
f.c.withConf(func(conf *commonConfig) {
f.c.withConfOrOldConf(func(conf *commonConfig) {
if lrport := conf.configs.GetFirstLanguageConfig().BaseURLLiveReload().Port(); lrport != 0 {
port = lrport
}
+8
View File
@@ -20,6 +20,7 @@ import (
"io"
"os"
"strings"
"sync"
"time"
"github.com/bep/logg"
@@ -123,8 +124,11 @@ func New(opts Options) Logger {
)
l := logger.WithLevel(opts.Level)
logMu := &sync.Mutex{}
reset := func() {
logMu.Lock()
defer logMu.Unlock()
logCounters.mu.Lock()
defer logCounters.mu.Unlock()
logCounters.counters = make(map[logg.Level]int)
@@ -135,6 +139,7 @@ func New(opts Options) Logger {
}
return &logAdapter{
mu: logMu,
logCounters: logCounters,
errors: errorsw,
reset: reset,
@@ -204,6 +209,7 @@ type Logger interface {
}
type logAdapter struct {
mu *sync.Mutex
logCounters *logLevelCounter
errors *strings.Builder
reset func()
@@ -328,6 +334,8 @@ func (l *logAdapter) Errorln(v ...any) {
}
func (l *logAdapter) Errors() string {
l.mu.Lock()
defer l.mu.Unlock()
return l.errors.String()
}
+3 -1
View File
@@ -241,7 +241,9 @@ var commonTestScriptsParam = testscript.Params{
if err != nil {
ts.Fatalf("failed to read file %v", err)
}
newContent := bytes.Replace(oldContent, []byte(args[1]), []byte(args[2]), -1)
old, new := args[1], args[2]
newContent := bytes.Replace(oldContent, []byte(old), []byte(new), -1)
err = os.WriteFile(filename, newContent, 0o644)
if err != nil {
ts.Fatalf("failed to write file: %v", err)