Skip to content

Commit

Permalink
Cross-module support
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
akutz committed Apr 25, 2022
1 parent 8cb5ce8 commit 2216eec
Showing 1 changed file with 71 additions and 5 deletions.
76 changes: 71 additions & 5 deletions pkg/loader/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import (
"go/types"
"io/ioutil"
"os"
"path"
"path/filepath"
"sync"

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

rawPkgs, err := packages.Load(l.cfg, roots...)
if err != nil {
// check each root to see if it should be expanded to include nested modules
var goModDirs []string
findGoModules := func(p string, d os.DirEntry, err error) error {
if err != nil {
return err
}
if !d.IsDir() && path.Base(p) == "go.mod" {
absPath, err := filepath.Abs(p)
if err != nil {
return err
}
goModDirs = append(goModDirs, path.Join(path.Dir(absPath), "..."))
}
return nil
}
for i, r := range roots {
// skip roots whose last path element is not four dot characters
if filepath.Base(r) != "...." {
continue
}
// update the root to no longer descend into nested modules
roots[i] = r[:len(r)-1]
// add any nested modules to the list of Go module directories to
// process later
if err := filepath.WalkDir(r[:len(r)-4], findGoModules); err != nil {
return nil, err
}
}

// loadRoots parses the provided file paths and returns their load packages
loadRoots := func(roots ...string) error {
rawPkgs, err := packages.Load(l.cfg, roots...)
if err != nil {
return err
}
for _, rawPkg := range rawPkgs {
l.Roots = append(l.Roots, l.packageFor(rawPkg))
}
return nil
}

// load the packages from the main module
if err := loadRoots(roots...); err != nil {
return nil, err
}

for _, rawPkg := range rawPkgs {
l.Roots = append(l.Roots, l.packageFor(rawPkg))
if len(goModDirs) > 0 {
// ensure the working directory is updated back to its original location
// as we switch into the directory of each Go module to process them to
// accommodate the package loader
workingDir, err := os.Getwd()
if err != nil {
return nil, err
}
defer func() {
retErr = os.Chdir(workingDir)
}()

// load the packages from the nested modules
for _, p := range goModDirs {
// change the working directory to the root of the nested module
// so the package loader does not complain about processing a
// directory that is not a member of the root module
if err := os.Chdir(path.Dir(p)); err != nil {
return nil, err
}
// load the packages from the nested module
if err := loadRoots("./..."); err != nil {
return nil, err
}
}
}

return l.Roots, nil
Expand Down

0 comments on commit 2216eec

Please sign in to comment.