summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2023-01-04 18:24:36 +0100
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2023-05-16 18:01:29 +0200
commit241b21b0fd34d91fccb2ce69874110dceae6f926 (patch)
treed4e0118eac7e9c42f065815447a70805f8d6ad3e /modules
parent6aededf6b42011c3039f5f66487a89a8dd65e0e7 (diff)
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
Diffstat (limited to 'modules')
-rw-r--r--modules/client.go4
-rw-r--r--modules/collect.go34
-rw-r--r--modules/config.go254
3 files changed, 133 insertions, 159 deletions
diff --git a/modules/client.go b/modules/client.go
index 1fff787d1..59f6b25d3 100644
--- a/modules/client.go
+++ b/modules/client.go
@@ -433,9 +433,9 @@ func (c *Client) Clean(pattern string) error {
if g != nil && !g.Match(m.Path) {
continue
}
- _, err = hugofs.MakeReadableAndRemoveAllModulePkgDir(c.fs, m.Dir)
+ dirCount, err := hugofs.MakeReadableAndRemoveAllModulePkgDir(c.fs, m.Dir)
if err == nil {
- c.logger.Printf("hugo: cleaned module cache for %q", m.Path)
+ c.logger.Printf("hugo: removed %d dirs in module cache for %q", dirCount, m.Path)
}
}
return err
diff --git a/modules/collect.go b/modules/collect.go
index fcde1d379..c69e7e7ee 100644
--- a/modules/collect.go
+++ b/modules/collect.go
@@ -52,20 +52,6 @@ func IsNotExist(err error) bool {
return errors.Is(err, os.ErrNotExist)
}
-// CreateProjectModule creates modules from the given config.
-// This is used in tests only.
-func CreateProjectModule(cfg config.Provider) (Module, error) {
- workingDir := cfg.GetString("workingDir")
- var modConfig Config
-
- mod := createProjectModule(nil, workingDir, modConfig)
- if err := ApplyProjectConfigDefaults(cfg, mod); err != nil {
- return nil, err
- }
-
- return mod, nil
-}
-
func (h *Client) Collect() (ModulesConfig, error) {
mc, coll := h.collect(true)
if coll.err != nil {
@@ -90,6 +76,9 @@ func (h *Client) Collect() (ModulesConfig, error) {
}
func (h *Client) collect(tidy bool) (ModulesConfig, *collector) {
+ if h == nil {
+ panic("nil client")
+ }
c := &collector{
Client: h,
}
@@ -133,6 +122,16 @@ type ModulesConfig struct {
GoWorkspaceFilename string
}
+func (m ModulesConfig) HasConfigFile() bool {
+ for _, mod := range m.ActiveModules {
+ if len(mod.ConfigFilenames()) > 0 {
+ return true
+ }
+
+ }
+ return false
+}
+
func (m *ModulesConfig) setActiveMods(logger loggers.Logger) error {
var activeMods Modules
for _, mod := range m.AllModules {
@@ -230,6 +229,7 @@ func (c *collector) getVendoredDir(path string) (vendoredModule, bool) {
}
func (c *collector) add(owner *moduleAdapter, moduleImport Import, disabled bool) (*moduleAdapter, error) {
+
var (
mod *goModule
moduleDir string
@@ -299,7 +299,7 @@ func (c *collector) add(owner *moduleAdapter, moduleImport Import, disabled bool
return nil, nil
}
if found, _ := afero.Exists(c.fs, moduleDir); !found {
- c.err = c.wrapModuleNotFound(fmt.Errorf(`module %q not found; either add it as a Hugo Module or store it in %q.`, modulePath, c.ccfg.ThemesDir))
+ c.err = c.wrapModuleNotFound(fmt.Errorf(`module %q not found in % q; either add it as a Hugo Module or store it in %q.`, modulePath, moduleDir, c.ccfg.ThemesDir))
return nil, nil
}
}
@@ -347,7 +347,7 @@ func (c *collector) addAndRecurse(owner *moduleAdapter, disabled bool) error {
moduleConfig := owner.Config()
if owner.projectMod {
if err := c.applyMounts(Import{}, owner); err != nil {
- return err
+ return fmt.Errorf("failed to apply mounts for project module: %w", err)
}
}
@@ -618,7 +618,7 @@ func (c *collector) mountCommonJSConfig(owner *moduleAdapter, mounts []Mount) ([
// Mount the common JS config files.
fis, err := afero.ReadDir(c.fs, owner.Dir())
if err != nil {
- return mounts, err
+ return mounts, fmt.Errorf("failed to read dir %q: %q", owner.Dir(), err)
}
for _, fi := range fis {
diff --git a/modules/config.go b/modules/config.go
index 9d516e841..f8faf7969 100644
--- a/modules/config.go
+++ b/modules/config.go
@@ -20,10 +20,9 @@ import (
"strings"
"github.com/gohugoio/hugo/common/hugo"
+ "github.com/gohugoio/hugo/hugofs/files"
"github.com/gohugoio/hugo/config"
- "github.com/gohugoio/hugo/hugofs/files"
- "github.com/gohugoio/hugo/langs"
"github.com/mitchellh/mapstructure"
)
@@ -58,12 +57,9 @@ var DefaultModuleConfig = Config{
// ApplyProjectConfigDefaults applies default/missing module configuration for
// the main project.
-func ApplyProjectConfigDefaults(cfg config.Provider, mod Module) error {
- moda := mod.(*moduleAdapter)
+func ApplyProjectConfigDefaults(mod Module, cfgs ...config.AllProvider) error {
- // Map legacy directory config into the new module.
- languages := cfg.Get("languagesSortedDefaultFirst").(langs.Languages)
- isMultiHost := languages.IsMultihost()
+ moda := mod.(*moduleAdapter)
// To bridge between old and new configuration format we need
// a way to make sure all of the core components are configured on
@@ -75,121 +71,92 @@ func ApplyProjectConfigDefaults(cfg config.Provider, mod Module) error {
}
}
- type dirKeyComponent struct {
- key string
- component string
- multilingual bool
- }
-
- dirKeys := []dirKeyComponent{
- {"contentDir", files.ComponentFolderContent, true},
- {"dataDir", files.ComponentFolderData, false},
- {"layoutDir", files.ComponentFolderLayouts, false},
- {"i18nDir", files.ComponentFolderI18n, false},
- {"archetypeDir", files.ComponentFolderArchetypes, false},
- {"assetDir", files.ComponentFolderAssets, false},
- {"", files.ComponentFolderStatic, isMultiHost},
- }
+ var mounts []Mount
- createMountsFor := func(d dirKeyComponent, cfg config.Provider) []Mount {
- var lang string
- if language, ok := cfg.(*langs.Language); ok {
- lang = language.Lang
+ for _, component := range []string{
+ files.ComponentFolderContent,
+ files.ComponentFolderData,
+ files.ComponentFolderLayouts,
+ files.ComponentFolderI18n,
+ files.ComponentFolderArchetypes,
+ files.ComponentFolderAssets,
+ files.ComponentFolderStatic,
+ } {
+ if componentsConfigured[component] {
+ continue
}
- // Static mounts are a little special.
- if d.component == files.ComponentFolderStatic {
- var mounts []Mount
- staticDirs := getStaticDirs(cfg)
- if len(staticDirs) > 0 {
- componentsConfigured[d.component] = true
+ first := cfgs[0]
+ dirsBase := first.DirsBase()
+ isMultiHost := first.IsMultihost()
+
+ for i, cfg := range cfgs {
+ dirs := cfg.Dirs()
+ var dir string
+ var dropLang bool
+ switch component {
+ case files.ComponentFolderContent:
+ dir = dirs.ContentDir
+ dropLang = dir == dirsBase.ContentDir
+ case files.ComponentFolderData:
+ dir = dirs.DataDir
+ case files.ComponentFolderLayouts:
+ dir = dirs.LayoutDir
+ case files.ComponentFolderI18n:
+ dir = dirs.I18nDir
+ case files.ComponentFolderArchetypes:
+ dir = dirs.ArcheTypeDir
+ case files.ComponentFolderAssets:
+ dir = dirs.AssetDir
+ case files.ComponentFolderStatic:
+ // For static dirs, we only care about the language in multihost setups.
+ dropLang = !isMultiHost
}
- for _, dir := range staticDirs {
- mounts = append(mounts, Mount{Lang: lang, Source: dir, Target: d.component})
+ var perLang bool
+ switch component {
+ case files.ComponentFolderContent, files.ComponentFolderStatic:
+ perLang = true
+ default:
+ }
+ if i > 0 && !perLang {
+ continue
}
- return mounts
-
- }
-
- if cfg.IsSet(d.key) {
- source := cfg.GetString(d.key)
- componentsConfigured[d.component] = true
-
- return []Mount{{
- // No lang set for layouts etc.
- Source: source,
- Target: d.component,
- }}
- }
-
- return nil
- }
-
- createMounts := func(d dirKeyComponent) []Mount {
- var mounts []Mount
- if d.multilingual {
- if d.component == files.ComponentFolderContent {
- seen := make(map[string]bool)
- hasContentDir := false
- for _, language := range languages {
- if language.ContentDir != "" {
- hasContentDir = true
- break
- }
- }
+ var lang string
+ if perLang && !dropLang {
+ lang = cfg.Language().Lang
+ }
- if hasContentDir {
- for _, language := range languages {
- contentDir := language.ContentDir
- if contentDir == "" {
- contentDir = files.ComponentFolderContent
- }
- if contentDir == "" || seen[contentDir] {
- continue
- }
- seen[contentDir] = true
- mounts = append(mounts, Mount{Lang: language.Lang, Source: contentDir, Target: d.component})
- }
+ // Static mounts are a little special.
+ if component == files.ComponentFolderStatic {
+ staticDirs := cfg.StaticDirs()
+ for _, dir := range staticDirs {
+ mounts = append(mounts, Mount{Lang: lang, Source: dir, Target: component})
}
+ continue
+ }
- componentsConfigured[d.component] = len(seen) > 0
-
- } else {
- for _, language := range languages {
- mounts = append(mounts, createMountsFor(d, language)...)
- }
+ if dir != "" {
+ mounts = append(mounts, Mount{Lang: lang, Source: dir, Target: component})
}
- } else {
- mounts = append(mounts, createMountsFor(d, cfg)...)
}
-
- return mounts
}
- var mounts []Mount
- for _, dirKey := range dirKeys {
- if componentsConfigured[dirKey.component] {
- continue
- }
-
- mounts = append(mounts, createMounts(dirKey)...)
+ moda.mounts = append(moda.mounts, mounts...)
- }
-
- // Add default configuration
- for _, dirKey := range dirKeys {
- if componentsConfigured[dirKey.component] {
+ // Temporary: Remove duplicates.
+ seen := make(map[string]bool)
+ var newMounts []Mount
+ for _, m := range moda.mounts {
+ key := m.Source + m.Target + m.Lang
+ if seen[key] {
continue
}
- mounts = append(mounts, Mount{Source: dirKey.component, Target: dirKey.component})
+ seen[key] = true
+ newMounts = append(newMounts, m)
}
-
- // Prepend the mounts from configuration.
- mounts = append(moda.mounts, mounts...)
-
- moda.mounts = mounts
+ moda.mounts = newMounts
return nil
}
@@ -275,7 +242,6 @@ func decodeConfig(cfg config.Provider, pathReplacements map[string]string) (Conf
Path: imp,
})
}
-
}
return c, nil
@@ -283,7 +249,10 @@ func decodeConfig(cfg config.Provider, pathReplacements map[string]string) (Conf
// Config holds a module config.
type Config struct {
- Mounts []Mount
+ // File system mounts.
+ Mounts []Mount
+
+ // Module imports.
Imports []Import
// Meta info about this module (license information etc.).
@@ -292,8 +261,7 @@ type Config struct {
// Will be validated against the running Hugo version.
HugoVersion HugoVersion
- // A optional Glob pattern matching module paths to skip when vendoring, e.g.
- // "github.com/**".
+ // Optional Glob pattern matching module paths to skip when vendoring, e.g. “github.com/**”
NoVendor string
// When enabled, we will pick the vendored module closest to the module
@@ -303,21 +271,31 @@ type Config struct {
// so once it is in use it cannot be redefined.
VendorClosest bool
+ // A comma separated (or a slice) list of module path to directory replacement mapping,
+ // e.g. github.com/bep/my-theme -> ../..,github.com/bep/shortcodes -> /some/path.
+ // This is mostly useful for temporary locally development of a module, and then it makes sense to set it as an
+ // OS environment variable, e.g: env HUGO_MODULE_REPLACEMENTS="github.com/bep/my-theme -> ../..".
+ // Any relative path is relate to themesDir, and absolute paths are allowed.
Replacements []string
replacementsMap map[string]string
- // Configures GOPROXY.
+ // Defines the proxy server to use to download remote modules. Default is direct, which means “git clone” and similar.
+ // Configures GOPROXY when running the Go command for module operations.
Proxy string
- // Configures GONOPROXY.
+
+ // Comma separated glob list matching paths that should not use the proxy configured above.
+ // Configures GONOPROXY when running the Go command for module operations.
NoProxy string
- // Configures GOPRIVATE.
+
+ // Comma separated glob list matching paths that should be treated as private.
+ // Configures GOPRIVATE when running the Go command for module operations.
Private string
// Defaults to "off".
// Set to a work file, e.g. hugo.work, to enable Go "Workspace" mode.
// Can be relative to the working directory or absolute.
- // Requires Go 1.18+
- // See https://tip.golang.org/doc/go1.18
+ // Requires Go 1.18+.
+ // Note that this can also be set via OS env, e.g. export HUGO_MODULE_WORKSPACE=/my/hugo.work.
Workspace string
}
@@ -387,21 +365,33 @@ func (v HugoVersion) IsValid() bool {
}
type Import struct {
- Path string // Module path
- pathProjectReplaced bool // Set when Path is replaced in project config.
- IgnoreConfig bool // Ignore any config in config.toml (will still follow imports).
- IgnoreImports bool // Do not follow any configured imports.
- NoMounts bool // Do not mount any folder in this import.
- NoVendor bool // Never vendor this import (only allowed in main project).
- Disable bool // Turn off this module.
- Mounts []Mount
+ // Module path
+ Path string
+ // Set when Path is replaced in project config.
+ pathProjectReplaced bool
+ // Ignore any config in config.toml (will still follow imports).
+ IgnoreConfig bool
+ // Do not follow any configured imports.
+ IgnoreImports bool
+ // Do not mount any folder in this import.
+ NoMounts bool
+ // Never vendor this import (only allowed in main project).
+ NoVendor bool
+ // Turn off this module.
+ Disable bool
+ // File mounts.
+ Mounts []Mount
}
type Mount struct {
- Source string // relative path in source repo, e.g. "scss"
- Target string // relative target path, e.g. "assets/bootstrap/scss"
+ // Relative path in source repo, e.g. "scss".
+ Source string
- Lang string // any language code associated with this mount.
+ // Relative target path, e.g. "assets/bootstrap/scss".
+ Target string
+
+ // Any file in this mount will be associated with this language.
+ Lang string
// Include only files matching the given Glob patterns (string or slice).
IncludeFiles any
@@ -423,19 +413,3 @@ func (m Mount) ComponentAndName() (string, string) {
c, n, _ := strings.Cut(m.Target, fileSeparator)
return c, n
}
-
-func getStaticDirs(cfg config.Provider) []string {
- var staticDirs []string
- for i := -1; i <= 10; i++ {
- staticDirs = append(staticDirs, getStringOrStringSlice(cfg, "staticDir", i)...)
- }
- return staticDirs
-}
-
-func getStringOrStringSlice(cfg config.Provider, key string, id int) []string {
- if id >= 0 {
- key = fmt.Sprintf("%s%d", key, id)
- }
-
- return config.GetStringSlicePreserveString(cfg, key)
-}