mirror of https://github.com/docker/docs.git
118 lines
2.4 KiB
Go
118 lines
2.4 KiB
Go
package filter
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
|
|
log "github.com/Sirupsen/logrus"
|
|
)
|
|
|
|
const (
|
|
// EQ is exported
|
|
EQ = iota
|
|
// NOTEQ is exported
|
|
NOTEQ
|
|
)
|
|
|
|
// OPERATORS is exported
|
|
var OPERATORS = []string{"==", "!="}
|
|
|
|
type expr struct {
|
|
key string
|
|
operator int
|
|
value string
|
|
isSoft bool
|
|
}
|
|
|
|
func parseExprs(key string, env []string) ([]expr, error) {
|
|
exprs := []expr{}
|
|
for _, e := range env {
|
|
if strings.HasPrefix(e, key+":") {
|
|
entry := strings.TrimPrefix(e, key+":")
|
|
found := false
|
|
for i, op := range OPERATORS {
|
|
if strings.Contains(entry, op) {
|
|
// split with the op
|
|
parts := strings.SplitN(entry, op, 2)
|
|
|
|
// validate key
|
|
// allow alpha-numeric
|
|
matched, err := regexp.MatchString(`^(?i)[a-z_][a-z0-9\-_]+$`, parts[0])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if matched == false {
|
|
return nil, fmt.Errorf("Key '%s' is invalid", parts[0])
|
|
}
|
|
|
|
if len(parts) == 2 {
|
|
|
|
// validate value
|
|
// allow leading = in case of using ==
|
|
// allow * for globbing
|
|
// allow regexp
|
|
matched, err := regexp.MatchString(`^(?i)[=!\/]?(~)?[a-z0-9:\-_\.\*/\(\)\?\+\[\]\\\^\$]+$`, parts[1])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if matched == false {
|
|
return nil, fmt.Errorf("Value '%s' is invalid", parts[1])
|
|
}
|
|
exprs = append(exprs, expr{key: strings.ToLower(parts[0]), operator: i, value: strings.TrimLeft(parts[1], "~"), isSoft: isSoft(parts[1])})
|
|
} else {
|
|
exprs = append(exprs, expr{key: strings.ToLower(parts[0]), operator: i})
|
|
}
|
|
|
|
found = true
|
|
break // found an op, move to next entry
|
|
}
|
|
}
|
|
if !found {
|
|
return nil, fmt.Errorf("One of operator ==, != is expected")
|
|
}
|
|
}
|
|
}
|
|
return exprs, nil
|
|
}
|
|
|
|
func (e *expr) Match(whats ...string) bool {
|
|
var (
|
|
pattern string
|
|
match bool
|
|
err error
|
|
)
|
|
|
|
if e.value[0] == '/' && e.value[len(e.value)-1] == '/' {
|
|
// regexp
|
|
pattern = e.value[1 : len(e.value)-1]
|
|
} else {
|
|
// simple match, create the regex for globbing (ex: ub*t* -> ^ub.*t.*$) and match.
|
|
pattern = "^" + strings.Replace(e.value, "*", ".*", -1) + "$"
|
|
}
|
|
|
|
for _, what := range whats {
|
|
if match, err = regexp.MatchString(pattern, what); match {
|
|
break
|
|
} else if err != nil {
|
|
log.Error(err)
|
|
}
|
|
}
|
|
|
|
switch e.operator {
|
|
case EQ:
|
|
return match
|
|
case NOTEQ:
|
|
return !match
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func isSoft(value string) bool {
|
|
if value[0] == '~' {
|
|
return true
|
|
}
|
|
return false
|
|
}
|