blob: f39a7077a8decc7285a0cf9fda6295fe1511ad33 [file] [log] [blame]
package genericresource
import (
"encoding/csv"
"fmt"
"strconv"
"strings"
"github.com/docker/swarmkit/api"
)
func newParseError(format string, args ...interface{}) error {
return fmt.Errorf("could not parse GenericResource: "+format, args...)
}
// discreteResourceVal returns an int64 if the string is a discreteResource
// and an error if it isn't
func discreteResourceVal(res string) (int64, error) {
return strconv.ParseInt(res, 10, 64)
}
// allNamedResources returns true if the array of resources are all namedResources
// e.g: res = [red, orange, green]
func allNamedResources(res []string) bool {
for _, v := range res {
if _, err := discreteResourceVal(v); err == nil {
return false
}
}
return true
}
// ParseCmd parses the Generic Resource command line argument
// and returns a list of *api.GenericResource
func ParseCmd(cmd string) ([]*api.GenericResource, error) {
if strings.Contains(cmd, "\n") {
return nil, newParseError("unexpected '\\n' character")
}
r := csv.NewReader(strings.NewReader(cmd))
records, err := r.ReadAll()
if err != nil {
return nil, newParseError("%v", err)
}
if len(records) != 1 {
return nil, newParseError("found multiple records while parsing cmd %v", records)
}
return Parse(records[0])
}
// Parse parses a table of GenericResource resources
func Parse(cmds []string) ([]*api.GenericResource, error) {
tokens := make(map[string][]string)
for _, term := range cmds {
kva := strings.Split(term, "=")
if len(kva) != 2 {
return nil, newParseError("incorrect term %s, missing"+
" '=' or malformed expression", term)
}
key := strings.TrimSpace(kva[0])
val := strings.TrimSpace(kva[1])
tokens[key] = append(tokens[key], val)
}
var rs []*api.GenericResource
for k, v := range tokens {
if u, ok := isDiscreteResource(v); ok {
if u < 0 {
return nil, newParseError("cannot ask for"+
" negative resource %s", k)
}
rs = append(rs, NewDiscrete(k, u))
continue
}
if allNamedResources(v) {
rs = append(rs, NewSet(k, v...)...)
continue
}
return nil, newParseError("mixed discrete and named resources"+
" in expression '%s=%s'", k, v)
}
return rs, nil
}
// isDiscreteResource returns true if the array of resources is a
// Discrete Resource.
// e.g: res = [1]
func isDiscreteResource(values []string) (int64, bool) {
if len(values) != 1 {
return int64(0), false
}
u, err := discreteResourceVal(values[0])
if err != nil {
return int64(0), false
}
return u, true
}