mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
commands: Fix data race
By wrapping all use of the shared config in a lock. Updates #10953
This commit is contained in:
parent
c371171ab8
commit
0a51dfac9e
3 changed files with 215 additions and 155 deletions
|
@ -79,18 +79,12 @@ func Execute(args []string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
type commonConfig struct {
|
type commonConfig struct {
|
||||||
mu sync.Mutex
|
mu *sync.Mutex
|
||||||
configs *allconfig.Configs
|
configs *allconfig.Configs
|
||||||
cfg config.Provider
|
cfg config.Provider
|
||||||
fs *hugofs.Fs
|
fs *hugofs.Fs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *commonConfig) getFs() *hugofs.Fs {
|
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
return c.fs
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is the root command.
|
// This is the root command.
|
||||||
type rootCommand struct {
|
type rootCommand struct {
|
||||||
Printf func(format string, v ...interface{})
|
Printf func(format string, v ...interface{})
|
||||||
|
@ -181,6 +175,7 @@ func (r *rootCommand) ConfigFromConfig(key int32, oldConf *commonConfig) (*commo
|
||||||
}
|
}
|
||||||
|
|
||||||
return &commonConfig{
|
return &commonConfig{
|
||||||
|
mu: oldConf.mu,
|
||||||
configs: configs,
|
configs: configs,
|
||||||
cfg: oldConf.cfg,
|
cfg: oldConf.cfg,
|
||||||
fs: fs,
|
fs: fs,
|
||||||
|
@ -295,6 +290,7 @@ func (r *rootCommand) ConfigFromProvider(key int32, cfg config.Provider) (*commo
|
||||||
}
|
}
|
||||||
|
|
||||||
commonConfig := &commonConfig{
|
commonConfig := &commonConfig{
|
||||||
|
mu: &sync.Mutex{},
|
||||||
configs: configs,
|
configs: configs,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
fs: fs,
|
fs: fs,
|
||||||
|
@ -309,9 +305,6 @@ func (r *rootCommand) ConfigFromProvider(key int32, cfg config.Provider) (*commo
|
||||||
|
|
||||||
func (r *rootCommand) HugFromConfig(conf *commonConfig) (*hugolib.HugoSites, error) {
|
func (r *rootCommand) HugFromConfig(conf *commonConfig) (*hugolib.HugoSites, error) {
|
||||||
h, _, err := r.hugoSites.GetOrCreate(r.configVersionID.Load(), func(key int32) (*hugolib.HugoSites, error) {
|
h, _, err := r.hugoSites.GetOrCreate(r.configVersionID.Load(), func(key int32) (*hugolib.HugoSites, error) {
|
||||||
conf.mu.Lock()
|
|
||||||
defer conf.mu.Unlock()
|
|
||||||
|
|
||||||
depsCfg := deps.DepsCfg{Configs: conf.configs, Fs: conf.fs, Logger: r.logger}
|
depsCfg := deps.DepsCfg{Configs: conf.configs, Fs: conf.fs, Logger: r.logger}
|
||||||
return hugolib.NewHugoSites(depsCfg)
|
return hugolib.NewHugoSites(depsCfg)
|
||||||
})
|
})
|
||||||
|
|
|
@ -52,8 +52,8 @@ import (
|
||||||
type hugoBuilder struct {
|
type hugoBuilder struct {
|
||||||
r *rootCommand
|
r *rootCommand
|
||||||
|
|
||||||
cunfMu sync.Mutex
|
confmu sync.Mutex
|
||||||
conf_ *commonConfig
|
conf *commonConfig
|
||||||
|
|
||||||
// May be nil.
|
// May be nil.
|
||||||
s *serverCommand
|
s *serverCommand
|
||||||
|
@ -74,16 +74,17 @@ type hugoBuilder struct {
|
||||||
errState hugoBuilderErrState
|
errState hugoBuilderErrState
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *hugoBuilder) conf() *commonConfig {
|
func (c *hugoBuilder) withConfE(fn func(conf *commonConfig) error) error {
|
||||||
c.cunfMu.Lock()
|
c.confmu.Lock()
|
||||||
defer c.cunfMu.Unlock()
|
defer c.confmu.Unlock()
|
||||||
return c.conf_
|
return fn(c.conf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *hugoBuilder) setConf(conf *commonConfig) {
|
func (c *hugoBuilder) withConf(fn func(conf *commonConfig)) {
|
||||||
c.cunfMu.Lock()
|
c.confmu.Lock()
|
||||||
defer c.cunfMu.Unlock()
|
defer c.confmu.Unlock()
|
||||||
c.conf_ = conf
|
fn(c.conf)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type hugoBuilderErrState struct {
|
type hugoBuilderErrState struct {
|
||||||
|
@ -357,7 +358,10 @@ func (c *hugoBuilder) newWatcher(pollIntervalStr string, dirList ...string) (*wa
|
||||||
|
|
||||||
// Identifies changes to config (config.toml) files.
|
// Identifies changes to config (config.toml) files.
|
||||||
configSet := make(map[string]bool)
|
configSet := make(map[string]bool)
|
||||||
configFiles := c.conf().configs.LoadingInfo.ConfigFiles
|
var configFiles []string
|
||||||
|
c.withConf(func(conf *commonConfig) {
|
||||||
|
configFiles = conf.configs.LoadingInfo.ConfigFiles
|
||||||
|
})
|
||||||
|
|
||||||
c.r.logger.Println("Watching for config changes in", strings.Join(configFiles, ", "))
|
c.r.logger.Println("Watching for config changes in", strings.Join(configFiles, ", "))
|
||||||
for _, configFile := range configFiles {
|
for _, configFile := range configFiles {
|
||||||
|
@ -466,14 +470,18 @@ func (c *hugoBuilder) copyStaticTo(sourceFs *filesystems.SourceFilesystem) (uint
|
||||||
fs := &countingStatFs{Fs: sourceFs.Fs}
|
fs := &countingStatFs{Fs: sourceFs.Fs}
|
||||||
|
|
||||||
syncer := fsync.NewSyncer()
|
syncer := fsync.NewSyncer()
|
||||||
syncer.NoTimes = c.conf().configs.Base.NoTimes
|
c.withConf(func(conf *commonConfig) {
|
||||||
syncer.NoChmod = c.conf().configs.Base.NoChmod
|
syncer.NoTimes = conf.configs.Base.NoTimes
|
||||||
|
syncer.NoChmod = conf.configs.Base.NoChmod
|
||||||
syncer.ChmodFilter = chmodFilter
|
syncer.ChmodFilter = chmodFilter
|
||||||
syncer.SrcFs = fs
|
|
||||||
syncer.DestFs = c.conf().fs.PublishDirStatic
|
syncer.DestFs = conf.fs.PublishDirStatic
|
||||||
// Now that we are using a unionFs for the static directories
|
// Now that we are using a unionFs for the static directories
|
||||||
// We can effectively clean the publishDir on initial sync
|
// We can effectively clean the publishDir on initial sync
|
||||||
syncer.Delete = c.conf().configs.Base.CleanDestinationDir
|
syncer.Delete = conf.configs.Base.CleanDestinationDir
|
||||||
|
})
|
||||||
|
|
||||||
|
syncer.SrcFs = fs
|
||||||
|
|
||||||
if syncer.Delete {
|
if syncer.Delete {
|
||||||
c.r.logger.Infoln("removing all files from destination that don't exist in static dirs")
|
c.r.logger.Infoln("removing all files from destination that don't exist in static dirs")
|
||||||
|
@ -518,9 +526,11 @@ func (c *hugoBuilder) doWithPublishDirs(f func(sourceFs *filesystems.SourceFiles
|
||||||
}
|
}
|
||||||
if lang == "" {
|
if lang == "" {
|
||||||
// Not multihost
|
// Not multihost
|
||||||
for _, l := range c.conf().configs.Languages {
|
c.withConf(func(conf *commonConfig) {
|
||||||
|
for _, l := range conf.configs.Languages {
|
||||||
langCount[l.Lang] = cnt
|
langCount[l.Lang] = cnt
|
||||||
}
|
}
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
langCount[lang] = cnt
|
langCount[lang] = cnt
|
||||||
}
|
}
|
||||||
|
@ -562,7 +572,11 @@ func (c *hugoBuilder) fullBuild(noBuildLock bool) error {
|
||||||
// Do not copy static files and build sites in parallel if cleanDestinationDir is enabled.
|
// Do not copy static files and build sites in parallel if cleanDestinationDir is enabled.
|
||||||
// This flag deletes all static resources in /public folder that are missing in /static,
|
// This flag deletes all static resources in /public folder that are missing in /static,
|
||||||
// and it does so at the end of copyStatic() call.
|
// and it does so at the end of copyStatic() call.
|
||||||
if c.conf().configs.Base.CleanDestinationDir {
|
var cleanDestinationDir bool
|
||||||
|
c.withConf(func(conf *commonConfig) {
|
||||||
|
cleanDestinationDir = conf.configs.Base.CleanDestinationDir
|
||||||
|
})
|
||||||
|
if cleanDestinationDir {
|
||||||
if err := copyStaticFunc(); err != nil {
|
if err := copyStaticFunc(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -692,8 +706,8 @@ func (c *hugoBuilder) handleEvents(watcher *watcher.Batcher,
|
||||||
}
|
}
|
||||||
|
|
||||||
if ev.Op&fsnotify.Remove == fsnotify.Remove || ev.Op&fsnotify.Rename == fsnotify.Rename {
|
if ev.Op&fsnotify.Remove == fsnotify.Remove || ev.Op&fsnotify.Rename == fsnotify.Rename {
|
||||||
configFiles := c.conf().configs.LoadingInfo.ConfigFiles
|
c.withConf(func(conf *commonConfig) {
|
||||||
for _, configFile := range configFiles {
|
for _, configFile := range conf.configs.LoadingInfo.ConfigFiles {
|
||||||
counter := 0
|
counter := 0
|
||||||
for watcher.Add(configFile) != nil {
|
for watcher.Add(configFile) != nil {
|
||||||
counter++
|
counter++
|
||||||
|
@ -703,6 +717,7 @@ func (c *hugoBuilder) handleEvents(watcher *watcher.Batcher,
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config file(s) changed. Need full rebuild.
|
// Config file(s) changed. Need full rebuild.
|
||||||
|
@ -834,9 +849,11 @@ func (c *hugoBuilder) handleEvents(watcher *watcher.Batcher,
|
||||||
// recursively add new directories to watch list
|
// recursively add new directories to watch list
|
||||||
// When mkdir -p is used, only the top directory triggers an event (at least on OSX)
|
// When mkdir -p is used, only the top directory triggers an event (at least on OSX)
|
||||||
if ev.Op&fsnotify.Create == fsnotify.Create {
|
if ev.Op&fsnotify.Create == fsnotify.Create {
|
||||||
if s, err := c.conf().fs.Source.Stat(ev.Name); err == nil && s.Mode().IsDir() {
|
c.withConf(func(conf *commonConfig) {
|
||||||
_ = helpers.SymbolicWalk(c.conf().fs.Source, ev.Name, walkAdder)
|
if s, err := conf.fs.Source.Stat(ev.Name); err == nil && s.Mode().IsDir() {
|
||||||
|
_ = helpers.SymbolicWalk(conf.fs.Source, ev.Name, walkAdder)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if staticSyncer.isStatic(h, ev.Name) {
|
if staticSyncer.isStatic(h, ev.Name) {
|
||||||
|
@ -942,10 +959,16 @@ func (c *hugoBuilder) handleEvents(watcher *watcher.Batcher,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *hugoBuilder) hugo() (*hugolib.HugoSites, error) {
|
func (c *hugoBuilder) hugo() (*hugolib.HugoSites, error) {
|
||||||
h, err := c.r.HugFromConfig(c.conf())
|
var h *hugolib.HugoSites
|
||||||
if err != nil {
|
if err := c.withConfE(func(conf *commonConfig) error {
|
||||||
|
var err error
|
||||||
|
h, err = c.r.HugFromConfig(conf)
|
||||||
|
return err
|
||||||
|
|
||||||
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.s != nil {
|
if c.s != nil {
|
||||||
// A running server, register the media types.
|
// A running server, register the media types.
|
||||||
for _, s := range h.Sites {
|
for _, s := range h.Sites {
|
||||||
|
@ -956,7 +979,10 @@ func (c *hugoBuilder) hugo() (*hugolib.HugoSites, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *hugoBuilder) hugoTry() *hugolib.HugoSites {
|
func (c *hugoBuilder) hugoTry() *hugolib.HugoSites {
|
||||||
h, _ := c.r.HugFromConfig(c.conf())
|
var h *hugolib.HugoSites
|
||||||
|
c.withConf(func(conf *commonConfig) {
|
||||||
|
h, _ = c.r.HugFromConfig(conf)
|
||||||
|
})
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -977,7 +1003,7 @@ func (c *hugoBuilder) loadConfig(cd *simplecobra.Commandeer, running bool) error
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.setConf(conf)
|
c.conf = conf
|
||||||
if c.onConfigLoaded != nil {
|
if c.onConfigLoaded != nil {
|
||||||
if err := c.onConfigLoaded(false); err != nil {
|
if err := c.onConfigLoaded(false); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1014,8 +1040,9 @@ func (c *hugoBuilder) rebuildSites(events []fsnotify.Event) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if c.fastRenderMode {
|
if c.fastRenderMode {
|
||||||
|
c.withConf(func(conf *commonConfig) {
|
||||||
// Make sure we always render the home pages
|
// Make sure we always render the home pages
|
||||||
for _, l := range c.conf().configs.Languages {
|
for _, l := range conf.configs.Languages {
|
||||||
langPath := h.GetLangSubDir(l.Lang)
|
langPath := h.GetLangSubDir(l.Lang)
|
||||||
if langPath != "" {
|
if langPath != "" {
|
||||||
langPath = langPath + "/"
|
langPath = langPath + "/"
|
||||||
|
@ -1023,6 +1050,7 @@ func (c *hugoBuilder) rebuildSites(events []fsnotify.Event) error {
|
||||||
home := h.PrependBasePath("/"+langPath, false)
|
home := h.PrependBasePath("/"+langPath, false)
|
||||||
visited[home] = true
|
visited[home] = true
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return h.Build(hugolib.BuildCfg{NoBuildLock: true, RecentlyVisited: visited, ErrRecovery: c.errState.wasErr()}, events...)
|
return h.Build(hugolib.BuildCfg{NoBuildLock: true, RecentlyVisited: visited, ErrRecovery: c.errState.wasErr()}, events...)
|
||||||
}
|
}
|
||||||
|
@ -1030,18 +1058,25 @@ func (c *hugoBuilder) rebuildSites(events []fsnotify.Event) error {
|
||||||
func (c *hugoBuilder) reloadConfig() error {
|
func (c *hugoBuilder) reloadConfig() error {
|
||||||
c.r.Reset()
|
c.r.Reset()
|
||||||
c.r.configVersionID.Add(1)
|
c.r.configVersionID.Add(1)
|
||||||
oldConf := c.conf()
|
|
||||||
conf, err := c.r.ConfigFromConfig(c.r.configVersionID.Load(), c.conf())
|
if err := c.withConfE(func(conf *commonConfig) error {
|
||||||
|
oldConf := conf
|
||||||
|
newConf, err := c.r.ConfigFromConfig(c.r.configVersionID.Load(), conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
sameLen := len(oldConf.configs.Languages) == len(conf.configs.Languages)
|
sameLen := len(oldConf.configs.Languages) == len(newConf.configs.Languages)
|
||||||
if !sameLen {
|
if !sameLen {
|
||||||
if oldConf.configs.IsMultihost || conf.configs.IsMultihost {
|
if oldConf.configs.IsMultihost || newConf.configs.IsMultihost {
|
||||||
return errors.New("multihost change detected, please restart server")
|
return errors.New("multihost change detected, please restart server")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.setConf(conf)
|
c.conf = newConf
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if c.onConfigLoaded != nil {
|
if c.onConfigLoaded != nil {
|
||||||
if err := c.onConfigLoaded(true); err != nil {
|
if err := c.onConfigLoaded(true); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -44,6 +44,7 @@ import (
|
||||||
"github.com/gohugoio/hugo/common/hugo"
|
"github.com/gohugoio/hugo/common/hugo"
|
||||||
"github.com/gohugoio/hugo/common/types"
|
"github.com/gohugoio/hugo/common/types"
|
||||||
"github.com/gohugoio/hugo/common/urls"
|
"github.com/gohugoio/hugo/common/urls"
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/gohugoio/hugo/helpers"
|
"github.com/gohugoio/hugo/helpers"
|
||||||
"github.com/gohugoio/hugo/hugofs"
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
"github.com/gohugoio/hugo/hugofs/files"
|
"github.com/gohugoio/hugo/hugofs/files"
|
||||||
|
@ -197,7 +198,6 @@ type fileServer struct {
|
||||||
|
|
||||||
func (f *fileServer) createEndpoint(i int) (*http.ServeMux, net.Listener, string, string, error) {
|
func (f *fileServer) createEndpoint(i int) (*http.ServeMux, net.Listener, string, string, error) {
|
||||||
r := f.c.r
|
r := f.c.r
|
||||||
conf := f.c.conf()
|
|
||||||
baseURL := f.baseURLs[i]
|
baseURL := f.baseURLs[i]
|
||||||
root := f.roots[i]
|
root := f.roots[i]
|
||||||
port := f.c.serverPorts[i].p
|
port := f.c.serverPorts[i].p
|
||||||
|
@ -216,7 +216,11 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, net.Listener, string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
httpFs := afero.NewHttpFs(conf.fs.PublishDirServer)
|
var httpFs *afero.HttpFs
|
||||||
|
f.c.withConf(func(conf *commonConfig) {
|
||||||
|
httpFs = afero.NewHttpFs(conf.fs.PublishDirServer)
|
||||||
|
})
|
||||||
|
|
||||||
fs := filesOnlyFs{httpFs.Dir(path.Join("/", root))}
|
fs := filesOnlyFs{httpFs.Dir(path.Join("/", root))}
|
||||||
if i == 0 && f.c.fastRenderMode {
|
if i == 0 && f.c.fastRenderMode {
|
||||||
r.Println("Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender")
|
r.Println("Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender")
|
||||||
|
@ -242,9 +246,11 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, net.Listener, string
|
||||||
}
|
}
|
||||||
|
|
||||||
port = 1313
|
port = 1313
|
||||||
|
f.c.withConf(func(conf *commonConfig) {
|
||||||
if lrport := conf.configs.GetFirstLanguageConfig().BaseURLLiveReload().Port(); lrport != 0 {
|
if lrport := conf.configs.GetFirstLanguageConfig().BaseURLLiveReload().Port(); lrport != 0 {
|
||||||
port = lrport
|
port = lrport
|
||||||
}
|
}
|
||||||
|
})
|
||||||
lr := *u
|
lr := *u
|
||||||
lr.Host = fmt.Sprintf("%s:%d", lr.Hostname(), port)
|
lr.Host = fmt.Sprintf("%s:%d", lr.Hostname(), port)
|
||||||
fmt.Fprint(w, injectLiveReloadScript(r, lr))
|
fmt.Fprint(w, injectLiveReloadScript(r, lr))
|
||||||
|
@ -258,7 +264,10 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, net.Listener, string
|
||||||
w.Header().Set("Pragma", "no-cache")
|
w.Header().Set("Pragma", "no-cache")
|
||||||
}
|
}
|
||||||
|
|
||||||
serverConfig := f.c.conf().configs.Base.Server
|
var serverConfig config.Server
|
||||||
|
f.c.withConf(func(conf *commonConfig) {
|
||||||
|
serverConfig = conf.configs.Base.Server
|
||||||
|
})
|
||||||
|
|
||||||
// Ignore any query params for the operations below.
|
// Ignore any query params for the operations below.
|
||||||
requestURI, _ := url.PathUnescape(strings.TrimSuffix(r.RequestURI, "?"+r.URL.RawQuery))
|
requestURI, _ := url.PathUnescape(strings.TrimSuffix(r.RequestURI, "?"+r.URL.RawQuery))
|
||||||
|
@ -277,7 +286,10 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, net.Listener, string
|
||||||
if root != "" {
|
if root != "" {
|
||||||
path = filepath.Join(root, path)
|
path = filepath.Join(root, path)
|
||||||
}
|
}
|
||||||
fs := f.c.conf().getFs().PublishDir
|
var fs afero.Fs
|
||||||
|
f.c.withConf(func(conf *commonConfig) {
|
||||||
|
fs = conf.fs.PublishDir
|
||||||
|
})
|
||||||
|
|
||||||
fi, err := fs.Stat(path)
|
fi, err := fs.Stat(path)
|
||||||
|
|
||||||
|
@ -519,8 +531,10 @@ func (c *serverCommand) PreRun(cd, runner *simplecobra.Commandeer) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reloaded && c.fastRenderMode {
|
if !reloaded && c.fastRenderMode {
|
||||||
c.conf().fs.PublishDir = hugofs.NewHashingFs(c.conf().fs.PublishDir, c.changeDetector)
|
c.withConf(func(conf *commonConfig) {
|
||||||
c.conf().fs.PublishDirStatic = hugofs.NewHashingFs(c.conf().fs.PublishDirStatic, c.changeDetector)
|
conf.fs.PublishDir = hugofs.NewHashingFs(conf.fs.PublishDir, c.changeDetector)
|
||||||
|
conf.fs.PublishDirStatic = hugofs.NewHashingFs(conf.fs.PublishDirStatic, c.changeDetector)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -562,18 +576,19 @@ func (c *serverCommand) setBaseURLsInConfig() error {
|
||||||
if len(c.serverPorts) == 0 {
|
if len(c.serverPorts) == 0 {
|
||||||
panic("no server ports set")
|
panic("no server ports set")
|
||||||
}
|
}
|
||||||
isMultiHost := c.conf().configs.IsMultihost
|
return c.withConfE(func(conf *commonConfig) error {
|
||||||
for i, language := range c.conf().configs.Languages {
|
for i, language := range conf.configs.Languages {
|
||||||
|
isMultiHost := conf.configs.IsMultihost
|
||||||
var serverPort int
|
var serverPort int
|
||||||
if isMultiHost {
|
if isMultiHost {
|
||||||
serverPort = c.serverPorts[i].p
|
serverPort = c.serverPorts[i].p
|
||||||
} else {
|
} else {
|
||||||
serverPort = c.serverPorts[0].p
|
serverPort = c.serverPorts[0].p
|
||||||
}
|
}
|
||||||
langConfig := c.conf().configs.LanguageConfigMap[language.Lang]
|
langConfig := conf.configs.LanguageConfigMap[language.Lang]
|
||||||
baseURLStr, err := c.fixURL(langConfig.BaseURL, c.r.baseURL, serverPort)
|
baseURLStr, err := c.fixURL(langConfig.BaseURL, c.r.baseURL, serverPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
baseURL, err := urls.NewBaseURLFromString(baseURLStr)
|
baseURL, err := urls.NewBaseURLFromString(baseURLStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -587,6 +602,7 @@ func (c *serverCommand) setBaseURLsInConfig() error {
|
||||||
langConfig.C.SetBaseURL(baseURL, baseURLLiveReload)
|
langConfig.C.SetBaseURL(baseURL, baseURLLiveReload)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *serverCommand) getErrorWithContext() any {
|
func (c *serverCommand) getErrorWithContext() any {
|
||||||
|
@ -609,13 +625,16 @@ func (c *serverCommand) getErrorWithContext() any {
|
||||||
|
|
||||||
func (c *serverCommand) createServerPorts(cd *simplecobra.Commandeer) error {
|
func (c *serverCommand) createServerPorts(cd *simplecobra.Commandeer) error {
|
||||||
flags := cd.CobraCommand.Flags()
|
flags := cd.CobraCommand.Flags()
|
||||||
isMultiHost := c.conf().configs.IsMultihost
|
var cerr error
|
||||||
|
c.withConf(func(conf *commonConfig) {
|
||||||
|
isMultiHost := conf.configs.IsMultihost
|
||||||
c.serverPorts = make([]serverPortListener, 1)
|
c.serverPorts = make([]serverPortListener, 1)
|
||||||
if isMultiHost {
|
if isMultiHost {
|
||||||
if !c.serverAppend {
|
if !c.serverAppend {
|
||||||
return errors.New("--appendPort=false not supported when in multihost mode")
|
cerr = errors.New("--appendPort=false not supported when in multihost mode")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
c.serverPorts = make([]serverPortListener, len(c.conf().configs.Languages))
|
c.serverPorts = make([]serverPortListener, len(conf.configs.Languages))
|
||||||
}
|
}
|
||||||
currentServerPort := c.serverPort
|
currentServerPort := c.serverPort
|
||||||
for i := 0; i < len(c.serverPorts); i++ {
|
for i := 0; i < len(c.serverPorts); i++ {
|
||||||
|
@ -625,19 +644,23 @@ func (c *serverCommand) createServerPorts(cd *simplecobra.Commandeer) error {
|
||||||
} else {
|
} else {
|
||||||
if i == 0 && flags.Changed("port") {
|
if i == 0 && flags.Changed("port") {
|
||||||
// port set explicitly by user -- he/she probably meant it!
|
// port set explicitly by user -- he/she probably meant it!
|
||||||
return fmt.Errorf("server startup failed: %s", err)
|
cerr = fmt.Errorf("server startup failed: %s", err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
c.r.Println("port", currentServerPort, "already in use, attempting to use an available port")
|
c.r.Println("port", currentServerPort, "already in use, attempting to use an available port")
|
||||||
l, sp, err := helpers.TCPListen()
|
l, sp, err := helpers.TCPListen()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to find alternative port to use: %s", err)
|
cerr = fmt.Errorf("unable to find alternative port to use: %s", err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
c.serverPorts[i] = serverPortListener{ln: l, p: sp.Port}
|
c.serverPorts[i] = serverPortListener{ln: l, p: sp.Port}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentServerPort = c.serverPorts[i].p + 1
|
currentServerPort = c.serverPorts[i].p + 1
|
||||||
}
|
}
|
||||||
return nil
|
})
|
||||||
|
|
||||||
|
return cerr
|
||||||
}
|
}
|
||||||
|
|
||||||
// fixURL massages the baseURL into a form needed for serving
|
// fixURL massages the baseURL into a form needed for serving
|
||||||
|
@ -709,30 +732,37 @@ func (c *serverCommand) partialReRender(urls ...string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *serverCommand) serve() error {
|
func (c *serverCommand) serve() error {
|
||||||
isMultiHost := c.conf().configs.IsMultihost
|
|
||||||
var err error
|
|
||||||
h, err := c.r.HugFromConfig(c.conf())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
r := c.r
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
baseURLs []string
|
baseURLs []string
|
||||||
roots []string
|
roots []string
|
||||||
|
h *hugolib.HugoSites
|
||||||
)
|
)
|
||||||
|
err := c.withConfE(func(conf *commonConfig) error {
|
||||||
|
isMultiHost := conf.configs.IsMultihost
|
||||||
|
var err error
|
||||||
|
h, err = c.r.HugFromConfig(conf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if isMultiHost {
|
if isMultiHost {
|
||||||
for _, l := range c.conf().configs.ConfigLangs() {
|
for _, l := range conf.configs.ConfigLangs() {
|
||||||
baseURLs = append(baseURLs, l.BaseURL().String())
|
baseURLs = append(baseURLs, l.BaseURL().String())
|
||||||
roots = append(roots, l.Language().Lang)
|
roots = append(roots, l.Language().Lang)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
l := c.conf().configs.GetFirstLanguageConfig()
|
l := conf.configs.GetFirstLanguageConfig()
|
||||||
baseURLs = []string{l.BaseURL().String()}
|
baseURLs = []string{l.BaseURL().String()}
|
||||||
roots = []string{""}
|
roots = []string{""}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Cache it here. The HugoSites object may be unavailable later on due to intermittent configuration errors.
|
// Cache it here. The HugoSites object may be unavailable later on due to intermittent configuration errors.
|
||||||
// To allow the en user to change the error template while the server is running, we use
|
// To allow the en user to change the error template while the server is running, we use
|
||||||
// the freshest template we can provide.
|
// the freshest template we can provide.
|
||||||
|
@ -796,7 +826,7 @@ func (c *serverCommand) serve() error {
|
||||||
mu.HandleFunc(u.Path+"/livereload.js", livereload.ServeJS)
|
mu.HandleFunc(u.Path+"/livereload.js", livereload.ServeJS)
|
||||||
mu.HandleFunc(u.Path+"/livereload", livereload.Handler)
|
mu.HandleFunc(u.Path+"/livereload", livereload.Handler)
|
||||||
}
|
}
|
||||||
r.Printf("Web Server is available at %s (bind address %s)\n", serverURL, c.serverInterface)
|
c.r.Printf("Web Server is available at %s (bind address %s)\n", serverURL, c.serverInterface)
|
||||||
wg1.Go(func() error {
|
wg1.Go(func() error {
|
||||||
err = srv.Serve(listener)
|
err = srv.Serve(listener)
|
||||||
if err != nil && err != http.ErrServerClosed {
|
if err != nil && err != http.ErrServerClosed {
|
||||||
|
@ -829,7 +859,7 @@ func (c *serverCommand) serve() error {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Println("Press Ctrl+C to stop")
|
c.r.Println("Press Ctrl+C to stop")
|
||||||
|
|
||||||
err = func() error {
|
err = func() error {
|
||||||
for {
|
for {
|
||||||
|
@ -845,7 +875,7 @@ func (c *serverCommand) serve() error {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Println("Error:", err)
|
c.r.Println("Error:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if h := c.hugoTry(); h != nil {
|
if h := c.hugoTry(); h != nil {
|
||||||
|
@ -892,17 +922,17 @@ func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
|
||||||
publishDir = filepath.Join(publishDir, sourceFs.PublishFolder)
|
publishDir = filepath.Join(publishDir, sourceFs.PublishFolder)
|
||||||
}
|
}
|
||||||
|
|
||||||
conf := s.c.conf().configs.Base
|
|
||||||
fs := s.c.conf().fs
|
|
||||||
syncer := fsync.NewSyncer()
|
syncer := fsync.NewSyncer()
|
||||||
syncer.NoTimes = conf.NoTimes
|
c.withConf(func(conf *commonConfig) {
|
||||||
syncer.NoChmod = conf.NoChmod
|
syncer.NoTimes = conf.configs.Base.NoTimes
|
||||||
|
syncer.NoChmod = conf.configs.Base.NoChmod
|
||||||
syncer.ChmodFilter = chmodFilter
|
syncer.ChmodFilter = chmodFilter
|
||||||
syncer.SrcFs = sourceFs.Fs
|
syncer.SrcFs = sourceFs.Fs
|
||||||
syncer.DestFs = fs.PublishDir
|
syncer.DestFs = conf.fs.PublishDir
|
||||||
if c.s != nil && c.s.renderStaticToDisk {
|
if c.s != nil && c.s.renderStaticToDisk {
|
||||||
syncer.DestFs = fs.PublishDirStatic
|
syncer.DestFs = conf.fs.PublishDirStatic
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// prevent spamming the log on changes
|
// prevent spamming the log on changes
|
||||||
logger := helpers.NewDistinctErrorLogger()
|
logger := helpers.NewDistinctErrorLogger()
|
||||||
|
@ -946,7 +976,9 @@ func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
|
||||||
if _, err := sourceFs.Fs.Stat(relPath); herrors.IsNotExist(err) {
|
if _, err := sourceFs.Fs.Stat(relPath); herrors.IsNotExist(err) {
|
||||||
// If file doesn't exist in any static dir, remove it
|
// If file doesn't exist in any static dir, remove it
|
||||||
logger.Println("File no longer exists in static dir, removing", relPath)
|
logger.Println("File no longer exists in static dir, removing", relPath)
|
||||||
_ = c.conf().fs.PublishDirStatic.RemoveAll(relPath)
|
c.withConf(func(conf *commonConfig) {
|
||||||
|
_ = conf.fs.PublishDirStatic.RemoveAll(relPath)
|
||||||
|
})
|
||||||
|
|
||||||
} else if err == nil {
|
} else if err == nil {
|
||||||
// If file still exists, sync it
|
// If file still exists, sync it
|
||||||
|
|
Loading…
Reference in a new issue