Commit 6f7542e4 authored by Jay Conrod's avatar Jay Conrod

cmd/go: ignore build tags when 'go get' modifies build list

In module mode, 'go get' should not consider build constraints when
loading packages in order to modify the module graph. With this
change, 'go get' considers all build tags to be true except for
"ignore" and malformed build constraint expressions.

When 'go get' builds packages, it still applies build constraints for
the target platform.

Fixes #32345

Change-Id: I6dceae6f10a5185870537de730b36292271ad124
Reviewed-on: https://go-review.googlesource.com/c/go/+/179898Reviewed-by: default avatarBryan C. Mills <bcmills@google.com>
parent 64c134f9
...@@ -8,6 +8,9 @@ import "cmd/go/internal/cfg" ...@@ -8,6 +8,9 @@ import "cmd/go/internal/cfg"
var tags map[string]bool var tags map[string]bool
// Tags returns a set of build tags that are true for the target platform.
// It includes GOOS, GOARCH, the compiler, possibly "cgo",
// release tags like "go1.13", and user-specified build tags.
func Tags() map[string]bool { func Tags() map[string]bool {
if tags == nil { if tags == nil {
tags = loadTags() tags = loadTags()
...@@ -32,3 +35,15 @@ func loadTags() map[string]bool { ...@@ -32,3 +35,15 @@ func loadTags() map[string]bool {
} }
return tags return tags
} }
var anyTags map[string]bool
// AnyTags returns a special set of build tags that satisfy nearly all
// build tag expressions. Only "ignore" and malformed build tag requirements
// are considered false.
func AnyTags() map[string]bool {
if anyTags == nil {
anyTags = map[string]bool{"*": true}
}
return anyTags
}
...@@ -166,8 +166,6 @@ func matchMetadata(dir string, info os.FileInfo) bool { ...@@ -166,8 +166,6 @@ func matchMetadata(dir string, info os.FileInfo) bool {
return false return false
} }
var anyTagsExceptIgnore = map[string]bool{"*": true}
// matchPotentialSourceFile reports whether info may be relevant to a build operation. // matchPotentialSourceFile reports whether info may be relevant to a build operation.
func matchPotentialSourceFile(dir string, info os.FileInfo) bool { func matchPotentialSourceFile(dir string, info os.FileInfo) bool {
if strings.HasSuffix(info.Name(), "_test.go") { if strings.HasSuffix(info.Name(), "_test.go") {
...@@ -181,7 +179,7 @@ func matchPotentialSourceFile(dir string, info os.FileInfo) bool { ...@@ -181,7 +179,7 @@ func matchPotentialSourceFile(dir string, info os.FileInfo) bool {
defer f.Close() defer f.Close()
content, err := imports.ReadImports(f, false, nil) content, err := imports.ReadImports(f, false, nil)
if err == nil && !imports.ShouldBuild(content, anyTagsExceptIgnore) { if err == nil && !imports.ShouldBuild(content, imports.AnyTags()) {
// The file is explicitly tagged "ignore", so it can't affect the build. // The file is explicitly tagged "ignore", so it can't affect the build.
// Leave it out. // Leave it out.
return false return false
......
...@@ -9,6 +9,7 @@ import ( ...@@ -9,6 +9,7 @@ import (
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/get" "cmd/go/internal/get"
"cmd/go/internal/imports"
"cmd/go/internal/load" "cmd/go/internal/load"
"cmd/go/internal/modfetch" "cmd/go/internal/modfetch"
"cmd/go/internal/modload" "cmd/go/internal/modload"
...@@ -446,9 +447,8 @@ func runGet(cmd *base.Command, args []string) { ...@@ -446,9 +447,8 @@ func runGet(cmd *base.Command, args []string) {
// Don't load packages if pkgPatterns is empty. Both // Don't load packages if pkgPatterns is empty. Both
// modload.ImportPathsQuiet and ModulePackages convert an empty list // modload.ImportPathsQuiet and ModulePackages convert an empty list
// of patterns to []string{"."}, which is not what we want. // of patterns to []string{"."}, which is not what we want.
matches = modload.ImportPathsQuiet(pkgPatterns) matches = modload.ImportPathsQuiet(pkgPatterns, imports.AnyTags())
seenPkgs = make(map[string]bool) seenPkgs = make(map[string]bool)
install = make([]string, 0, len(pkgPatterns))
for i, match := range matches { for i, match := range matches {
arg := pkgGets[i] arg := pkgGets[i]
...@@ -462,7 +462,6 @@ func runGet(cmd *base.Command, args []string) { ...@@ -462,7 +462,6 @@ func runGet(cmd *base.Command, args []string) {
continue continue
} }
install = append(install, arg.path)
allStd := true allStd := true
for _, pkg := range match.Pkgs { for _, pkg := range match.Pkgs {
if !seenPkgs[pkg] { if !seenPkgs[pkg] {
...@@ -513,7 +512,11 @@ func runGet(cmd *base.Command, args []string) { ...@@ -513,7 +512,11 @@ func runGet(cmd *base.Command, args []string) {
} }
prevBuildList = buildList prevBuildList = buildList
} }
search.WarnUnmatched(matches) // don't warn on every iteration if !*getD {
// Only print warnings after the last iteration,
// and only if we aren't going to build.
search.WarnUnmatched(matches)
}
// Handle downgrades. // Handle downgrades.
var down []module.Version var down []module.Version
...@@ -606,16 +609,17 @@ func runGet(cmd *base.Command, args []string) { ...@@ -606,16 +609,17 @@ func runGet(cmd *base.Command, args []string) {
// If -d was specified, we're done after the module work. // If -d was specified, we're done after the module work.
// We've already downloaded modules by loading packages above. // We've already downloaded modules by loading packages above.
// Otherwise, we need to build and install the packages matched // Otherwise, we need to build and install the packages matched by
// by command line arguments. // command line arguments. This may be a different set of packages,
// Note that 'go get -u' without any arguments results in // since we only build packages for the target platform.
// len(install) == 1 if there's a package in the current directory. // Note that 'go get -u' without arguments is equivalent to
// search.CleanPatterns returns "." for empty args. // 'go get -u .', so we'll typically build the package in the current
if *getD || len(install) == 0 { // directory.
if *getD || len(pkgPatterns) == 0 {
return return
} }
work.BuildInit() work.BuildInit()
pkgs := load.PackagesForBuild(install) pkgs := load.PackagesForBuild(pkgPatterns)
work.InstallPackages(install, pkgs) work.InstallPackages(install, pkgs)
} }
......
...@@ -51,15 +51,19 @@ var buildList []module.Version ...@@ -51,15 +51,19 @@ var buildList []module.Version
var loaded *loader var loaded *loader
// ImportPaths returns the set of packages matching the args (patterns), // ImportPaths returns the set of packages matching the args (patterns),
// adding modules to the build list as needed to satisfy new imports. // on the target platform. Modules may be added to the build list
// to satisfy new imports.
func ImportPaths(patterns []string) []*search.Match { func ImportPaths(patterns []string) []*search.Match {
matches := ImportPathsQuiet(patterns) matches := ImportPathsQuiet(patterns, imports.Tags())
search.WarnUnmatched(matches) search.WarnUnmatched(matches)
return matches return matches
} }
// ImportPathsQuiet is like ImportPaths but does not warn about patterns with no matches. // ImportPathsQuiet is like ImportPaths but does not warn about patterns with
func ImportPathsQuiet(patterns []string) []*search.Match { // no matches. It also lets the caller specify a set of build tags to match
// packages. The build tags should typically be imports.Tags() or
// imports.AnyTags(); a nil map has no special meaning.
func ImportPathsQuiet(patterns []string, tags map[string]bool) []*search.Match {
var fsDirs [][]string var fsDirs [][]string
updateMatches := func(matches []*search.Match, iterating bool) { updateMatches := func(matches []*search.Match, iterating bool) {
for i, m := range matches { for i, m := range matches {
...@@ -179,7 +183,7 @@ func ImportPathsQuiet(patterns []string) []*search.Match { ...@@ -179,7 +183,7 @@ func ImportPathsQuiet(patterns []string) []*search.Match {
}) })
} }
loaded = newLoader() loaded = newLoader(tags)
loaded.load(func() []string { loaded.load(func() []string {
var roots []string var roots []string
updateMatches(matches, true) updateMatches(matches, true)
...@@ -258,12 +262,13 @@ func warnPattern(pattern string, list []string) []string { ...@@ -258,12 +262,13 @@ func warnPattern(pattern string, list []string) []string {
func ImportFromFiles(gofiles []string) { func ImportFromFiles(gofiles []string) {
InitMod() InitMod()
imports, testImports, err := imports.ScanFiles(gofiles, imports.Tags()) tags := imports.Tags()
imports, testImports, err := imports.ScanFiles(gofiles, tags)
if err != nil { if err != nil {
base.Fatalf("go: %v", err) base.Fatalf("go: %v", err)
} }
loaded = newLoader() loaded = newLoader(tags)
loaded.load(func() []string { loaded.load(func() []string {
var roots []string var roots []string
roots = append(roots, imports...) roots = append(roots, imports...)
...@@ -312,7 +317,7 @@ func LoadBuildList() []module.Version { ...@@ -312,7 +317,7 @@ func LoadBuildList() []module.Version {
} }
func ReloadBuildList() []module.Version { func ReloadBuildList() []module.Version {
loaded = newLoader() loaded = newLoader(imports.Tags())
loaded.load(func() []string { return nil }) loaded.load(func() []string { return nil })
return buildList return buildList
} }
...@@ -338,9 +343,8 @@ func LoadVendor() []string { ...@@ -338,9 +343,8 @@ func LoadVendor() []string {
func loadAll(testAll bool) []string { func loadAll(testAll bool) []string {
InitMod() InitMod()
loaded = newLoader() loaded = newLoader(imports.AnyTags())
loaded.isALL = true loaded.isALL = true
loaded.tags = anyTags
loaded.testAll = testAll loaded.testAll = testAll
if !testAll { if !testAll {
loaded.testRoots = true loaded.testRoots = true
...@@ -359,15 +363,11 @@ func loadAll(testAll bool) []string { ...@@ -359,15 +363,11 @@ func loadAll(testAll bool) []string {
return paths return paths
} }
// anyTags is a special tags map that satisfies nearly all build tag expressions.
// Only "ignore" and malformed build tag requirements are considered false.
var anyTags = map[string]bool{"*": true}
// TargetPackages returns the list of packages in the target (top-level) module // TargetPackages returns the list of packages in the target (top-level) module
// matching pattern, which may be relative to the working directory, under all // matching pattern, which may be relative to the working directory, under all
// build tag settings. // build tag settings.
func TargetPackages(pattern string) []string { func TargetPackages(pattern string) []string {
return matchPackages(pattern, anyTags, false, []module.Version{Target}) return matchPackages(pattern, imports.AnyTags(), false, []module.Version{Target})
} }
// BuildList returns the module build list, // BuildList returns the module build list,
...@@ -510,9 +510,9 @@ type loader struct { ...@@ -510,9 +510,9 @@ type loader struct {
// LoadTests controls whether the loaders load tests of the root packages. // LoadTests controls whether the loaders load tests of the root packages.
var LoadTests bool var LoadTests bool
func newLoader() *loader { func newLoader(tags map[string]bool) *loader {
ld := new(loader) ld := new(loader)
ld.tags = imports.Tags() ld.tags = tags
ld.testRoots = LoadTests ld.testRoots = LoadTests
// Inside the "std" and "cmd" modules, we prefer to use the vendor directory // Inside the "std" and "cmd" modules, we prefer to use the vendor directory
......
...@@ -12,6 +12,7 @@ import ( ...@@ -12,6 +12,7 @@ import (
"strings" "strings"
"sync" "sync"
"cmd/go/internal/imports"
"cmd/go/internal/modfetch" "cmd/go/internal/modfetch"
"cmd/go/internal/module" "cmd/go/internal/module"
"cmd/go/internal/search" "cmd/go/internal/search"
...@@ -265,7 +266,7 @@ func QueryPattern(pattern, query string, allowed func(module.Version) bool) ([]Q ...@@ -265,7 +266,7 @@ func QueryPattern(pattern, query string, allowed func(module.Version) bool) ([]Q
if i := strings.Index(pattern, "..."); i >= 0 { if i := strings.Index(pattern, "..."); i >= 0 {
base = pathpkg.Dir(pattern[:i+3]) base = pathpkg.Dir(pattern[:i+3])
match = func(m module.Version, root string, isLocal bool) []string { match = func(m module.Version, root string, isLocal bool) []string {
return matchPackages(pattern, anyTags, false, []module.Version{m}) return matchPackages(pattern, imports.AnyTags(), false, []module.Version{m})
} }
} else { } else {
match = func(m module.Version, root string, isLocal bool) []string { match = func(m module.Version, root string, isLocal bool) []string {
......
env GO111MODULE=on
[short] skip
# get should add modules needed to build packages, even if those
# dependencies are in sources excluded by build tags.
# All build tags are considered true except "ignore".
go mod init m
go get -d .
go list -m all
stdout 'example.com/version v1.1.0'
stdout 'rsc.io/quote v1.5.2'
[short] skip
# Packages that are only imported in excluded files should not be built.
go get -x .
stderr 'compile.* -p m '
! stderr 'compile.* -p example.com/version '
! stderr 'compile.* -p rsc.io/quote '
-- empty.go --
package m
-- excluded.go --
// +build windows,mips
package m
import _ "example.com/version"
-- tools.go --
// +build tools
package tools
import _ "rsc.io/quote"
-- ignore.go --
// +build ignore
package ignore
import _ "example.com/doesnotexist"
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