From 64d8846aaef4b64d2649917581069c0ec30ca561 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Fri, 11 Dec 2020 16:45:39 -0500 Subject: [PATCH] cmd/go: print hint when 'go install' run without version outside module If 'go install' is invoked in module mode outside a module with a package that could only be loaded from a module, it will now suggest running 'go install pkg@latest'. 'go install' will still work outside a module on packages in std and cmd, as well as .go files specified on the command line. Fixes #42638 Change-Id: Ib0963935f028b7656178bc04a279b1114de35fbb Reviewed-on: https://go-review.googlesource.com/c/go/+/277355 Run-TryBot: Jay Conrod Trust: Jay Conrod Reviewed-by: Bryan C. Mills --- src/cmd/go/internal/work/build.go | 26 +++++++++++++++++++++- src/cmd/go/testdata/script/mod_outside.txt | 5 ++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go index 1f99ed6e07..7f2617cf1c 100644 --- a/src/cmd/go/internal/work/build.go +++ b/src/cmd/go/internal/work/build.go @@ -583,8 +583,31 @@ func runInstall(ctx context.Context, cmd *base.Command, args []string) { return } } + BuildInit() pkgs := load.PackagesAndErrors(ctx, args) + if cfg.ModulesEnabled && !modload.HasModRoot() { + haveErrors := false + allMissingErrors := true + for _, pkg := range pkgs { + if pkg.Error == nil { + continue + } + haveErrors = true + if missingErr := (*modload.ImportMissingError)(nil); !errors.As(pkg.Error, &missingErr) { + allMissingErrors = false + break + } + } + if haveErrors && allMissingErrors { + latestArgs := make([]string, len(args)) + for i := range args { + latestArgs[i] = args[i] + "@latest" + } + hint := strings.Join(latestArgs, " ") + base.Fatalf("go install: version is required when current directory is not in a module\n\tTry 'go install %s' to install the latest version", hint) + } + } load.CheckPackageErrors(pkgs) if cfg.BuildI { allGoroot := true @@ -598,6 +621,7 @@ func runInstall(ctx context.Context, cmd *base.Command, args []string) { fmt.Fprint(os.Stderr, "go install: -i flag is deprecated\n") } } + InstallPackages(ctx, args, pkgs) } @@ -815,7 +839,7 @@ func installOutsideModule(ctx context.Context, args []string) { // Load packages for all arguments. Ignore non-main packages. // Print a warning if an argument contains "..." and matches no main packages. - // PackagesForBuild already prints warnings for patterns that don't match any + // PackagesAndErrors already prints warnings for patterns that don't match any // packages, so be careful not to double print. matchers := make([]func(string) bool, len(patterns)) for i, p := range patterns { diff --git a/src/cmd/go/testdata/script/mod_outside.txt b/src/cmd/go/testdata/script/mod_outside.txt index 28379ab40d..8f01b5d242 100644 --- a/src/cmd/go/testdata/script/mod_outside.txt +++ b/src/cmd/go/testdata/script/mod_outside.txt @@ -189,13 +189,16 @@ exists $GOPATH/bin/printversion$GOEXE # 'go install' should fail if a package argument must be resolved to a module. ! go install example.com/printversion -stderr 'no required module provides package example.com/printversion: working directory is not part of a module' +stderr '^go install: version is required when current directory is not in a module\n\tTry ''go install example.com/printversion@latest'' to install the latest version$' # 'go install' should fail if a source file imports a package that must be # resolved to a module. ! go install ./needmod/needmod.go stderr 'needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: working directory is not part of a module' +# 'go install' should succeed with a package in GOROOT. +go install cmd/addr2line +! stderr . # 'go run' with a verison should fail due to syntax. ! go run example.com/printversion@v1.0.0 -- 2.48.1