Files
moxa/interp/build.go

150 lines
3.1 KiB
Go

package interp
import (
"go/parser"
"path"
"runtime"
"strconv"
"strings"
)
// buildOk returns true if a file or script matches build constraints
// as specified in https://golang.org/pkg/go/build/#hdr-Build_Constraints
func (interp *Interpreter) buildOk(name, src string) bool {
// Extract comments before the first clause
f, err := parser.ParseFile(interp.fset, name, src, parser.PackageClauseOnly|parser.ParseComments)
if err != nil {
return false
}
for _, g := range f.Comments {
// in file, evaluate the AND of multiple line build constraints
for _, line := range strings.Split(strings.TrimSpace(g.Text()), "\n") {
if !buildLineOk(line) {
return false
}
}
}
return true
}
// buildLineOk returns true if line is not a build constraint or
// if build constraint is satisfied
func buildLineOk(line string) (ok bool) {
if len(line) < 7 || line[:7] != "+build " {
return true
}
// In line, evaluate the OR of space-separated options
options := strings.Split(strings.TrimSpace(line[6:]), " ")
for _, o := range options {
if ok = buildOptionOk(o); ok {
break
}
}
return ok
}
// buildOptionOk return true if all comma separated tags match, false otherwise
func buildOptionOk(tag string) bool {
// in option, evaluate the AND of individual tags
for _, t := range strings.Split(tag, ",") {
if !buildTagOk(t) {
return false
}
}
return true
}
var (
goos = runtime.GOOS
goarch = runtime.GOARCH
goversion = goNumVersion()
)
// buildTagOk returns true if a build tag matches, false otherwise
// if first character is !, result is negated
func buildTagOk(s string) (r bool) {
not := s[0] == '!'
if not {
s = s[1:]
}
switch {
case s == goos:
r = true
case s == goarch:
r = true
case len(s) > 4 && s[:4] == "go1.":
if n, err := strconv.Atoi(s[4:]); err != nil {
r = false
} else {
r = goversion >= n
}
}
if not {
r = !r
}
return
}
// goNumVersion returns the go minor version number
func goNumVersion() int {
v := strings.Split(runtime.Version(), ".")
n, _ := strconv.Atoi(v[1])
return n
}
// skipFile returns true if file should be skipped
func skipFile(p string) bool {
if !strings.HasSuffix(p, ".go") {
return true
}
p = strings.TrimSuffix(path.Base(p), ".go")
if strings.HasSuffix(p, "_test") {
return true
}
i := strings.Index(p, "_")
if i < 0 {
return false
}
a := strings.Split(p[i+1:], "_")
last := len(a) - 1
if last1 := last - 1; last1 >= 0 && a[last1] == goos && a[last] == goarch {
return false
}
if s := a[last]; s != goos && s != goarch && knownOs[s] || knownArch[s] {
return true
}
return false
}
var knownOs = map[string]bool{
"aix": true,
"android": true,
"darwin": true,
"dragonfly": true,
"freebsd": true,
"js": true,
"linux": true,
"nacl": true,
"netbsd": true,
"openbsd": true,
"plan9": true,
"solaris": true,
"windows": true,
}
var knownArch = map[string]bool{
"386": true,
"amd64": true,
"amd64p32": true,
"arm": true,
"arm64": true,
"mips": true,
"mips64": true,
"mips64le": true,
"mipsle": true,
"ppc64": true,
"ppc64le": true,
"s390x": true,
"wasm": true,
}