buildtags: doc exported symbols (#9)
This commit is contained in:
@@ -1,3 +1,24 @@
|
|||||||
|
// Package buildtags provides types for representing and manipulating build constraints.
|
||||||
|
//
|
||||||
|
// In Go, build constraints are represented as comments in source code together with file naming conventions. For example
|
||||||
|
//
|
||||||
|
// // +build linux,386 darwin,!cgo
|
||||||
|
// // +build !purego
|
||||||
|
//
|
||||||
|
// Any terms provided in the filename can be thought of as an implicit extra
|
||||||
|
// constraint comment line. Collectively, these are referred to as
|
||||||
|
// ``constraints''. Each line is a ``constraint''. Within each constraint the
|
||||||
|
// space-separated terms are ``options'', and within that the comma-separated
|
||||||
|
// items are ``terms'' which may be negated with at most one exclaimation mark.
|
||||||
|
//
|
||||||
|
// These represent a boolean formulae. The constraints are evaluated as the AND
|
||||||
|
// of constraint lines; a constraint is evaluated as the OR of its options and
|
||||||
|
// an option is evaluated as the AND of its terms. Overall build constraints are
|
||||||
|
// a boolean formula that is an AND of ORs of ANDs.
|
||||||
|
//
|
||||||
|
// This level of complexity is rarely used in Go programs. Therefore this
|
||||||
|
// package aims to provide access to all these layers of nesting if required,
|
||||||
|
// but make it easy to forget about for basic use cases too.
|
||||||
package buildtags
|
package buildtags
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -31,6 +52,7 @@ import (
|
|||||||
// // (linux OR darwin) AND 386
|
// // (linux OR darwin) AND 386
|
||||||
//
|
//
|
||||||
|
|
||||||
|
// Interface represents a build constraint.
|
||||||
type Interface interface {
|
type Interface interface {
|
||||||
ConstraintsConvertable
|
ConstraintsConvertable
|
||||||
fmt.GoStringer
|
fmt.GoStringer
|
||||||
@@ -38,27 +60,37 @@ type Interface interface {
|
|||||||
Validate() error
|
Validate() error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ConstraintsConvertable can be converted to a Constraints object.
|
||||||
type ConstraintsConvertable interface {
|
type ConstraintsConvertable interface {
|
||||||
ToConstraints() Constraints
|
ToConstraints() Constraints
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ConstraintConvertable can be converted to a Constraint.
|
||||||
type ConstraintConvertable interface {
|
type ConstraintConvertable interface {
|
||||||
ToConstraint() Constraint
|
ToConstraint() Constraint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OptionConvertable can be converted to an Option.
|
||||||
type OptionConvertable interface {
|
type OptionConvertable interface {
|
||||||
ToOption() Option
|
ToOption() Option
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
// Constraints represents the AND of a list of Constraint lines.
|
||||||
Constraints []Constraint
|
type Constraints []Constraint
|
||||||
Constraint []Option
|
|
||||||
Option []Term
|
|
||||||
Term string
|
|
||||||
)
|
|
||||||
|
|
||||||
|
// And builds Constraints that will be true if all of its constraints are true.
|
||||||
|
func And(cs ...ConstraintConvertable) Constraints {
|
||||||
|
constraints := Constraints{}
|
||||||
|
for _, c := range cs {
|
||||||
|
constraints = append(constraints, c.ToConstraint())
|
||||||
|
}
|
||||||
|
return constraints
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToConstraints returns cs.
|
||||||
func (cs Constraints) ToConstraints() Constraints { return cs }
|
func (cs Constraints) ToConstraints() Constraints { return cs }
|
||||||
|
|
||||||
|
// Validate validates the constraints set.
|
||||||
func (cs Constraints) Validate() error {
|
func (cs Constraints) Validate() error {
|
||||||
for _, c := range cs {
|
for _, c := range cs {
|
||||||
if err := c.Validate(); err != nil {
|
if err := c.Validate(); err != nil {
|
||||||
@@ -68,6 +100,8 @@ func (cs Constraints) Validate() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Evaluate the boolean formula represented by cs under the given assignment of
|
||||||
|
// tag values. This is the AND of the values of the constituent Constraints.
|
||||||
func (cs Constraints) Evaluate(v map[string]bool) bool {
|
func (cs Constraints) Evaluate(v map[string]bool) bool {
|
||||||
r := true
|
r := true
|
||||||
for _, c := range cs {
|
for _, c := range cs {
|
||||||
@@ -76,6 +110,7 @@ func (cs Constraints) Evaluate(v map[string]bool) bool {
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GoString represents Constraints as +build comment lines.
|
||||||
func (cs Constraints) GoString() string {
|
func (cs Constraints) GoString() string {
|
||||||
s := ""
|
s := ""
|
||||||
for _, c := range cs {
|
for _, c := range cs {
|
||||||
@@ -84,9 +119,38 @@ func (cs Constraints) GoString() string {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Constraint represents the OR of a list of Options.
|
||||||
|
type Constraint []Option
|
||||||
|
|
||||||
|
// Any builds a Constraint that will be true if any of its options are true.
|
||||||
|
func Any(opts ...OptionConvertable) Constraint {
|
||||||
|
c := Constraint{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
c = append(c, opt.ToOption())
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseConstraint parses a space-separated list of options.
|
||||||
|
func ParseConstraint(expr string) (Constraint, error) {
|
||||||
|
c := Constraint{}
|
||||||
|
for _, field := range strings.Fields(expr) {
|
||||||
|
opt, err := ParseOption(field)
|
||||||
|
if err != nil {
|
||||||
|
return c, err
|
||||||
|
}
|
||||||
|
c = append(c, opt)
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToConstraints returns the list of constraints containing just c.
|
||||||
func (c Constraint) ToConstraints() Constraints { return Constraints{c} }
|
func (c Constraint) ToConstraints() Constraints { return Constraints{c} }
|
||||||
|
|
||||||
|
// ToConstraint returns c.
|
||||||
func (c Constraint) ToConstraint() Constraint { return c }
|
func (c Constraint) ToConstraint() Constraint { return c }
|
||||||
|
|
||||||
|
// Validate validates the constraint.
|
||||||
func (c Constraint) Validate() error {
|
func (c Constraint) Validate() error {
|
||||||
for _, o := range c {
|
for _, o := range c {
|
||||||
if err := o.Validate(); err != nil {
|
if err := o.Validate(); err != nil {
|
||||||
@@ -96,6 +160,8 @@ func (c Constraint) Validate() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Evaluate the boolean formula represented by c under the given assignment of
|
||||||
|
// tag values. This is the OR of the values of the constituent Options.
|
||||||
func (c Constraint) Evaluate(v map[string]bool) bool {
|
func (c Constraint) Evaluate(v map[string]bool) bool {
|
||||||
r := false
|
r := false
|
||||||
for _, o := range c {
|
for _, o := range c {
|
||||||
@@ -104,6 +170,7 @@ func (c Constraint) Evaluate(v map[string]bool) bool {
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GoString represents the Constraint as one +build comment line.
|
||||||
func (c Constraint) GoString() string {
|
func (c Constraint) GoString() string {
|
||||||
s := "// +build"
|
s := "// +build"
|
||||||
for _, o := range c {
|
for _, o := range c {
|
||||||
@@ -112,10 +179,33 @@ func (c Constraint) GoString() string {
|
|||||||
return s + "\n"
|
return s + "\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Option represents the AND of a list of Terms.
|
||||||
|
type Option []Term
|
||||||
|
|
||||||
|
// Opt builds an Option from the list of Terms.
|
||||||
|
func Opt(terms ...Term) Option {
|
||||||
|
return Option(terms)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseOption parses a comma-separated list of terms.
|
||||||
|
func ParseOption(expr string) (Option, error) {
|
||||||
|
opt := Option{}
|
||||||
|
for _, t := range strings.Split(expr, ",") {
|
||||||
|
opt = append(opt, Term(t))
|
||||||
|
}
|
||||||
|
return opt, opt.Validate()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToConstraints returns Constraints containing just this option.
|
||||||
func (o Option) ToConstraints() Constraints { return o.ToConstraint().ToConstraints() }
|
func (o Option) ToConstraints() Constraints { return o.ToConstraint().ToConstraints() }
|
||||||
|
|
||||||
|
// ToConstraint returns a Constraint containing just this option.
|
||||||
func (o Option) ToConstraint() Constraint { return Constraint{o} }
|
func (o Option) ToConstraint() Constraint { return Constraint{o} }
|
||||||
|
|
||||||
|
// ToOption returns o.
|
||||||
func (o Option) ToOption() Option { return o }
|
func (o Option) ToOption() Option { return o }
|
||||||
|
|
||||||
|
// Validate validates o.
|
||||||
func (o Option) Validate() error {
|
func (o Option) Validate() error {
|
||||||
for _, t := range o {
|
for _, t := range o {
|
||||||
if err := t.Validate(); err != nil {
|
if err := t.Validate(); err != nil {
|
||||||
@@ -125,6 +215,8 @@ func (o Option) Validate() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Evaluate the boolean formula represented by o under the given assignment of
|
||||||
|
// tag values. This is the AND of the values of the constituent Terms.
|
||||||
func (o Option) Evaluate(v map[string]bool) bool {
|
func (o Option) Evaluate(v map[string]bool) bool {
|
||||||
r := true
|
r := true
|
||||||
for _, t := range o {
|
for _, t := range o {
|
||||||
@@ -133,6 +225,7 @@ func (o Option) Evaluate(v map[string]bool) bool {
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GoString represents the Option as a comma-separated list of terms.
|
||||||
func (o Option) GoString() string {
|
func (o Option) GoString() string {
|
||||||
var ts []string
|
var ts []string
|
||||||
for _, t := range o {
|
for _, t := range o {
|
||||||
@@ -141,16 +234,32 @@ func (o Option) GoString() string {
|
|||||||
return strings.Join(ts, ",")
|
return strings.Join(ts, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Term is an atomic term in a build constraint: an identifier or its negation.
|
||||||
|
type Term string
|
||||||
|
|
||||||
|
// Not returns a term for the negation of ident.
|
||||||
|
func Not(ident string) Term {
|
||||||
|
return Term("!" + ident)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToConstraints returns Constraints containing just this term.
|
||||||
func (t Term) ToConstraints() Constraints { return t.ToOption().ToConstraints() }
|
func (t Term) ToConstraints() Constraints { return t.ToOption().ToConstraints() }
|
||||||
|
|
||||||
|
// ToConstraint returns a Constraint containing just this term.
|
||||||
func (t Term) ToConstraint() Constraint { return t.ToOption().ToConstraint() }
|
func (t Term) ToConstraint() Constraint { return t.ToOption().ToConstraint() }
|
||||||
|
|
||||||
|
// ToOption returns an Option containing just this term.
|
||||||
func (t Term) ToOption() Option { return Option{t} }
|
func (t Term) ToOption() Option { return Option{t} }
|
||||||
|
|
||||||
|
// IsNegated reports whether t is the negation of an identifier.
|
||||||
func (t Term) IsNegated() bool { return strings.HasPrefix(string(t), "!") }
|
func (t Term) IsNegated() bool { return strings.HasPrefix(string(t), "!") }
|
||||||
|
|
||||||
|
// Name returns the identifier for this term.
|
||||||
func (t Term) Name() string {
|
func (t Term) Name() string {
|
||||||
return strings.TrimPrefix(string(t), "!")
|
return strings.TrimPrefix(string(t), "!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate the term.
|
||||||
func (t Term) Validate() error {
|
func (t Term) Validate() error {
|
||||||
// Reference: https://github.com/golang/go/blob/204a8f55dc2e0ac8d27a781dab0da609b98560da/src/cmd/go/internal/imports/build.go#L110-L112
|
// Reference: https://github.com/golang/go/blob/204a8f55dc2e0ac8d27a781dab0da609b98560da/src/cmd/go/internal/imports/build.go#L110-L112
|
||||||
//
|
//
|
||||||
@@ -185,60 +294,19 @@ func (t Term) Validate() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Evaluate the term under the given set of identifier values.
|
||||||
func (t Term) Evaluate(v map[string]bool) bool {
|
func (t Term) Evaluate(v map[string]bool) bool {
|
||||||
return (t.Validate() == nil) && (v[t.Name()] == !t.IsNegated())
|
return (t.Validate() == nil) && (v[t.Name()] == !t.IsNegated())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GoString returns t.
|
||||||
func (t Term) GoString() string { return string(t) }
|
func (t Term) GoString() string { return string(t) }
|
||||||
|
|
||||||
func Not(ident string) Term {
|
// SetTags builds a set where the given list of identifiers are true.
|
||||||
return Term("!" + ident)
|
func SetTags(idents ...string) map[string]bool {
|
||||||
}
|
|
||||||
|
|
||||||
func And(cs ...ConstraintConvertable) Constraints {
|
|
||||||
constraints := Constraints{}
|
|
||||||
for _, c := range cs {
|
|
||||||
constraints = append(constraints, c.ToConstraint())
|
|
||||||
}
|
|
||||||
return constraints
|
|
||||||
}
|
|
||||||
|
|
||||||
func Any(opts ...OptionConvertable) Constraint {
|
|
||||||
c := Constraint{}
|
|
||||||
for _, opt := range opts {
|
|
||||||
c = append(c, opt.ToOption())
|
|
||||||
}
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func Opt(terms ...Term) Option {
|
|
||||||
return Option(terms)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseOption(expr string) (Option, error) {
|
|
||||||
opt := Option{}
|
|
||||||
for _, t := range strings.Split(expr, ",") {
|
|
||||||
opt = append(opt, Term(t))
|
|
||||||
}
|
|
||||||
return opt, opt.Validate()
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseConstraint(expr string) (Constraint, error) {
|
|
||||||
c := Constraint{}
|
|
||||||
for _, field := range strings.Fields(expr) {
|
|
||||||
opt, err := ParseOption(field)
|
|
||||||
if err != nil {
|
|
||||||
return c, err
|
|
||||||
}
|
|
||||||
c = append(c, opt)
|
|
||||||
}
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetTags(names ...string) map[string]bool {
|
|
||||||
v := map[string]bool{}
|
v := map[string]bool{}
|
||||||
for _, n := range names {
|
for _, ident := range idents {
|
||||||
v[n] = true
|
v[ident] = true
|
||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|||||||
16
buildtags/examples_test.go
Normal file
16
buildtags/examples_test.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package buildtags_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/mmcloughlin/avo/buildtags"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleParseConstraint() {
|
||||||
|
c, err := buildtags.ParseConstraint("a,!b c")
|
||||||
|
fmt.Print(c.GoString())
|
||||||
|
fmt.Println(err)
|
||||||
|
// Output:
|
||||||
|
// // +build a,!b c
|
||||||
|
// <nil>
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user