github.com/kaisenlinux/docker@v0.0.0-20230510090727-ea55db55fac7/swarmkit/api/genericresource/parse.go (about) 1 package genericresource 2 3 import ( 4 "encoding/csv" 5 "fmt" 6 "strconv" 7 "strings" 8 9 "github.com/docker/swarmkit/api" 10 ) 11 12 func newParseError(format string, args ...interface{}) error { 13 return fmt.Errorf("could not parse GenericResource: "+format, args...) 14 } 15 16 // discreteResourceVal returns an int64 if the string is a discreteResource 17 // and an error if it isn't 18 func discreteResourceVal(res string) (int64, error) { 19 return strconv.ParseInt(res, 10, 64) 20 } 21 22 // allNamedResources returns true if the array of resources are all namedResources 23 // e.g: res = [red, orange, green] 24 func allNamedResources(res []string) bool { 25 for _, v := range res { 26 if _, err := discreteResourceVal(v); err == nil { 27 return false 28 } 29 } 30 31 return true 32 } 33 34 // ParseCmd parses the Generic Resource command line argument 35 // and returns a list of *api.GenericResource 36 func ParseCmd(cmd string) ([]*api.GenericResource, error) { 37 if strings.Contains(cmd, "\n") { 38 return nil, newParseError("unexpected '\\n' character") 39 } 40 41 r := csv.NewReader(strings.NewReader(cmd)) 42 records, err := r.ReadAll() 43 44 if err != nil { 45 return nil, newParseError("%v", err) 46 } 47 48 if len(records) != 1 { 49 return nil, newParseError("found multiple records while parsing cmd %v", records) 50 } 51 52 return Parse(records[0]) 53 } 54 55 // Parse parses a table of GenericResource resources 56 func Parse(cmds []string) ([]*api.GenericResource, error) { 57 tokens := make(map[string][]string) 58 59 for _, term := range cmds { 60 kva := strings.Split(term, "=") 61 if len(kva) != 2 { 62 return nil, newParseError("incorrect term %s, missing"+ 63 " '=' or malformed expression", term) 64 } 65 66 key := strings.TrimSpace(kva[0]) 67 val := strings.TrimSpace(kva[1]) 68 69 tokens[key] = append(tokens[key], val) 70 } 71 72 var rs []*api.GenericResource 73 for k, v := range tokens { 74 if u, ok := isDiscreteResource(v); ok { 75 if u < 0 { 76 return nil, newParseError("cannot ask for"+ 77 " negative resource %s", k) 78 } 79 80 rs = append(rs, NewDiscrete(k, u)) 81 continue 82 } 83 84 if allNamedResources(v) { 85 rs = append(rs, NewSet(k, v...)...) 86 continue 87 } 88 89 return nil, newParseError("mixed discrete and named resources"+ 90 " in expression '%s=%s'", k, v) 91 } 92 93 return rs, nil 94 } 95 96 // isDiscreteResource returns true if the array of resources is a 97 // Discrete Resource. 98 // e.g: res = [1] 99 func isDiscreteResource(values []string) (int64, bool) { 100 if len(values) != 1 { 101 return int64(0), false 102 } 103 104 u, err := discreteResourceVal(values[0]) 105 if err != nil { 106 return int64(0), false 107 } 108 109 return u, true 110 111 }