Skip to content

Commit 2216eec

Browse files
committed
Cross-module support
This patch updates the controller-gen package loader to support nested Go modules. If the syntax for the paths= argument ends with four dot-characters "/....", then this now indicates to the loader that any nested Go modules in that path should also be considered when loading packages.
1 parent 8cb5ce8 commit 2216eec

File tree

1 file changed

+71
-5
lines changed

1 file changed

+71
-5
lines changed

pkg/loader/loader.go

Lines changed: 71 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import (
2525
"go/types"
2626
"io/ioutil"
2727
"os"
28+
"path"
29+
"path/filepath"
2830
"sync"
2931

3032
"golang.org/x/tools/go/packages"
@@ -329,7 +331,7 @@ func LoadRoots(roots ...string) ([]*Package, error) {
329331
//
330332
// This is generally only useful for use in testing when you need to modify
331333
// loading settings to load from a fake location.
332-
func LoadRootsWithConfig(cfg *packages.Config, roots ...string) ([]*Package, error) {
334+
func LoadRootsWithConfig(cfg *packages.Config, roots ...string) (pkgs []*Package, retErr error) {
333335
l := &loader{
334336
cfg: cfg,
335337
packages: make(map[*packages.Package]*Package),
@@ -341,13 +343,77 @@ func LoadRootsWithConfig(cfg *packages.Config, roots ...string) ([]*Package, err
341343
// put our build flags first so that callers can override them
342344
l.cfg.BuildFlags = append([]string{"-tags", "ignore_autogenerated"}, l.cfg.BuildFlags...)
343345

344-
rawPkgs, err := packages.Load(l.cfg, roots...)
345-
if err != nil {
346+
// check each root to see if it should be expanded to include nested modules
347+
var goModDirs []string
348+
findGoModules := func(p string, d os.DirEntry, err error) error {
349+
if err != nil {
350+
return err
351+
}
352+
if !d.IsDir() && path.Base(p) == "go.mod" {
353+
absPath, err := filepath.Abs(p)
354+
if err != nil {
355+
return err
356+
}
357+
goModDirs = append(goModDirs, path.Join(path.Dir(absPath), "..."))
358+
}
359+
return nil
360+
}
361+
for i, r := range roots {
362+
// skip roots whose last path element is not four dot characters
363+
if filepath.Base(r) != "...." {
364+
continue
365+
}
366+
// update the root to no longer descend into nested modules
367+
roots[i] = r[:len(r)-1]
368+
// add any nested modules to the list of Go module directories to
369+
// process later
370+
if err := filepath.WalkDir(r[:len(r)-4], findGoModules); err != nil {
371+
return nil, err
372+
}
373+
}
374+
375+
// loadRoots parses the provided file paths and returns their load packages
376+
loadRoots := func(roots ...string) error {
377+
rawPkgs, err := packages.Load(l.cfg, roots...)
378+
if err != nil {
379+
return err
380+
}
381+
for _, rawPkg := range rawPkgs {
382+
l.Roots = append(l.Roots, l.packageFor(rawPkg))
383+
}
384+
return nil
385+
}
386+
387+
// load the packages from the main module
388+
if err := loadRoots(roots...); err != nil {
346389
return nil, err
347390
}
348391

349-
for _, rawPkg := range rawPkgs {
350-
l.Roots = append(l.Roots, l.packageFor(rawPkg))
392+
if len(goModDirs) > 0 {
393+
// ensure the working directory is updated back to its original location
394+
// as we switch into the directory of each Go module to process them to
395+
// accommodate the package loader
396+
workingDir, err := os.Getwd()
397+
if err != nil {
398+
return nil, err
399+
}
400+
defer func() {
401+
retErr = os.Chdir(workingDir)
402+
}()
403+
404+
// load the packages from the nested modules
405+
for _, p := range goModDirs {
406+
// change the working directory to the root of the nested module
407+
// so the package loader does not complain about processing a
408+
// directory that is not a member of the root module
409+
if err := os.Chdir(path.Dir(p)); err != nil {
410+
return nil, err
411+
}
412+
// load the packages from the nested module
413+
if err := loadRoots("./..."); err != nil {
414+
return nil, err
415+
}
416+
}
351417
}
352418

353419
return l.Roots, nil

0 commit comments

Comments
 (0)