//
// Usage:
//
-// go get [-d] [-m] [-u] [-v] [-insecure] [build flags] [packages]
+// go get [-d] [-m] [-t] [-u] [-v] [-insecure] [build flags] [packages]
//
// Get resolves and adds dependencies to the current development module
// and then builds and installs them.
// are competing requirements for a particular module, then 'go get' resolves
// those requirements by taking the maximum requested version.)
//
+// The -t flag instructs get to consider modules needed to build tests of
+// packages specified on the command line.
+//
// The -u flag instructs get to update dependencies to use newer minor or
// patch releases when available. Continuing the previous example,
// 'go get -u A' will use the latest A with B v1.3.1 (not B v1.2.3).
// 'go get -u=patch A@latest' will use the latest A with B v1.2.4 (not B v1.2.3),
// while 'go get -u=patch A' will use a patch release of A instead.
//
+// When the -t and -u flags are used together, get will update
+// test dependencies as well.
+//
// In general, adding a new dependency may require upgrading
// existing dependencies to keep a working build, and 'go get' does
// this automatically. Similarly, downgrading one dependency may
var CmdGet = &base.Command{
// Note: -d -m -u are listed explicitly because they are the most common get flags.
// Do not send CLs removing them because they're covered by [get flags].
- UsageLine: "go get [-d] [-m] [-u] [-v] [-insecure] [build flags] [packages]",
+ UsageLine: "go get [-d] [-m] [-t] [-u] [-v] [-insecure] [build flags] [packages]",
Short: "add dependencies to current module and install them",
Long: `
Get resolves and adds dependencies to the current development module
are competing requirements for a particular module, then 'go get' resolves
those requirements by taking the maximum requested version.)
+The -t flag instructs get to consider modules needed to build tests of
+packages specified on the command line.
+
The -u flag instructs get to update dependencies to use newer minor or
patch releases when available. Continuing the previous example,
'go get -u A' will use the latest A with B v1.3.1 (not B v1.2.3).
'go get -u=patch A@latest' will use the latest A with B v1.2.4 (not B v1.2.3),
while 'go get -u=patch A' will use a patch release of A instead.
+When the -t and -u flags are used together, get will update
+test dependencies as well.
+
In general, adding a new dependency may require upgrading
existing dependencies to keep a working build, and 'go get' does
this automatically. Similarly, downgrading one dependency may
if *getFix {
fmt.Fprintf(os.Stderr, "go get: -fix flag is a no-op when using modules\n")
}
- if *getT {
- fmt.Fprintf(os.Stderr, "go get: -t flag is a no-op when using modules\n")
- }
+ modload.LoadTests = *getT
if cfg.BuildMod == "vendor" {
base.Fatalf("go get: disabled by -mod=%s", cfg.BuildMod)
// Initialize work queue with root packages.
seen := make(map[string]bool)
var work []string
- for pkg := range pkgs {
- seen[pkg] = true
- for _, imp := range modload.PackageImports(pkg) {
- if !pkgs[imp] && !seen[imp] {
- seen[imp] = true
- work = append(work, imp)
- }
+ add := func(path string) {
+ if !seen[path] {
+ seen[path] = true
+ work = append(work, path)
}
}
+ for pkg := range pkgs {
+ add(pkg)
+ }
for len(work) > 0 {
pkg := work[0]
work = work[1:]
m := modload.PackageModule(pkg)
u.upgrade[m.Path] = true
- for _, imp := range modload.PackageImports(pkg) {
- if !seen[imp] {
- seen[imp] = true
- work = append(work, imp)
- }
+ imports, testImports := modload.PackageImports(pkg)
+ for _, imp := range imports {
+ add(imp)
+ }
+ for _, imp := range testImports {
+ add(imp)
}
}
}
}
// PackageImports returns the imports for the package named by the import path.
-// It does not include test imports. It returns nil for unknown packages.
-func PackageImports(path string) []string {
+// Test imports will be returned as well if tests were loaded for the package
+// (i.e., if "all" was loaded or if LoadTests was set and the path was matched
+// by a command line argument). PackageImports will return nil for
+// unknown package paths.
+func PackageImports(path string) (imports, testImports []string) {
pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
if !ok {
- return nil
+ return nil, nil
}
- imports := make([]string, len(pkg.imports))
+ imports = make([]string, len(pkg.imports))
for i, p := range pkg.imports {
imports[i] = p.path
}
- return imports
+ if pkg.test != nil {
+ testImports = make([]string, len(pkg.test.imports))
+ for i, p := range pkg.test.imports {
+ testImports[i] = p.path
+ }
+ }
+ return imports, testImports
}
// ModuleUsedDirectly reports whether the main module directly imports
--- /dev/null
+env GO111MODULE=on
+
+# By default, 'go get' should ignore tests
+cp go.mod.empty go.mod
+go get m/a
+! grep rsc.io/quote go.mod
+
+# 'go get -t' should consider test dependencies of the named package.
+cp go.mod.empty go.mod
+go get -d -t m/a
+grep 'rsc.io/quote v1.5.2$' go.mod
+
+# 'go get -t' should not consider test dependencies of imported packages,
+# including packages imported from tests.
+cp go.mod.empty go.mod
+go get -d -t m/b
+! grep rsc.io/quote go.mod
+
+# 'go get -t -u' should update test dependencies of the named package.
+cp go.mod.empty go.mod
+go mod edit -require=rsc.io/quote@v1.5.1
+go get -d -t -u m/a
+grep 'rsc.io/quote v1.5.2$' go.mod
+
+# 'go get -t -u' should not add or update test dependencies
+# of imported packages, including packages imported from tests.
+cp go.mod.empty go.mod
+go get -d -t -u m/b
+! grep rsc.io/quote go.mod
+go mod edit -require=rsc.io/quote@v1.5.1
+go get -d -t -u m/b
+grep 'rsc.io/quote v1.5.1$' go.mod
+
+# 'go get all' should consider test dependencies with or without -t.
+cp go.mod.empty go.mod
+go get all
+grep 'rsc.io/quote v1.5.2$' go.mod
+
+-- go.mod.empty --
+module m
+
+-- a/a.go --
+package a
+
+-- a/a_test.go --
+package a_test
+
+import _ "rsc.io/quote"
+
+-- b/b.go --
+package b
+
+import _ "m/a"
+
+-- b/b_test.go --
+package b_test
+
+import _ "m/a"