Commit 608b94be authored by Jay Conrod's avatar Jay Conrod

cmd/go: fix error for empty packages referenced with relative paths

'go build' now reports a more useful error when a relative path on the
command line points to a directory that doesn't exist or a directory
without .go files. Errors are generated by go/build.Context.ImportDir
instead of a vague call to base.Fatalf in modload.

Fixes #35414

Change-Id: I2642230c5e409107b98bb6d6c3a484d8d25b4147
Reviewed-on: https://go-review.googlesource.com/c/go/+/206902
Run-TryBot: Jay Conrod <jayconrod@google.com>
Reviewed-by: default avatarBryan C. Mills <bcmills@google.com>
parent 718f5539
...@@ -670,6 +670,11 @@ func loadPackageData(path, parentPath, parentDir, parentRoot string, parentIsStd ...@@ -670,6 +670,11 @@ func loadPackageData(path, parentPath, parentDir, parentRoot string, parentIsStd
// we create from the full directory to the package. // we create from the full directory to the package.
// Otherwise it is the usual import path. // Otherwise it is the usual import path.
// For vendored imports, it is the expanded form. // For vendored imports, it is the expanded form.
//
// Note that when modules are enabled, local import paths are normally
// canonicalized by modload.ImportPaths before now. However, if there's an
// error resolving a local path, it will be returned untransformed
// so that 'go list -e' reports something useful.
importKey := importSpec{ importKey := importSpec{
path: path, path: path,
parentPath: parentPath, parentPath: parentPath,
......
...@@ -45,11 +45,19 @@ func findStandardImportPath(path string) string { ...@@ -45,11 +45,19 @@ func findStandardImportPath(path string) string {
return "" return ""
} }
// PackageModuleInfo returns information about 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
// ImportPaths or a similar loading function, nil is returned.
func PackageModuleInfo(pkgpath string) *modinfo.ModulePublic { func PackageModuleInfo(pkgpath string) *modinfo.ModulePublic {
if isStandardImportPath(pkgpath) || !Enabled() { if isStandardImportPath(pkgpath) || !Enabled() {
return nil return nil
} }
return moduleInfo(findModule(pkgpath, pkgpath), true) m, ok := findModule(pkgpath)
if !ok {
return nil
}
return moduleInfo(m, true)
} }
func ModuleInfo(path string) *modinfo.ModulePublic { func ModuleInfo(path string) *modinfo.ModulePublic {
...@@ -199,12 +207,11 @@ func PackageBuildInfo(path string, deps []string) string { ...@@ -199,12 +207,11 @@ func PackageBuildInfo(path string, deps []string) string {
if isStandardImportPath(path) || !Enabled() { if isStandardImportPath(path) || !Enabled() {
return "" return ""
} }
target := mustFindModule(path, path)
target := findModule(path, path)
mdeps := make(map[module.Version]bool) mdeps := make(map[module.Version]bool)
for _, dep := range deps { for _, dep := range deps {
if !isStandardImportPath(dep) { if !isStandardImportPath(dep) {
mdeps[findModule(path, dep)] = true mdeps[mustFindModule(path, dep)] = true
} }
} }
var mods []module.Version var mods []module.Version
...@@ -239,9 +246,12 @@ func PackageBuildInfo(path string, deps []string) string { ...@@ -239,9 +246,12 @@ func PackageBuildInfo(path string, deps []string) string {
return buf.String() return buf.String()
} }
// findModule returns the module containing the package at path, // mustFindModule is like findModule, but it calls base.Fatalf if the
// needed to build the package at target. // module can't be found.
func findModule(target, path string) module.Version { //
// TODO(jayconrod): remove this. Callers should use findModule and return
// errors instead of relying on base.Fatalf.
func mustFindModule(target, path string) module.Version {
pkg, ok := loaded.pkgCache.Get(path).(*loadPkg) pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
if ok { if ok {
if pkg.err != nil { if pkg.err != nil {
...@@ -261,6 +271,20 @@ func findModule(target, path string) module.Version { ...@@ -261,6 +271,20 @@ func findModule(target, path string) module.Version {
panic("unreachable") panic("unreachable")
} }
// findModule searches for the module that contains the package at path.
// If the package was loaded with ImportPaths or one of the other loading
// functions, its containing module and true are returned. Otherwise,
// module.Version{} and false are returend.
func findModule(path string) (module.Version, bool) {
if pkg, ok := loaded.pkgCache.Get(path).(*loadPkg); ok {
return pkg.mod, pkg.mod != module.Version{}
}
if path == "command-line-arguments" {
return Target, true
}
return module.Version{}, false
}
func ModInfoProg(info string, isgccgo bool) []byte { func ModInfoProg(info string, isgccgo bool) []byte {
// Inject a variable with the debug information as runtime.modinfo, // Inject a variable with the debug information as runtime.modinfo,
// but compile it in package main so that it is specific to the binary. // but compile it in package main so that it is specific to the binary.
......
...@@ -94,11 +94,11 @@ func ImportPathsQuiet(patterns []string, tags map[string]bool) []*search.Match { ...@@ -94,11 +94,11 @@ func ImportPathsQuiet(patterns []string, tags map[string]bool) []*search.Match {
pkgs := m.Pkgs pkgs := m.Pkgs
m.Pkgs = m.Pkgs[:0] m.Pkgs = m.Pkgs[:0]
for _, pkg := range pkgs { for _, pkg := range pkgs {
dir := pkg var dir string
if !filepath.IsAbs(dir) { if !filepath.IsAbs(pkg) {
dir = filepath.Join(base.Cwd, pkg) dir = filepath.Join(base.Cwd, pkg)
} else { } else {
dir = filepath.Clean(dir) dir = filepath.Clean(pkg)
} }
// golang.org/issue/32917: We should resolve a relative path to a // golang.org/issue/32917: We should resolve a relative path to a
......
# This test checks error messages for non-existant packages in module mode.
# Veries golang.org/issue/35414
env GO111MODULE=on
cd $WORK
go list -e -f {{.Error}} .
stdout 'package \.: no Go files in \$WORK'
go list -e -f {{.Error}} ./empty
stdout 'package \./empty: no Go files in \$WORK[/\\]empty'
go list -e -f {{.Error}} ./exclude
stdout 'package \./exclude: build constraints exclude all Go files in \$WORK[/\\]exclude'
go list -e -f {{.Error}} ./missing
stdout 'package \./missing: cannot find package "." in:\s*\$WORK[/\\]missing'
# use 'go build -n' because 'go list' reports no error.
! go build -n ./testonly
stderr 'example.com/m/testonly: no non-test Go files in \$WORK[/\\]testonly'
-- $WORK/go.mod --
module example.com/m
go 1.14
-- $WORK/empty/empty.txt --
-- $WORK/exclude/exclude.go --
// +build exclude
package exclude
-- $WORK/testonly/testonly_test.go --
package testonly_test
-- $WORK/excluded-stdout --
package ./excluded: cannot find package "." in:
$WORK/excluded
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment