package genericresource import ( "encoding/csv" "fmt" "strconv" "strings" "github.com/moby/swarmkit/v2/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 }