1
0
mirror of https://github.com/golang/go synced 2024-09-29 04:24:36 -06:00

cmd/go: changes to use modindex

This CL makes the changes to actually use the module index when loading
packages and instead of scanning their directories to see if they
contain go files or to extract imports.

Change-Id: I70106181cf64d6fd5a416644ba518b6b90030e0a
Reviewed-on: https://go-review.googlesource.com/c/go/+/403778
Reviewed-by: Michael Matloob <matloob@golang.org>
Reviewed-by: Bryan Mills <bcmills@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Michael Matloob <matloob@golang.org>
This commit is contained in:
Michael Matloob 2022-04-05 18:47:23 -04:00
parent 06261062e9
commit ee87cd1dd9
8 changed files with 89 additions and 31 deletions

View File

@ -35,6 +35,7 @@ import (
"cmd/go/internal/fsys"
"cmd/go/internal/imports"
"cmd/go/internal/modfetch"
"cmd/go/internal/modindex"
"cmd/go/internal/modinfo"
"cmd/go/internal/modload"
"cmd/go/internal/par"
@ -871,7 +872,16 @@ func loadPackageData(ctx context.Context, path, parentPath, parentDir, parentRoo
if !cfg.ModulesEnabled {
buildMode = build.ImportComment
}
if modroot := modload.PackageModRoot(ctx, r.dir); modroot != "" {
if mi, err := modindex.Get(modroot); err == nil {
data.p, data.err = mi.Import(cfg.BuildContext, mi.RelPath(r.dir), buildMode)
goto Happy
} else if !errors.Is(err, modindex.ErrNotIndexed) {
base.Fatalf("go: %v", err)
}
}
data.p, data.err = cfg.BuildContext.ImportDir(r.dir, buildMode)
Happy:
if cfg.ModulesEnabled {
// Override data.p.Root, since ImportDir sets it to $GOPATH, if
// the module is inside $GOPATH/src.

View File

@ -134,7 +134,7 @@ func openIndex(modroot string, ismodcache bool) (*ModuleIndex, error) {
if err != nil {
return result{nil, err}
}
return mi
return result{mi, nil}
}).(result)
return r.mi, r.err
}

View File

@ -20,7 +20,7 @@ import (
// if the module shouldn't be indexed, and nil otherwise.
func moduleWalkErr(modroot string, path string, info fs.FileInfo, err error) error {
if err != nil {
return err
return ErrNotIndexed
}
// stop at module boundaries
if info.IsDir() && path != modroot {

View File

@ -63,6 +63,26 @@ func PackageModuleInfo(ctx context.Context, pkgpath string) *modinfo.ModulePubli
return moduleInfo(ctx, rs, m, 0)
}
// PackageModRoot returns the module root directory for the module that provides
// a given package. If modules are not enabled or if the package is in the
// standard library or if the package was not successfully loaded with
// LoadPackages or ImportFromFiles, the empty string is returned.
func PackageModRoot(ctx context.Context, pkgpath string) string {
if isStandardImportPath(pkgpath) || !Enabled() || cfg.BuildMod == "vendor" {
return ""
}
m, ok := findModule(loaded, pkgpath)
if !ok {
return ""
}
const needSum = true
root, _, err := fetch(ctx, m, needSum)
if err != nil {
return ""
}
return root
}
func ModuleInfo(ctx context.Context, path string) *modinfo.ModulePublic {
if !Enabled() {
return nil

View File

@ -20,8 +20,10 @@ import (
"cmd/go/internal/cfg"
"cmd/go/internal/fsys"
"cmd/go/internal/modfetch"
"cmd/go/internal/modindex"
"cmd/go/internal/par"
"cmd/go/internal/search"
"cmd/go/internal/str"
"golang.org/x/mod/module"
"golang.org/x/mod/semver"
@ -247,9 +249,9 @@ func (e *invalidImportError) Unwrap() error {
// If the package is present in exactly one module, importFromModules will
// return the module, its root directory, and a list of other modules that
// lexically could have provided the package but did not.
func importFromModules(ctx context.Context, path string, rs *Requirements, mg *ModuleGraph) (m module.Version, dir string, altMods []module.Version, err error) {
invalidf := func(format string, args ...interface{}) (module.Version, string, []module.Version, error) {
return module.Version{}, "", nil, &invalidImportError{
func importFromModules(ctx context.Context, path string, rs *Requirements, mg *ModuleGraph) (m module.Version, modroot, dir string, altMods []module.Version, err error) {
invalidf := func(format string, args ...interface{}) (module.Version, string, string, []module.Version, error) {
return module.Version{}, "", "", nil, &invalidImportError{
importPath: path,
err: fmt.Errorf(format, args...),
}
@ -270,11 +272,11 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
if path == "C" {
// There's no directory for import "C".
return module.Version{}, "", nil, nil
return module.Version{}, "", "", nil, nil
}
// Before any further lookup, check that the path is valid.
if err := module.CheckImportPath(path); err != nil {
return module.Version{}, "", nil, &invalidImportError{importPath: path, err: err}
return module.Version{}, "", "", nil, &invalidImportError{importPath: path, err: err}
}
// Is the package in the standard library?
@ -283,14 +285,18 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
for _, mainModule := range MainModules.Versions() {
if MainModules.InGorootSrc(mainModule) {
if dir, ok, err := dirInModule(path, MainModules.PathPrefix(mainModule), MainModules.ModRoot(mainModule), true); err != nil {
return module.Version{}, dir, nil, err
return module.Version{}, MainModules.ModRoot(mainModule), dir, nil, err
} else if ok {
return mainModule, dir, nil, nil
return mainModule, MainModules.ModRoot(mainModule), dir, nil, nil
}
}
}
dir := filepath.Join(cfg.GOROOT, "src", path)
return module.Version{}, dir, nil, nil
dir := filepath.Join(cfg.GOROOTsrc, path)
modroot = cfg.GOROOTsrc
if str.HasPathPrefix(path, "cmd") {
modroot = filepath.Join(cfg.GOROOTsrc, "cmd")
}
return module.Version{}, modroot, dir, nil, nil
}
// -mod=vendor is special.
@ -301,23 +307,23 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
mainDir, mainOK, mainErr := dirInModule(path, MainModules.PathPrefix(mainModule), modRoot, true)
vendorDir, vendorOK, _ := dirInModule(path, "", filepath.Join(modRoot, "vendor"), false)
if mainOK && vendorOK {
return module.Version{}, "", nil, &AmbiguousImportError{importPath: path, Dirs: []string{mainDir, vendorDir}}
return module.Version{}, modRoot, "", nil, &AmbiguousImportError{importPath: path, Dirs: []string{mainDir, vendorDir}}
}
// Prefer to return main directory if there is one,
// Note that we're not checking that the package exists.
// We'll leave that for load.
if !vendorOK && mainDir != "" {
return mainModule, mainDir, nil, nil
return mainModule, modRoot, mainDir, nil, nil
}
if mainErr != nil {
return module.Version{}, "", nil, mainErr
return module.Version{}, "", "", nil, mainErr
}
readVendorList(mainModule)
return vendorPkgModule[path], vendorDir, nil, nil
return vendorPkgModule[path], modRoot, vendorDir, nil, nil
}
// Check each module on the build list.
var dirs []string
var dirs, roots []string
var mods []module.Version
// Iterate over possible modules for the path, not all selected modules.
@ -368,12 +374,13 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
// continue the loop and find the package in some other module,
// we need to look at this module to make sure the import is
// not ambiguous.
return module.Version{}, "", nil, err
return module.Version{}, "", "", nil, err
}
if dir, ok, err := dirInModule(path, m.Path, root, isLocal); err != nil {
return module.Version{}, "", nil, err
return module.Version{}, "", "", nil, err
} else if ok {
mods = append(mods, m)
roots = append(roots, root)
dirs = append(dirs, dir)
} else {
altMods = append(altMods, m)
@ -387,9 +394,10 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
for i := 0; i < len(mods)/2; i++ {
j := len(mods) - 1 - i
mods[i], mods[j] = mods[j], mods[i]
roots[i], roots[j] = roots[j], roots[i]
dirs[i], dirs[j] = dirs[j], dirs[i]
}
return module.Version{}, "", nil, &AmbiguousImportError{importPath: path, Dirs: dirs, Modules: mods}
return module.Version{}, "", "", nil, &AmbiguousImportError{importPath: path, Dirs: dirs, Modules: mods}
}
if len(sumErrMods) > 0 {
@ -397,7 +405,7 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
j := len(sumErrMods) - 1 - i
sumErrMods[i], sumErrMods[j] = sumErrMods[j], sumErrMods[i]
}
return module.Version{}, "", nil, &ImportMissingSumError{
return module.Version{}, "", "", nil, &ImportMissingSumError{
importPath: path,
mods: sumErrMods,
found: len(mods) > 0,
@ -405,7 +413,7 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
}
if len(mods) == 1 {
return mods[0], dirs[0], altMods, nil
return mods[0], roots[0], dirs[0], altMods, nil
}
if mg != nil {
@ -415,7 +423,7 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
if !HasModRoot() {
queryErr = ErrNoModRoot
}
return module.Version{}, "", nil, &ImportMissingError{Path: path, QueryErr: queryErr, isStd: pathIsStd}
return module.Version{}, "", "", nil, &ImportMissingError{Path: path, QueryErr: queryErr, isStd: pathIsStd}
}
// So far we've checked the root dependencies.
@ -426,7 +434,7 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
// the module graph, so we can't return an ImportMissingError here — one
// of the missing modules might actually contain the package in question,
// in which case we shouldn't go looking for it in some new dependency.
return module.Version{}, "", nil, err
return module.Version{}, "", "", nil, err
}
}
}
@ -650,6 +658,15 @@ func dirInModule(path, mpath, mdir string, isLocal bool) (dir string, haveGoFile
// We don't care about build tags, not even "+build ignore".
// We're just looking for a plausible directory.
res := haveGoFilesCache.Do(dir, func() any {
// modindex.Get will return ErrNotIndexed for any directories which
// are reached through a symlink, so that they will be handled by
// fsys.IsDirWithGoFiles below.
if mi, err := modindex.Get(mdir); err == nil {
isDirWithGoFiles, err := mi.IsDirWithGoFiles(mi.RelPath(dir))
return goFilesEntry{isDirWithGoFiles, err}
} else if !errors.Is(err, modindex.ErrNotIndexed) {
return goFilesEntry{err: err}
}
ok, err := fsys.IsDirWithGoFiles(dir)
return goFilesEntry{haveGoFiles: ok, err: err}
}).(goFilesEntry)

View File

@ -116,6 +116,7 @@ import (
"cmd/go/internal/fsys"
"cmd/go/internal/imports"
"cmd/go/internal/modfetch"
"cmd/go/internal/modindex"
"cmd/go/internal/mvs"
"cmd/go/internal/par"
"cmd/go/internal/search"
@ -1401,7 +1402,7 @@ func (ld *loader) updateRequirements(ctx context.Context) (changed bool, err err
//
// In some sense, we can think of this as upgraded the module providing
// pkg.path from "none" to a version higher than "none".
if _, _, _, err = importFromModules(ctx, pkg.path, rs, nil); err == nil {
if _, _, _, _, err = importFromModules(ctx, pkg.path, rs, nil); err == nil {
changed = true
break
}
@ -1612,7 +1613,7 @@ func (ld *loader) preloadRootModules(ctx context.Context, rootPkgs []string) (ch
// If the main module is tidy and the package is in "all" — or if we're
// lucky — we can identify all of its imports without actually loading the
// full module graph.
m, _, _, err := importFromModules(ctx, path, ld.requirements, nil)
m, _, _, _, err := importFromModules(ctx, path, ld.requirements, nil)
if err != nil {
var missing *ImportMissingError
if errors.As(err, &missing) && ld.ResolveMissingImports {
@ -1699,7 +1700,8 @@ func (ld *loader) load(ctx context.Context, pkg *loadPkg) {
}
}
pkg.mod, pkg.dir, pkg.altMods, pkg.err = importFromModules(ctx, pkg.path, ld.requirements, mg)
var modroot string
pkg.mod, modroot, pkg.dir, pkg.altMods, pkg.err = importFromModules(ctx, pkg.path, ld.requirements, mg)
if pkg.dir == "" {
return
}
@ -1729,7 +1731,7 @@ func (ld *loader) load(ctx context.Context, pkg *loadPkg) {
// We can't scan standard packages for gccgo.
} else {
var err error
imports, testImports, err = scanDir(pkg.dir, ld.Tags)
imports, testImports, err = scanDir(modroot, pkg.dir, ld.Tags)
if err != nil {
pkg.err = err
return
@ -1958,7 +1960,7 @@ func (ld *loader) checkTidyCompatibility(ctx context.Context, rs *Requirements)
pkg := pkg
ld.work.Add(func() {
mod, _, _, err := importFromModules(ctx, pkg.path, rs, mg)
mod, _, _, _, err := importFromModules(ctx, pkg.path, rs, mg)
if mod != pkg.mod {
mismatches := <-mismatchMu
mismatches[pkg] = mismatch{mod: mod, err: err}
@ -2099,8 +2101,16 @@ func (ld *loader) checkTidyCompatibility(ctx context.Context, rs *Requirements)
// during "go vendor", we look into "// +build appengine" files and
// may see these legacy imports. We drop them so that the module
// search does not look for modules to try to satisfy them.
func scanDir(dir string, tags map[string]bool) (imports_, testImports []string, err error) {
func scanDir(modroot string, dir string, tags map[string]bool) (imports_, testImports []string, err error) {
if mi, mierr := modindex.Get(modroot); mierr == nil {
imports_, testImports, err = mi.ScanDir(mi.RelPath(dir), tags)
goto Happy
} else if !errors.Is(mierr, modindex.ErrNotIndexed) {
return nil, nil, mierr
}
imports_, testImports, err = imports.ScanDir(dir, tags)
Happy:
filter := func(x []string) []string {
w := 0

View File

@ -107,7 +107,7 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f
if !have[name] {
have[name] = true
if isMatch(name) {
if _, _, err := scanDir(path, tags); err != imports.ErrNoGo {
if _, _, err := scanDir(root, path, tags); err != imports.ErrNoGo {
m.Pkgs = append(m.Pkgs, name)
}
}
@ -208,7 +208,7 @@ func MatchInModule(ctx context.Context, pattern string, m module.Version, tags m
return match
}
if haveGoFiles {
if _, _, err := scanDir(dir, tags); err != imports.ErrNoGo {
if _, _, err := scanDir(root, dir, tags); err != imports.ErrNoGo {
// ErrNoGo indicates that the directory is not actually a Go package,
// perhaps due to the tags in use. Any other non-nil error indicates a
// problem with one or more of the Go source files, but such an error does

View File

@ -170,6 +170,7 @@ func (ts *testScript) setup() {
"GOCACHE=" + testGOCACHE,
"GODEBUG=" + os.Getenv("GODEBUG"),
"GOEXE=" + cfg.ExeSuffix,
"GOINDEX=true",
"GOOS=" + runtime.GOOS,
"GOPATH=" + filepath.Join(ts.workdir, "gopath"),
"GOPROXY=" + proxyURL,