modules: Add config option modules.vendorClosest

Fixes #8235
Fixes #8242
This commit is contained in:
Bjørn Erik Pedersen 2021-02-14 19:24:13 +01:00
parent b60e9279ab
commit bdfbcf6f4b
5 changed files with 64 additions and 9 deletions

View file

@ -29,6 +29,9 @@ replacements = ""
noVendor {{< new-in "0.75.0" >}}
: A optional Glob pattern matching module paths to skip when vendoring, e.g. "github.com/**"
vendorClosest {{< new-in "0.81.0" >}}
: When enabled, we will pick the vendored module closest to the module using it. The default behaviour is to pick the first. Note that there can still be only one dependency of a given module path, so once it is in use it cannot be redefined.
proxy
: Defines the proxy server to use to download remote modules. Default is `direct`, which means "git clone" and similar.

View file

@ -33,6 +33,14 @@ var (
globMu sync.RWMutex
)
type caseInsensitiveGlob struct {
g glob.Glob
}
func (g caseInsensitiveGlob) Match(s string) bool {
return g.g.Match(strings.ToLower(s))
}
func GetGlob(pattern string) (glob.Glob, error) {
var eg globErr
@ -46,7 +54,7 @@ func GetGlob(pattern string) (glob.Glob, error) {
var err error
g, err := glob.Compile(strings.ToLower(pattern), '/')
eg = globErr{g, err}
eg = globErr{caseInsensitiveGlob{g: g}, err}
globMu.Lock()
globCache[pattern] = eg

View file

@ -18,6 +18,7 @@ import (
"fmt"
"os"
"path/filepath"
"sync/atomic"
"testing"
"github.com/gohugoio/hugo/hugofs/glob"
@ -32,15 +33,18 @@ import (
func TestClient(t *testing.T) {
modName := "hugo-modules-basic-test"
modPath := "github.com/gohugoio/tests/" + modName
defaultImport := "modh2_2"
expect := `github.com/gohugoio/tests/hugo-modules-basic-test github.com/gohugoio/hugoTestModules1_darwin/modh2_2@v1.4.0
github.com/gohugoio/hugoTestModules1_darwin/modh2_2@v1.4.0 github.com/gohugoio/hugoTestModules1_darwin/modh2_2_1v@v1.3.0
github.com/gohugoio/hugoTestModules1_darwin/modh2_2@v1.4.0 github.com/gohugoio/hugoTestModules1_darwin/modh2_2_2@v1.3.0
`
c := qt.New(t)
var clientID uint64 // we increment this to get each test in its own directory.
newClient := func(c *qt.C, withConfig func(cfg *ClientConfig)) (*Client, func()) {
workingDir, clean, err := htesting.CreateTempDir(hugofs.Os, modName)
newClient := func(c *qt.C, withConfig func(cfg *ClientConfig), imp string) (*Client, func()) {
atomic.AddUint64(&clientID, uint64(1))
workingDir, clean, err := htesting.CreateTempDir(hugofs.Os, fmt.Sprintf("%s-%d", modName, clientID))
c.Assert(err, qt.IsNil)
themesDir := filepath.Join(workingDir, "themes")
err = os.Mkdir(themesDir, 0777)
@ -53,7 +57,7 @@ github.com/gohugoio/hugoTestModules1_darwin/modh2_2@v1.4.0 github.com/gohugoio/h
}
withConfig(&ccfg)
ccfg.ModuleConfig.Imports = []Import{{Path: "github.com/gohugoio/hugoTestModules1_darwin/modh2_2"}}
ccfg.ModuleConfig.Imports = []Import{{Path: "github.com/gohugoio/hugoTestModules1_darwin/" + imp}}
client := NewClient(ccfg)
return client, clean
@ -62,7 +66,7 @@ github.com/gohugoio/hugoTestModules1_darwin/modh2_2@v1.4.0 github.com/gohugoio/h
c.Run("All", func(c *qt.C) {
client, clean := newClient(c, func(cfg *ClientConfig) {
cfg.ModuleConfig = DefaultModuleConfig
})
}, defaultImport)
defer clean()
// Test Init
@ -103,7 +107,7 @@ project github.com/gohugoio/hugoTestModules1_darwin/modh2_2_2@v1.3.0+vendor
c, func(cfg *ClientConfig) {
cfg.ModuleConfig = DefaultModuleConfig
cfg.IgnoreVendor = globAll
})
}, defaultImport)
defer clean()
c.Assert(client.Init(modPath), qt.IsNil)
@ -122,7 +126,7 @@ project github.com/gohugoio/hugoTestModules1_darwin/modh2_2_2@v1.3.0+vendor
client, clean := newClient(
c, func(cfg *ClientConfig) {
cfg.ModuleConfig = mcfg
})
}, defaultImport)
defer clean()
c.Assert(client.Init(modPath), qt.IsNil)
@ -135,13 +139,37 @@ project github.com/gohugoio/hugoTestModules1_darwin/modh2_2_2@v1.3.0+vendor
c.Assert(graphb.String(), qt.Equals, expect)
})
c.Run("VendorClosest", func(c *qt.C) {
mcfg := DefaultModuleConfig
mcfg.VendorClosest = true
client, clean := newClient(
c, func(cfg *ClientConfig) {
cfg.ModuleConfig = mcfg
s := "github.com/gohugoio/hugoTestModules1_darwin/modh1_1v"
g, _ := glob.GetGlob(s)
cfg.IgnoreVendor = g
}, "modh1v")
defer clean()
c.Assert(client.Init(modPath), qt.IsNil)
_, err := client.Collect()
c.Assert(err, qt.IsNil)
c.Assert(client.Vendor(), qt.IsNil)
var graphb bytes.Buffer
c.Assert(client.Graph(&graphb), qt.IsNil)
c.Assert(graphb.String(), qt.Contains, "github.com/gohugoio/hugoTestModules1_darwin/modh1_1v@v1.3.0 github.com/gohugoio/hugoTestModules1_darwin/modh1_1_1v@v1.1.0+vendor")
})
// 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
})
}, defaultImport)
defer clean()
dirname, err := client.createThemeDirname("foo", false)

View file

@ -531,7 +531,16 @@ func (c *collector) collectModulesTXT(owner Module) error {
return errors.Errorf("invalid modules list: %q", filename)
}
path := parts[0]
if _, found := c.vendored[path]; !found {
shouldAdd := c.Client.moduleConfig.VendorClosest
if !shouldAdd {
if _, found := c.vendored[path]; !found {
shouldAdd = true
}
}
if shouldAdd {
c.vendored[path] = vendoredModule{
Owner: owner,
Dir: filepath.Join(vendorDir, path),

View file

@ -279,6 +279,13 @@ type Config struct {
// "github.com/**".
NoVendor string
// When enabled, we will pick the vendored module closest to the module
// using it.
// The default behaviour is to pick the first.
// Note that there can still be only one dependency of a given module path,
// so once it is in use it cannot be redefined.
VendorClosest bool
Replacements []string
replacementsMap map[string]string