package version
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// Operator is a dependancy comparison operator
|
|
type Operator string
|
|
|
|
// ParseOperator parses a string as operator
|
|
func ParseOperator(s string) (Operator, error) {
|
|
op, _, err := parseOperator(s, true)
|
|
return op, err
|
|
}
|
|
|
|
func parseOperator(s string, strict bool) (op Operator, ends int, err error) {
|
|
op = Operator(s)
|
|
if ends = strings.IndexFunc(s, func(r rune) bool {
|
|
return r != '<' && r != '>' && r != '='
|
|
}); ends != -1 {
|
|
// We've hit something not <, > or =
|
|
if !strict {
|
|
op = op[:ends]
|
|
}
|
|
} else {
|
|
ends = len(op)
|
|
}
|
|
if _, known := operators[op]; !known {
|
|
err = fmt.Errorf("version: invalid operator %q", op)
|
|
op = None
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
// Operator types
|
|
const (
|
|
None Operator = ""
|
|
LessThan Operator = "<"
|
|
LessThenOrEqualTo Operator = "<="
|
|
EqualTo Operator = "="
|
|
MoreThanOrEqualTo Operator = ">="
|
|
MoreThan Operator = ">"
|
|
)
|
|
|
|
var operators = map[Operator]bool{
|
|
None: true,
|
|
LessThan: true,
|
|
LessThenOrEqualTo: true,
|
|
EqualTo: true,
|
|
MoreThanOrEqualTo: true,
|
|
MoreThan: true,
|
|
}
|
|
|
|
func (op Operator) String() string {
|
|
return string(op)
|
|
}
|
|
|
|
// Dependency describes a dependency
|
|
type Dependency struct {
|
|
Operator
|
|
Version
|
|
}
|
|
|
|
// ParseDependency parses a string into its prefix and the dependency specifier
|
|
func ParseDependency(s string) (string, Dependency, error) {
|
|
var (
|
|
name = s
|
|
ops string
|
|
dep Dependency
|
|
offset, ends int
|
|
err error
|
|
)
|
|
if offset = strings.Index(name, ": "); offset != -1 {
|
|
// Dependancies may have a comment, which is separated by ": " (notice the
|
|
// space, which is different from epoch)
|
|
name = name[:offset]
|
|
}
|
|
if offset = strings.IndexFunc(name, func(r rune) bool {
|
|
return r == '<' || r == '>' || r == '='
|
|
}); offset != -1 {
|
|
// We have an operator, probably
|
|
name, ops = name[:offset], name[offset:]
|
|
if dep.Operator, ends, err = parseOperator(ops, false); err != nil {
|
|
return "", Dependency{}, err
|
|
}
|
|
dep.Version = Parse(ops[ends:])
|
|
}
|
|
return name, dep, nil
|
|
}
|
|
|
|
// Match this dependency against a version
|
|
func (dep Dependency) Match(version Version) bool {
|
|
if dep.Operator == None {
|
|
return true
|
|
}
|
|
cmp := Compare(version, dep.Version)
|
|
switch dep.Operator {
|
|
case LessThan:
|
|
return cmp == -1
|
|
case LessThenOrEqualTo:
|
|
return cmp <= 0
|
|
case EqualTo:
|
|
return cmp == 0
|
|
case MoreThanOrEqualTo:
|
|
return cmp >= 0
|
|
case MoreThan:
|
|
return cmp == 1
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func (dep Dependency) String() string {
|
|
if dep.Operator == None {
|
|
return ""
|
|
}
|
|
return dep.Operator.String() + dep.Version.String()
|
|
}
|