cmd/go/internal/vgo: allow vgo get of module with no package in root
Historically "go get" has meant both "download these packages" and
"install these packages". For example "go get rsc.io/github/issue"
downloads that package but also builds and installs it (into $GOBIN/issue).
Similarly "go get golang.org/x/text/number" downloads, builds, and
installs that package (not a package main).
If one needs to just download a whole repo, it has always tripped
up users that "go get golang.org/x/text" fails, because there are no
Go source files in that directory (the root of that repo, it turns out).
Go modules compound this problem, because it is quite natural
to want to run "go get golang.org/x/text@v0.1.0" to add (or to
upgrade or downgrade to) that specific version of golang.org/x/text.
This CL changes "go get" to make this common usage not an error:
if the path is successfully identified as a directory within a known
module, then if there's no code there, "go get" just skips the
"build and install" step, instead of reporting an error.
This way, command installations like "go get rsc.io/github/issue"
continue to work, but now module installations like "go get golang.org/x/text"
or "go get golang.org/x/text@v0.1.0" also now succeed.
Fixes golang/go#24008.
Change-Id: I977ab448bc13a4391e85f63052b8373e30f77026
Reviewed-on: https://go-review.googlesource.com/120995
Reviewed-by: Bryan C. Mills <bcmills@google.com>
diff --git a/vendor/cmd/go/internal/vgo/get.go b/vendor/cmd/go/internal/vgo/get.go
index 6a12e06..f19364f 100644
--- a/vendor/cmd/go/internal/vgo/get.go
+++ b/vendor/cmd/go/internal/vgo/get.go
@@ -8,6 +8,7 @@
"strings"
"cmd/go/internal/base"
+ "cmd/go/internal/load"
"cmd/go/internal/modfetch"
"cmd/go/internal/module"
"cmd/go/internal/mvs"
@@ -16,7 +17,7 @@
)
var CmdGet = &base.Command{
- UsageLine: "get [build flags] [packages]",
+ UsageLine: "get [build flags] [modules or packages]",
Short: "download and install versioned modules and dependencies",
Long: `
Get downloads the latest versions of modules containing the named packages,
@@ -25,6 +26,15 @@
It then installs the named packages, like 'go install'.
+By default, get downloads the named packages, updates go.mod, and builds the packages.
+As a special case if a package is a module root and has no code, no error is reported.
+
+TODO make this better
+
+The -m flag causes get to update the module file but not build anything.
+
+The -d flag causes get to download the code and update the module file but not build anything.
+
The -u flag causes get to download the latest version of dependencies as well.
Each package being updated can be suffixed with @version to specify
@@ -36,7 +46,11 @@
`,
}
-var getU = CmdGet.Flag.Bool("u", false, "")
+var (
+ getD = CmdGet.Flag.Bool("d", false, "")
+ getM = CmdGet.Flag.Bool("m", false, "")
+ getU = CmdGet.Flag.Bool("u", false, "")
+)
func init() {
CmdGet.Run = runGet // break init loop
@@ -52,7 +66,7 @@
}
if *getU {
- ImportPaths([]string{"."})
+ LoadBuildList()
return
}
@@ -105,7 +119,7 @@
base.Fatalf("vgo get: %v", err)
}
- importPaths([]string{"."})
+ LoadBuildList()
// Downgrade anything that went too far.
version := make(map[string]string)
@@ -144,7 +158,25 @@
}
WriteGoMod()
+ if *getD {
+ // Download all needed code as side-effect.
+ ImportPaths([]string{"ALL"})
+ }
+
+ if *getM {
+ return
+ }
+
if len(args) > 0 {
- work.CmdInstall.Run(work.CmdInstall, args)
+ work.BuildInit()
+ var list []string
+ for _, p := range load.PackagesAndErrors(args) {
+ if p.Error == nil || !strings.HasPrefix(p.Error.Err, "no Go files") {
+ list = append(list, p.ImportPath)
+ }
+ }
+ if len(list) > 0 {
+ work.InstallPackages(list, false)
+ }
}
}
diff --git a/vendor/cmd/go/internal/vgo/load.go b/vendor/cmd/go/internal/vgo/load.go
index 8653a27..6668470 100644
--- a/vendor/cmd/go/internal/vgo/load.go
+++ b/vendor/cmd/go/internal/vgo/load.go
@@ -272,6 +272,11 @@
imports, testImports, err := scanDir(dir, ld.tags)
if err != nil {
+ if strings.HasPrefix(err.Error(), "no Go ") {
+ // Don't print about directories with no Go source files.
+ // Let the eventual real package load do that.
+ return
+ }
base.Errorf("vgo: %s [%s]: %v", ld.stackText(), dir, err)
return
}
diff --git a/vendor/cmd/go/vgo_test.go b/vendor/cmd/go/vgo_test.go
index 5fd8469..e2dc6c5 100644
--- a/vendor/cmd/go/vgo_test.go
+++ b/vendor/cmd/go/vgo_test.go
@@ -268,7 +268,7 @@
tg.cd(tg.path("x"))
tg.runFail("-vgo", "list", "-f={{.GoFiles}}")
- tg.grepStderr("no Go source files", "no Go source files without tags")
+ tg.grepStderr("build constraints exclude all Go files", "no Go source files without tags")
tg.run("-vgo", "list", "-f={{.GoFiles}}", "-tags=tag1")
tg.grepStdout(`\[x.go\]`, "Go source files for tag1")
@@ -346,6 +346,31 @@
tg.run("-vgo", "get", "github.com/gobuffalo/uuid@v1.2.0")
tg.run("-vgo", "list", "-m", "all")
tg.grepStdout("github.com/gobuffalo/uuid.*v1.2.0", "did upgrade to v1.2.0")
+
+ // @7f39a6fea4fe9364 should resolve,
+ // and also there should be no build error about not having Go files in the root.
+ tg.run("-vgo", "get", "golang.org/x/crypto@7f39a6fea4fe9364")
+
+ // @7f39a6fea4fe9364 should resolve.
+ // Now there should be no build at all.
+ tg.run("-vgo", "get", "-m", "golang.org/x/crypto@7f39a6fea4fe9364")
+
+ // TODO(rsc): These should work, but "go get" needs more work
+ // regarding packages versus modules.
+
+ // @7f39a6fea4fe9364 should resolve.
+ // Now there should be no build at all.
+ // tg.run("-vgo", "get", "-m", "-x", "golang.org/x/crypto/pbkdf2@7f39a6fea4fe9364")
+ // tg.grepStderrNot("compile", "should not see compile steps")
+
+ // @7f39a6fea4fe9364 should resolve.
+ // Now there should be a build
+ // tg.run("-vgo", "get", "-x", "golang.org/x/crypto/pbkdf2@7f39a6fea4fe9364")
+ // tg.grepStderr("compile", "should see compile steps")
+
+ // .../pbkdf2@7f39a6fea4fe9364 should NOT resolve:
+ // we are using -m and .../pbkdf2 is not a module path.
+ tg.runFail("-vgo", "get", "-m", "golang.org/x/crypto/pbkdf2@7f39a6fea4fe9364")
}
func TestVgoBadDomain(t *testing.T) {