Skip to content

Commit

Permalink
modules: Add config option modules.vendorClosest
Browse files Browse the repository at this point in the history
Fixes #8235
Fixes #8242
  • Loading branch information
bep committed Feb 16, 2021
1 parent b60e927 commit bdfbcf6
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 9 deletions.
3 changes: 3 additions & 0 deletions docs/content/en/hugo-modules/configuration.md
Expand Up @@ -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.

Expand Down
10 changes: 9 additions & 1 deletion hugofs/glob/glob.go
Expand Up @@ -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

Expand All @@ -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
Expand Down
42 changes: 35 additions & 7 deletions modules/client_test.go
Expand Up @@ -18,6 +18,7 @@ import (
"fmt"
"os"
"path/filepath"
"sync/atomic"
"testing"

"github.com/gohugoio/hugo/hugofs/glob"
Expand All @@ -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)
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand Down
11 changes: 10 additions & 1 deletion modules/collect.go
Expand Up @@ -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),
Expand Down
7 changes: 7 additions & 0 deletions modules/config.go
Expand Up @@ -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

Expand Down

0 comments on commit bdfbcf6

Please sign in to comment.