Module module.Version
QueryErr error
- ImportingModule module.Version
+ ImportingMainModule module.Version
// isStd indicates whether we would expect to find the package in the standard
// library. This is normally true for all dotless import paths, but replace
if e.QueryErr != nil {
return fmt.Sprintf("%s: %v", message, e.QueryErr)
}
+ if e.ImportingMainModule.Path != "" && e.ImportingMainModule != MainModules.ModContainingCWD() {
+ return fmt.Sprintf("%s; to add it:\n\tcd %s\n\tgo get %s", message, MainModules.ModRoot(e.ImportingMainModule), e.Path)
+ }
return fmt.Sprintf("%s; to add it:\n\tgo get %s", message, e.Path)
}
modFiles map[module.Version]*modfile.File
+ modContainingCWD module.Version
+
indexMu sync.Mutex
indices map[module.Version]*modFileIndex
}
return len(mms.versions)
}
+// ModContainingCWD returns the main module containing the working directory,
+// or module.Version{} if none of the main modules contain the working
+// directory.
+func (mms *MainModuleSet) ModContainingCWD() module.Version {
+ return mms.modContainingCWD
+}
+
var MainModules *MainModuleSet
type Root int
} else if inWorkspaceMode() {
// We're in workspace mode.
} else {
- modRoots = findModuleRoots(base.Cwd())
- if modRoots == nil {
+ if modRoot := findModuleRoot(base.Cwd()); modRoot == "" {
if cfg.ModFile != "" {
base.Fatalf("go: cannot find main module, but -modfile was set.\n\t-modfile cannot be used to set the module root directory.")
}
// Stay in GOPATH mode.
return
}
- } else if search.InDir(modRoots[0], os.TempDir()) == "." {
+ } else if search.InDir(modRoot, os.TempDir()) == "." {
// If you create /tmp/go.mod for experimenting,
// then any tests that create work directories under /tmp
// will find it and get modules when they're not expecting them.
// It's a bit of a peculiar thing to disallow but quite mysterious
// when it happens. See golang.org/issue/26708.
- modRoots = nil
fmt.Fprintf(os.Stderr, "go: warning: ignoring go.mod in system temp root %v\n", os.TempDir())
if !mustUseModules {
return
}
+ } else {
+ modRoots = []string{modRoot}
}
}
if cfg.ModFile != "" && !strings.HasSuffix(cfg.ModFile, ".mod") {
return false
}
- if modRoots := findModuleRoots(base.Cwd()); modRoots == nil {
+ if modRoot := findModuleRoot(base.Cwd()); modRoot == "" {
// GO111MODULE is 'auto', and we can't find a module root.
// Stay in GOPATH mode.
return false
- } else if search.InDir(modRoots[0], os.TempDir()) == "." {
- _ = TODOWorkspaces("modRoots[0] is not right here")
+ } else if search.InDir(modRoot, os.TempDir()) == "." {
// If you create /tmp/go.mod for experimenting,
// then any tests that create work directories under /tmp
// will find it and get modules when they're not expecting them.
panic("mainModulesCalled with module.Version with non empty Version field: " + fmt.Sprintf("%#v", m))
}
}
+ modRootContainingCWD := findModuleRoot(base.Cwd())
mainModules := &MainModuleSet{
versions: ms[:len(ms):len(ms)],
inGorootSrc: map[module.Version]bool{},
mainModules.modFiles[m] = modFiles[i]
mainModules.indices[m] = indices[i]
+ if mainModules.modRoot[m] == modRootContainingCWD {
+ mainModules.modContainingCWD = m
+ }
+
if rel := search.InDir(rootDirs[i], cfg.GOROOTsrc); rel != "" {
mainModules.inGorootSrc[m] = true
if m.Path == "std" {
".git/config",
}
-func findModuleRoots(dir string) (roots []string) {
+func findModuleRoot(dir string) (roots string) {
if dir == "" {
panic("dir not set")
}
// Look for enclosing go.mod.
for {
if fi, err := fsys.Stat(filepath.Join(dir, "go.mod")); err == nil && !fi.IsDir() {
- return []string{dir}
+ return dir
}
d := filepath.Dir(dir)
if d == dir {
}
dir = d
}
- return nil
+ return ""
}
func findWorkspaceFile(dir string) (root string) {
var err error
mod, err = queryImport(ctx, pkg.path, ld.requirements)
if err != nil {
+ var ime *ImportMissingError
+ if errors.As(err, &ime) {
+ for curstack := pkg.stack; curstack != nil; curstack = curstack.stack {
+ if MainModules.Contains(curstack.mod.Path) {
+ ime.ImportingMainModule = curstack.mod
+ break
+ }
+ }
+ }
// pkg.err was already non-nil, so we can reasonably attribute the error
// for pkg to either the original error or the one returned by
// queryImport. The existing error indicates only that we couldn't find