cmd/go: fix mod_install_pkg_version

mainPackagesOnly now includes non-main packages matched by literal
arguments in the returned slice, since their errors must be reported.

GoFilesPackages attaches the same error to its package if
opts.MainOnly is true. This changes the error output of 'go run'
slightly, but it seems like an imporovement.

For #42088

Change-Id: I8f2942470383af5d4c9763022bc94338f5314b07
Reviewed-on: https://go-review.googlesource.com/c/go/+/310829
Trust: Jay Conrod <jayconrod@google.com>
Run-TryBot: Jay Conrod <jayconrod@google.com>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
Jay Conrod 2021-04-16 13:34:37 -04:00
parent 60abe01321
commit 492eb059f9
5 changed files with 34 additions and 16 deletions

View file

@ -480,6 +480,7 @@ type ImportPathError interface {
var ( var (
_ ImportPathError = (*importError)(nil) _ ImportPathError = (*importError)(nil)
_ ImportPathError = (*mainPackageError)(nil)
_ ImportPathError = (*modload.ImportMissingError)(nil) _ ImportPathError = (*modload.ImportMissingError)(nil)
_ ImportPathError = (*modload.ImportMissingSumError)(nil) _ ImportPathError = (*modload.ImportMissingSumError)(nil)
_ ImportPathError = (*modload.DirectImportFromImplicitDependencyError)(nil) _ ImportPathError = (*modload.DirectImportFromImplicitDependencyError)(nil)
@ -2545,7 +2546,8 @@ func CheckPackageErrors(pkgs []*Package) {
// mainPackagesOnly filters out non-main packages matched only by arguments // mainPackagesOnly filters out non-main packages matched only by arguments
// containing "..." and returns the remaining main packages. // containing "..." and returns the remaining main packages.
// //
// mainPackagesOnly sets a package's error if it is named by a literal argument. // mainPackagesOnly sets a non-main package's Error field and returns it if it
// is named by a literal argument.
// //
// mainPackagesOnly prints warnings for non-literal arguments that only match // mainPackagesOnly prints warnings for non-literal arguments that only match
// non-main packages. // non-main packages.
@ -2557,12 +2559,12 @@ func mainPackagesOnly(pkgs []*Package, patterns []string) []*Package {
} }
} }
mainPkgs := make([]*Package, 0, len(pkgs)) matchedPkgs := make([]*Package, 0, len(pkgs))
mainCount := make([]int, len(patterns)) mainCount := make([]int, len(patterns))
nonMainCount := make([]int, len(patterns)) nonMainCount := make([]int, len(patterns))
for _, pkg := range pkgs { for _, pkg := range pkgs {
if pkg.Name == "main" { if pkg.Name == "main" {
mainPkgs = append(mainPkgs, pkg) matchedPkgs = append(matchedPkgs, pkg)
for i := range patterns { for i := range patterns {
if matchers[i] != nil && matchers[i](pkg.ImportPath) { if matchers[i] != nil && matchers[i](pkg.ImportPath) {
mainCount[i]++ mainCount[i]++
@ -2570,8 +2572,11 @@ func mainPackagesOnly(pkgs []*Package, patterns []string) []*Package {
} }
} else { } else {
for i := range patterns { for i := range patterns {
if matchers[i] == nil && patterns[i] == pkg.ImportPath && pkg.Error == nil { if matchers[i] == nil && patterns[i] == pkg.ImportPath {
pkg.Error = &PackageError{Err: ImportErrorf(pkg.ImportPath, "package %s is not a main package", pkg.ImportPath)} if pkg.Error == nil {
pkg.Error = &PackageError{Err: &mainPackageError{importPath: pkg.ImportPath}}
}
matchedPkgs = append(matchedPkgs, pkg)
} else if matchers[i] != nil && matchers[i](pkg.ImportPath) { } else if matchers[i] != nil && matchers[i](pkg.ImportPath) {
nonMainCount[i]++ nonMainCount[i]++
} }
@ -2584,7 +2589,19 @@ func mainPackagesOnly(pkgs []*Package, patterns []string) []*Package {
} }
} }
return mainPkgs return matchedPkgs
}
type mainPackageError struct {
importPath string
}
func (e *mainPackageError) Error() string {
return fmt.Sprintf("package %s is not a main package", e.importPath)
}
func (e *mainPackageError) ImportPath() string {
return e.importPath
} }
func setToolFlags(pkgs ...*Package) { func setToolFlags(pkgs ...*Package) {
@ -2679,6 +2696,9 @@ func GoFilesPackage(ctx context.Context, opts PackageOpts, gofiles []string) *Pa
} }
} }
if opts.MainOnly && pkg.Name != "main" && pkg.Error == nil {
pkg.Error = &PackageError{Err: &mainPackageError{importPath: pkg.ImportPath}}
}
setToolFlags(pkg) setToolFlags(pkg)
return pkg return pkg

View file

@ -92,6 +92,7 @@ func runRun(ctx context.Context, cmd *base.Command, args []string) {
for i < len(args) && strings.HasSuffix(args[i], ".go") { for i < len(args) && strings.HasSuffix(args[i], ".go") {
i++ i++
} }
pkgOpts := load.PackageOpts{MainOnly: true}
var p *load.Package var p *load.Package
if i > 0 { if i > 0 {
files := args[:i] files := args[:i]
@ -102,10 +103,9 @@ func runRun(ctx context.Context, cmd *base.Command, args []string) {
base.Fatalf("go run: cannot run *_test.go files (%s)", file) base.Fatalf("go run: cannot run *_test.go files (%s)", file)
} }
} }
p = load.GoFilesPackage(ctx, load.PackageOpts{}, files) p = load.GoFilesPackage(ctx, pkgOpts, files)
} else if len(args) > 0 && !strings.HasPrefix(args[0], "-") { } else if len(args) > 0 && !strings.HasPrefix(args[0], "-") {
arg := args[0] arg := args[0]
pkgOpts := load.PackageOpts{MainOnly: true}
var pkgs []*load.Package var pkgs []*load.Package
if strings.Contains(arg, "@") && !build.IsLocalImport(arg) && !filepath.IsAbs(arg) { if strings.Contains(arg, "@") && !build.IsLocalImport(arg) && !filepath.IsAbs(arg) {
var err error var err error
@ -133,9 +133,6 @@ func runRun(ctx context.Context, cmd *base.Command, args []string) {
base.Fatalf("go run: no go files listed") base.Fatalf("go run: no go files listed")
} }
cmdArgs := args[i:] cmdArgs := args[i:]
if p.Name != "main" {
base.Fatalf("go run: cannot run non-main package")
}
load.CheckPackageErrors([]*load.Package{p}) load.CheckPackageErrors([]*load.Package{p})
p.Internal.OmitDebug = true p.Internal.OmitDebug = true

View file

@ -118,7 +118,7 @@ stderr '^package rsc.io/fortune provided by module rsc.io/fortune@v1.0.0\n\tAll
# 'go install pkg@version' should report an error if an argument is not # 'go install pkg@version' should report an error if an argument is not
# a main package. # a main package.
! go install example.com/cmd/a@v1.0.0 example.com/cmd/err@v1.0.0 ! go install example.com/cmd/a@v1.0.0 example.com/cmd/err@v1.0.0
stderr '^go: package example.com/cmd/err is not a main package$' stderr '^package example.com/cmd/err is not a main package$'
# Wildcards should match only main packages. This module has a non-main package # Wildcards should match only main packages. This module has a non-main package
# with an error, so we'll know if that gets built. # with an error, so we'll know if that gets built.

View file

@ -207,10 +207,6 @@ stderr 'needmod[/\\]needmod.go:10:2: no required module provides package example
go install cmd/addr2line go install cmd/addr2line
! stderr . ! stderr .
# 'go run' with a version should fail due to syntax.
! go run example.com/printversion@v1.0.0
stderr 'can only use path@version syntax with'
# 'go run' should fail if a package argument must be resolved to a module. # 'go run' should fail if a package argument must be resolved to a module.
! go run example.com/printversion ! go run example.com/printversion
stderr '^no required module provides package example.com/printversion: go.mod file not found in current directory or any parent directory; see ''go help modules''$' stderr '^no required module provides package example.com/printversion: go.mod file not found in current directory or any parent directory; see ''go help modules''$'

View file

@ -36,6 +36,11 @@ stderr '^go: found rsc.io/quote in rsc.io/quote v1.5.2$'
stderr '^Hello, world.$' stderr '^Hello, world.$'
# 'go run pkg@version' should report an error if pkg is not a main package.
! go run example.com/cmd/err@v1.0.0
stderr '^package example.com/cmd/err is not a main package$'
# 'go run pkg@version' should report errors if the module contains # 'go run pkg@version' should report errors if the module contains
# replace or exclude directives. # replace or exclude directives.
go mod download example.com/cmd@v1.0.0-replace go mod download example.com/cmd@v1.0.0-replace