Create a struct with all of Hugo's config options

Primary motivation is documentation, but it will also hopefully simplify the code.

Also,

* Lower case the default output format names; this is in line with the custom ones (map keys) and how
it's treated all the places. This avoids doing `stringds.EqualFold` everywhere.

Closes #10896
Closes #10620
This commit is contained in:
Bjørn Erik Pedersen
2023-01-04 18:24:36 +01:00
parent 6aededf6b4
commit 241b21b0fd
337 changed files with 13377 additions and 14898 deletions

View File

@@ -1,4 +1,4 @@
// Copyright 2015 The Hugo Authors. All rights reserved.
// Copyright 2023 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.
@@ -11,13 +11,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package source
package source_test
import (
"fmt"
"path/filepath"
"testing"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/config/testconfig"
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/source"
"github.com/spf13/afero"
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/hugofs"
@@ -45,22 +50,30 @@ func TestIgnoreDotFilesAndDirectories(t *testing.T) {
{"foobar/foo.md", true, []string{"\\.md$", "\\.boo$"}},
{"foobar/foo.html", false, []string{"\\.md$", "\\.boo$"}},
{"foobar/foo.md", true, []string{"foo.md$"}},
{"foobar/foo.md", true, []string{"*", "\\.md$", "\\.boo$"}},
{"foobar/foo.md", true, []string{".*", "\\.md$", "\\.boo$"}},
{"foobar/.#content.md", true, []string{"/\\.#"}},
{".#foobar.md", true, []string{"^\\.#"}},
}
for i, test := range tests {
v := newTestConfig()
v.Set("ignoreFiles", test.ignoreFilesRegexpes)
fs := hugofs.NewMem(v)
ps, err := helpers.NewPathSpec(fs, v, nil)
c.Assert(err, qt.IsNil)
test := test
c.Run(fmt.Sprintf("[%d] %s", i, test.path), func(c *qt.C) {
c.Parallel()
v := config.New()
v.Set("ignoreFiles", test.ignoreFilesRegexpes)
v.Set("publishDir", "public")
afs := afero.NewMemMapFs()
conf := testconfig.GetTestConfig(afs, v)
fs := hugofs.NewFromOld(afs, v)
ps, err := helpers.NewPathSpec(fs, conf, nil)
c.Assert(err, qt.IsNil)
s := NewSourceSpec(ps, nil, fs.Source)
s := source.NewSourceSpec(ps, nil, fs.Source)
if ignored := s.IgnoreFile(filepath.FromSlash(test.path)); test.ignore != ignored {
t.Errorf("[%d] File not ignored", i)
}
})
if ignored := s.IgnoreFile(filepath.FromSlash(test.path)); test.ignore != ignored {
t.Errorf("[%d] File not ignored", i)
}
}
}

View File

@@ -96,6 +96,7 @@ type FileWithoutOverlap interface {
// Hugo content files being one of them, considered to be unique.
UniqueID() string
// For internal use only.
FileInfo() hugofs.FileMetaInfo
}
@@ -182,6 +183,7 @@ func (fi *FileInfo) UniqueID() string {
}
// FileInfo returns a file's underlying os.FileInfo.
// For internal use only.
func (fi *FileInfo) FileInfo() hugofs.FileMetaInfo { return fi.fi }
func (fi *FileInfo) String() string { return fi.BaseFileName() }

View File

@@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package source
package source_test
import (
"path/filepath"
@@ -19,6 +19,7 @@ import (
"testing"
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/source"
)
func TestFileInfo(t *testing.T) {
@@ -29,9 +30,9 @@ func TestFileInfo(t *testing.T) {
for _, this := range []struct {
base string
filename string
assert func(f *FileInfo)
assert func(f *source.FileInfo)
}{
{filepath.FromSlash("/a/"), filepath.FromSlash("/a/b/page.md"), func(f *FileInfo) {
{filepath.FromSlash("/a/"), filepath.FromSlash("/a/b/page.md"), func(f *source.FileInfo) {
c.Assert(f.Filename(), qt.Equals, filepath.FromSlash("/a/b/page.md"))
c.Assert(f.Dir(), qt.Equals, filepath.FromSlash("b/"))
c.Assert(f.Path(), qt.Equals, filepath.FromSlash("b/page.md"))
@@ -39,10 +40,10 @@ func TestFileInfo(t *testing.T) {
c.Assert(f.TranslationBaseName(), qt.Equals, filepath.FromSlash("page"))
c.Assert(f.BaseFileName(), qt.Equals, filepath.FromSlash("page"))
}},
{filepath.FromSlash("/a/"), filepath.FromSlash("/a/b/c/d/page.md"), func(f *FileInfo) {
{filepath.FromSlash("/a/"), filepath.FromSlash("/a/b/c/d/page.md"), func(f *source.FileInfo) {
c.Assert(f.Section(), qt.Equals, "b")
}},
{filepath.FromSlash("/a/"), filepath.FromSlash("/a/b/page.en.MD"), func(f *FileInfo) {
{filepath.FromSlash("/a/"), filepath.FromSlash("/a/b/page.en.MD"), func(f *source.FileInfo) {
c.Assert(f.Section(), qt.Equals, "b")
c.Assert(f.Path(), qt.Equals, filepath.FromSlash("b/page.en.MD"))
c.Assert(f.TranslationBaseName(), qt.Equals, filepath.FromSlash("page"))

View File

@@ -1,4 +1,4 @@
// Copyright 2015 The Hugo Authors. All rights reserved.
// Copyright 2023 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.
@@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package source
package source_test
import (
"fmt"
@@ -19,17 +19,14 @@ import (
"runtime"
"testing"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/modules"
"github.com/gohugoio/hugo/langs"
"github.com/spf13/afero"
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/config/testconfig"
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/source"
)
func TestEmptySourceFilesystem(t *testing.T) {
@@ -60,13 +57,11 @@ func TestUnicodeNorm(t *testing.T) {
}
ss := newTestSourceSpec()
fi := hugofs.NewFileMetaInfo(nil, hugofs.NewFileMeta())
for i, path := range paths {
base := fmt.Sprintf("base%d", i)
c.Assert(afero.WriteFile(ss.Fs.Source, filepath.Join(base, path.NFD), []byte("some data"), 0777), qt.IsNil)
src := ss.NewFilesystem(base)
_ = src.add(path.NFD, fi)
files, err := src.Files()
c.Assert(err, qt.IsNil)
f := files[0]
@@ -76,27 +71,14 @@ func TestUnicodeNorm(t *testing.T) {
}
}
func newTestConfig() config.Provider {
v := config.NewWithTestDefaults()
_, err := langs.LoadLanguageSettings(v, nil)
func newTestSourceSpec() *source.SourceSpec {
v := config.New()
afs := hugofs.NewBaseFileDecorator(afero.NewMemMapFs())
conf := testconfig.GetTestConfig(afs, v)
fs := hugofs.NewFrom(afs, conf.BaseConfig())
ps, err := helpers.NewPathSpec(fs, conf, nil)
if err != nil {
panic(err)
}
mod, err := modules.CreateProjectModule(v)
if err != nil {
panic(err)
}
v.Set("allModules", modules.Modules{mod})
return v
}
func newTestSourceSpec() *SourceSpec {
v := newTestConfig()
fs := hugofs.NewFrom(hugofs.NewBaseFileDecorator(afero.NewMemMapFs()), v)
ps, err := helpers.NewPathSpec(fs, v, nil)
if err != nil {
panic(err)
}
return NewSourceSpec(ps, nil, fs.Source)
return source.NewSourceSpec(ps, nil, fs.Source)
}

View File

@@ -17,16 +17,13 @@ package source
import (
"os"
"path/filepath"
"regexp"
"runtime"
"github.com/gohugoio/hugo/hugofs/glob"
"github.com/gohugoio/hugo/langs"
"github.com/spf13/afero"
"github.com/gohugoio/hugo/helpers"
"github.com/spf13/cast"
)
// SourceSpec abstracts language-specific file creation.
@@ -37,56 +34,23 @@ type SourceSpec struct {
SourceFs afero.Fs
shouldInclude func(filename string) bool
Languages map[string]any
DefaultContentLanguage string
DisabledLanguages map[string]bool
}
// NewSourceSpec initializes SourceSpec using languages the given filesystem and PathSpec.
func NewSourceSpec(ps *helpers.PathSpec, inclusionFilter *glob.FilenameFilter, fs afero.Fs) *SourceSpec {
cfg := ps.Cfg
defaultLang := cfg.GetString("defaultContentLanguage")
languages := cfg.GetStringMap("languages")
disabledLangsSet := make(map[string]bool)
for _, disabledLang := range cfg.GetStringSlice("disableLanguages") {
disabledLangsSet[disabledLang] = true
}
if len(languages) == 0 {
l := langs.NewDefaultLanguage(cfg)
languages[l.Lang] = l
defaultLang = l.Lang
}
ignoreFiles := cast.ToStringSlice(cfg.Get("ignoreFiles"))
var regexps []*regexp.Regexp
if len(ignoreFiles) > 0 {
for _, ignorePattern := range ignoreFiles {
re, err := regexp.Compile(ignorePattern)
if err != nil {
helpers.DistinctErrorLog.Printf("Invalid regexp %q in ignoreFiles: %s", ignorePattern, err)
} else {
regexps = append(regexps, re)
}
}
}
shouldInclude := func(filename string) bool {
if !inclusionFilter.Match(filename, false) {
return false
}
for _, r := range regexps {
if r.MatchString(filename) {
return false
}
if ps.Cfg.IgnoreFile(filename) {
return false
}
return true
}
return &SourceSpec{shouldInclude: shouldInclude, PathSpec: ps, SourceFs: fs, Languages: languages, DefaultContentLanguage: defaultLang, DisabledLanguages: disabledLangsSet}
return &SourceSpec{shouldInclude: shouldInclude, PathSpec: ps, SourceFs: fs}
}
// IgnoreFile returns whether a given file should be ignored.