"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"
// 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...),
}
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?
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.
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.
// 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)
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 {
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,
}
if len(mods) == 1 {
- return mods[0], dirs[0], altMods, nil
+ return mods[0], roots[0], dirs[0], altMods, nil
}
if mg != nil {
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.
// 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
}
}
}
// 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)
"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"
//
// 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
}
// 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 {
}
}
- 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
}
// 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
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}
// 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