mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-07 20:30:36 -05:00
parent
8a1c637c44
commit
173187e263
5 changed files with 146 additions and 25 deletions
|
@ -613,6 +613,15 @@ func (c *Client) shouldVendor(path string) bool {
|
|||
return c.noVendor == nil || !c.noVendor.Match(path)
|
||||
}
|
||||
|
||||
func (c *Client) createThemeDirname(modulePath string, isProjectMod bool) (string, error) {
|
||||
modulePath = filepath.Clean(modulePath)
|
||||
moduleDir := filepath.Join(c.ccfg.ThemesDir, modulePath)
|
||||
if !isProjectMod && !strings.HasPrefix(moduleDir, c.ccfg.ThemesDir) {
|
||||
return "", errors.Errorf("invalid module path %q; must be relative to themesDir when defined outside of the project", modulePath)
|
||||
}
|
||||
return moduleDir, nil
|
||||
}
|
||||
|
||||
// ClientConfig configures the module Client.
|
||||
type ClientConfig struct {
|
||||
Fs afero.Fs
|
||||
|
|
|
@ -15,6 +15,8 @@ package modules
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/gohugoio/hugo/hugofs/glob"
|
||||
|
@ -41,10 +43,14 @@ github.com/gohugoio/hugoTestModules1_darwin/modh2_2@v1.4.0 github.com/gohugoio/h
|
|||
|
||||
workingDir, clean, err := htesting.CreateTempDir(hugofs.Os, modName)
|
||||
c.Assert(err, qt.IsNil)
|
||||
themesDir := filepath.Join(workingDir, "themes")
|
||||
err = os.Mkdir(themesDir, 0777)
|
||||
c.Assert(err, qt.IsNil)
|
||||
|
||||
ccfg := ClientConfig{
|
||||
Fs: hugofs.Os,
|
||||
WorkingDir: workingDir,
|
||||
ThemesDir: themesDir,
|
||||
}
|
||||
|
||||
withConfig(&ccfg)
|
||||
|
@ -131,6 +137,28 @@ project github.com/gohugoio/hugoTestModules1_darwin/modh2_2_2@v1.3.0+vendor
|
|||
c.Assert(graphb.String(), qt.Equals, expect)
|
||||
})
|
||||
|
||||
// https://github.com/gohugoio/hugo/issues/7908
|
||||
c.Run("createThemeDirname", func(c *qt.C) {
|
||||
mcfg := DefaultModuleConfig
|
||||
client, clean := newClient(
|
||||
c, func(cfg *ClientConfig) {
|
||||
cfg.ModuleConfig = mcfg
|
||||
})
|
||||
defer clean()
|
||||
|
||||
dirname, err := client.createThemeDirname("foo", false)
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(dirname, qt.Equals, filepath.Join(client.ccfg.ThemesDir, "foo"))
|
||||
|
||||
dirname, err = client.createThemeDirname("../../foo", true)
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(dirname, qt.Equals, filepath.Join(client.ccfg.ThemesDir, "../../foo"))
|
||||
|
||||
dirname, err = client.createThemeDirname("../../foo", false)
|
||||
c.Assert(err, qt.Not(qt.IsNil))
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
var globAll, _ = glob.GetGlob("**")
|
||||
|
|
|
@ -274,10 +274,14 @@ func (c *collector) add(owner *moduleAdapter, moduleImport Import, disabled bool
|
|||
}
|
||||
}
|
||||
|
||||
// Fall back to /themes/<mymodule>
|
||||
// Fall back to project/themes/<mymodule>
|
||||
if moduleDir == "" {
|
||||
moduleDir = filepath.Join(c.ccfg.ThemesDir, modulePath)
|
||||
|
||||
var err error
|
||||
moduleDir, err = c.createThemeDirname(modulePath, owner.projectMod)
|
||||
if err != nil {
|
||||
c.err = err
|
||||
return nil, nil
|
||||
}
|
||||
if found, _ := afero.Exists(c.fs, moduleDir); !found {
|
||||
c.err = c.wrapModuleNotFound(errors.Errorf(`module %q not found; either add it as a Hugo Module or store it in %q.`, modulePath, c.ccfg.ThemesDir))
|
||||
return nil, nil
|
||||
|
@ -441,7 +445,7 @@ func (c *collector) applyThemeConfig(tc *moduleAdapter) error {
|
|||
tc.cfg = cfg
|
||||
}
|
||||
|
||||
config, err := DecodeConfig(cfg)
|
||||
config, err := decodeConfig(cfg, c.moduleConfig.replacementsMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -605,7 +609,6 @@ func (c *collector) normalizeMounts(owner *moduleAdapter, mounts []Mount) ([]Mou
|
|||
|
||||
mnt.Source = filepath.Clean(mnt.Source)
|
||||
mnt.Target = filepath.Clean(mnt.Target)
|
||||
|
||||
var sourceDir string
|
||||
|
||||
if owner.projectMod && filepath.IsAbs(mnt.Source) {
|
||||
|
|
|
@ -18,6 +18,8 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/gohugoio/hugo/common/hugo"
|
||||
|
||||
"github.com/gohugoio/hugo/config"
|
||||
|
@ -40,6 +42,14 @@ var DefaultModuleConfig = Config{
|
|||
// Comma separated glob list matching paths that should be
|
||||
// treated as private.
|
||||
Private: "*.*",
|
||||
|
||||
// A list of replacement directives mapping a module path to a directory
|
||||
// or a theme component in the themes folder.
|
||||
// Note that this will turn the component into a traditional theme component
|
||||
// that does not partake in vendoring etc.
|
||||
// The syntax is the similar to the replacement directives used in go.mod, e.g:
|
||||
// github.com/mod1 -> ../mod1,github.com/mod2 -> ../mod2
|
||||
Replacements: nil,
|
||||
}
|
||||
|
||||
// ApplyProjectConfigDefaults applies default/missing module configuration for
|
||||
|
@ -182,7 +192,12 @@ func ApplyProjectConfigDefaults(cfg config.Provider, mod Module) error {
|
|||
|
||||
// DecodeConfig creates a modules Config from a given Hugo configuration.
|
||||
func DecodeConfig(cfg config.Provider) (Config, error) {
|
||||
return decodeConfig(cfg, nil)
|
||||
}
|
||||
|
||||
func decodeConfig(cfg config.Provider, pathReplacements map[string]string) (Config, error) {
|
||||
c := DefaultModuleConfig
|
||||
c.replacementsMap = pathReplacements
|
||||
|
||||
if cfg == nil {
|
||||
return c, nil
|
||||
|
@ -197,6 +212,37 @@ func DecodeConfig(cfg config.Provider) (Config, error) {
|
|||
return c, err
|
||||
}
|
||||
|
||||
if c.replacementsMap == nil {
|
||||
|
||||
if len(c.Replacements) == 1 {
|
||||
c.Replacements = strings.Split(c.Replacements[0], ",")
|
||||
}
|
||||
|
||||
for i, repl := range c.Replacements {
|
||||
c.Replacements[i] = strings.TrimSpace(repl)
|
||||
}
|
||||
|
||||
c.replacementsMap = make(map[string]string)
|
||||
for _, repl := range c.Replacements {
|
||||
parts := strings.Split(repl, "->")
|
||||
if len(parts) != 2 {
|
||||
return c, errors.Errorf(`invalid module.replacements: %q; configure replacement pairs on the form "oldpath->newpath" `, repl)
|
||||
}
|
||||
|
||||
c.replacementsMap[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1])
|
||||
}
|
||||
}
|
||||
|
||||
if c.replacementsMap != nil && c.Imports != nil {
|
||||
for i, imp := range c.Imports {
|
||||
if newImp, found := c.replacementsMap[imp.Path]; found {
|
||||
imp.Path = newImp
|
||||
c.Imports[i] = imp
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for i, mnt := range c.Mounts {
|
||||
mnt.Source = filepath.Clean(mnt.Source)
|
||||
mnt.Target = filepath.Clean(mnt.Target)
|
||||
|
@ -233,6 +279,9 @@ type Config struct {
|
|||
// "github.com/**".
|
||||
NoVendor string
|
||||
|
||||
Replacements []string
|
||||
replacementsMap map[string]string
|
||||
|
||||
// Configures GOPROXY.
|
||||
Proxy string
|
||||
// Configures GONOPROXY.
|
||||
|
|
|
@ -41,7 +41,9 @@ func TestConfigHugoVersionIsValid(t *testing.T) {
|
|||
|
||||
func TestDecodeConfig(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
tomlConfig := `
|
||||
|
||||
c.Run("Basic", func(c *qt.C) {
|
||||
tomlConfig := `
|
||||
[module]
|
||||
|
||||
[module.hugoVersion]
|
||||
|
@ -63,31 +65,61 @@ source="src/markdown/blog"
|
|||
target="content/blog"
|
||||
lang="en"
|
||||
`
|
||||
cfg, err := config.FromConfigString(tomlConfig, "toml")
|
||||
c.Assert(err, qt.IsNil)
|
||||
cfg, err := config.FromConfigString(tomlConfig, "toml")
|
||||
c.Assert(err, qt.IsNil)
|
||||
|
||||
mcfg, err := DecodeConfig(cfg)
|
||||
c.Assert(err, qt.IsNil)
|
||||
mcfg, err := DecodeConfig(cfg)
|
||||
c.Assert(err, qt.IsNil)
|
||||
|
||||
v056 := hugo.VersionString("0.56.0")
|
||||
v056 := hugo.VersionString("0.56.0")
|
||||
|
||||
hv := mcfg.HugoVersion
|
||||
hv := mcfg.HugoVersion
|
||||
|
||||
c.Assert(v056.Compare(hv.Min), qt.Equals, -1)
|
||||
c.Assert(v056.Compare(hv.Max), qt.Equals, 1)
|
||||
c.Assert(hv.Extended, qt.Equals, true)
|
||||
c.Assert(v056.Compare(hv.Min), qt.Equals, -1)
|
||||
c.Assert(v056.Compare(hv.Max), qt.Equals, 1)
|
||||
c.Assert(hv.Extended, qt.Equals, true)
|
||||
|
||||
if hugo.IsExtended {
|
||||
c.Assert(hv.IsValid(), qt.Equals, true)
|
||||
}
|
||||
if hugo.IsExtended {
|
||||
c.Assert(hv.IsValid(), qt.Equals, true)
|
||||
}
|
||||
|
||||
c.Assert(len(mcfg.Mounts), qt.Equals, 1)
|
||||
c.Assert(len(mcfg.Imports), qt.Equals, 1)
|
||||
imp := mcfg.Imports[0]
|
||||
imp.Path = "github.com/bep/mycomponent"
|
||||
c.Assert(imp.Mounts[1].Source, qt.Equals, "src/markdown/blog")
|
||||
c.Assert(imp.Mounts[1].Target, qt.Equals, "content/blog")
|
||||
c.Assert(imp.Mounts[1].Lang, qt.Equals, "en")
|
||||
c.Assert(len(mcfg.Mounts), qt.Equals, 1)
|
||||
c.Assert(len(mcfg.Imports), qt.Equals, 1)
|
||||
imp := mcfg.Imports[0]
|
||||
imp.Path = "github.com/bep/mycomponent"
|
||||
c.Assert(imp.Mounts[1].Source, qt.Equals, "src/markdown/blog")
|
||||
c.Assert(imp.Mounts[1].Target, qt.Equals, "content/blog")
|
||||
c.Assert(imp.Mounts[1].Lang, qt.Equals, "en")
|
||||
})
|
||||
|
||||
c.Run("Replacements", func(c *qt.C) {
|
||||
for _, tomlConfig := range []string{`
|
||||
[module]
|
||||
replacements="a->b,github.com/bep/mycomponent->c"
|
||||
[[module.imports]]
|
||||
path="github.com/bep/mycomponent"
|
||||
`, `
|
||||
[module]
|
||||
replacements=["a->b","github.com/bep/mycomponent->c"]
|
||||
[[module.imports]]
|
||||
path="github.com/bep/mycomponent"
|
||||
`} {
|
||||
|
||||
cfg, err := config.FromConfigString(tomlConfig, "toml")
|
||||
c.Assert(err, qt.IsNil)
|
||||
|
||||
mcfg, err := DecodeConfig(cfg)
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(mcfg.Replacements, qt.DeepEquals, []string{"a->b", "github.com/bep/mycomponent->c"})
|
||||
c.Assert(mcfg.replacementsMap, qt.DeepEquals, map[string]string{
|
||||
"a": "b",
|
||||
"github.com/bep/mycomponent": "c",
|
||||
})
|
||||
|
||||
c.Assert(mcfg.Imports[0].Path, qt.Equals, "c")
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue