1
0
mirror of https://github.com/golang/go synced 2024-11-26 03:47:57 -07:00

test/run: process build tags like go/build

R=bradfitz, dave, rsc, r
CC=golang-dev
https://golang.org/cl/10001045
This commit is contained in:
Anthony Martin 2013-08-13 12:25:41 -04:00 committed by Russ Cox
parent 71c6da39ce
commit a538558003
2 changed files with 105 additions and 33 deletions

View File

@ -27,6 +27,7 @@ import (
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
"unicode"
) )
var ( var (
@ -299,14 +300,17 @@ func goDirPackages(longdir string) ([][]string, error) {
return pkgs, nil return pkgs, nil
} }
type context struct {
GOOS string
GOARCH string
}
// shouldTest looks for build tags in a source file and returns // shouldTest looks for build tags in a source file and returns
// whether the file should be used according to the tags. // whether the file should be used according to the tags.
func shouldTest(src string, goos, goarch string) (ok bool, whyNot string) { func shouldTest(src string, goos, goarch string) (ok bool, whyNot string) {
if idx := strings.Index(src, "\npackage"); idx >= 0 { if idx := strings.Index(src, "\npackage"); idx >= 0 {
src = src[:idx] src = src[:idx]
} }
notgoos := "!" + goos
notgoarch := "!" + goarch
for _, line := range strings.Split(src, "\n") { for _, line := range strings.Split(src, "\n") {
line = strings.TrimSpace(line) line = strings.TrimSpace(line)
if strings.HasPrefix(line, "//") { if strings.HasPrefix(line, "//") {
@ -318,29 +322,59 @@ func shouldTest(src string, goos, goarch string) (ok bool, whyNot string) {
if len(line) == 0 || line[0] != '+' { if len(line) == 0 || line[0] != '+' {
continue continue
} }
ctxt := &context{
GOOS: goos,
GOARCH: goarch,
}
words := strings.Fields(line) words := strings.Fields(line)
if words[0] == "+build" { if words[0] == "+build" {
for _, word := range words { ok := false
switch word { for _, word := range words[1:] {
case goos, goarch: if ctxt.match(word) {
return true, "" ok = true
case notgoos, notgoarch: break
continue
default:
if word[0] == '!' {
// NOT something-else
return true, ""
}
} }
} }
// no matching tag found. if !ok {
return false, line // no matching tag found.
return false, line
}
} }
} }
// no build tags. // no build tags
return true, "" return true, ""
} }
func (ctxt *context) match(name string) bool {
if name == "" {
return false
}
if i := strings.Index(name, ","); i >= 0 {
// comma-separated list
return ctxt.match(name[:i]) && ctxt.match(name[i+1:])
}
if strings.HasPrefix(name, "!!") { // bad syntax, reject always
return false
}
if strings.HasPrefix(name, "!") { // negation
return len(name) > 1 && !ctxt.match(name[1:])
}
// Tags must be letters, digits, underscores or dots.
// Unlike in Go identifiers, all digits are fine (e.g., "386").
for _, c := range name {
if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' {
return false
}
}
if name == ctxt.GOOS || name == ctxt.GOARCH {
return true
}
return false
}
func init() { checkShouldTest() } func init() { checkShouldTest() }
// run runs a test. // run runs a test.
@ -815,7 +849,7 @@ func defaultRunOutputLimit() int {
return cpu return cpu
} }
// checkShouldTest runs canity checks on the shouldTest function. // checkShouldTest runs sanity checks on the shouldTest function.
func checkShouldTest() { func checkShouldTest() {
assert := func(ok bool, _ string) { assert := func(ok bool, _ string) {
if !ok { if !ok {
@ -823,11 +857,28 @@ func checkShouldTest() {
} }
} }
assertNot := func(ok bool, _ string) { assert(!ok, "") } assertNot := func(ok bool, _ string) { assert(!ok, "") }
// Simple tests.
assert(shouldTest("// +build linux", "linux", "arm")) assert(shouldTest("// +build linux", "linux", "arm"))
assert(shouldTest("// +build !windows", "linux", "arm")) assert(shouldTest("// +build !windows", "linux", "arm"))
assertNot(shouldTest("// +build !windows", "windows", "amd64")) assertNot(shouldTest("// +build !windows", "windows", "amd64"))
assertNot(shouldTest("// +build arm 386", "linux", "amd64"))
// A file with no build tags will always be tested.
assert(shouldTest("// This is a test.", "os", "arch")) assert(shouldTest("// This is a test.", "os", "arch"))
// Build tags separated by a space are OR-ed together.
assertNot(shouldTest("// +build arm 386", "linux", "amd64"))
// Build tags seperated by a comma are AND-ed together.
assertNot(shouldTest("// +build !windows,!plan9", "windows", "amd64"))
assertNot(shouldTest("// +build !windows,!plan9", "plan9", "386"))
// Build tags on multiple lines are AND-ed together.
assert(shouldTest("// +build !windows\n// +build amd64", "linux", "amd64"))
assertNot(shouldTest("// +build !windows\n// +build amd64", "windows", "amd64"))
// Test that (!a OR !b) matches anything.
assert(shouldTest("// +build !windows !plan9", "windows", "amd64"))
} }
// envForDir returns a copy of the environment // envForDir returns a copy of the environment

View File

@ -16,29 +16,50 @@ pkgs() {
done | sort done | sort
} }
_match() {
case $1 in
*,*)
#echo >&2 "match comma separated $1"
first=$(echo $1 | sed 's/,.*//')
rest=$(echo $1 | sed 's/[^,]*,//')
if _match $first && _match $rest; then
return 0
fi
return 1
;;
'!'*)
#echo >&2 "match negation $1"
neg=$(echo $1 | sed 's/^!//')
if _match $neg; then
return 1
fi
return 0
;;
$GOARCH|$GOOS)
#echo >&2 "match GOARCH or GOOS $1"
return 0
;;
esac
return 1
}
# +build aborts execution if the supplied tags don't match, # +build aborts execution if the supplied tags don't match,
# i.e. none of the tags (x or !x) matches GOARCH or GOOS. # i.e. none of the tags (x or !x) matches GOARCH or GOOS.
+build() { +build() {
if (( $# == 0 )); then if (( $# == 0 )); then
return return
fi fi
m=0
for tag; do for tag; do
case $tag in if _match $tag; then
$GOARCH|$GOOS) m=1
#echo >&2 "match $tag in $1" fi
return # don't exclude.
;;
'!'$GOARCH|'!'$GOOS)
;;
'!'*)
# not x where x is neither GOOS nor GOARCH.
#echo >&2 "match $tag in $1"
return # don't exclude
;;
esac
done done
# no match. if [ $m = 0 ]; then
exit 0 #echo >&2 no match
exit 0
fi
unset m
} }
compile() { compile() {