github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/cmd/juju/service/flags.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package service 5 6 import ( 7 "fmt" 8 "strings" 9 10 "github.com/juju/errors" 11 12 "github.com/juju/juju/storage" 13 ) 14 15 type storageFlag struct { 16 stores *map[string]storage.Constraints 17 bundleStores *map[string]map[string]storage.Constraints 18 } 19 20 // Set implements gnuflag.Value.Set. 21 func (f storageFlag) Set(s string) error { 22 fields := strings.SplitN(s, "=", 2) 23 if len(fields) < 2 { 24 return errors.New("expected [<service>:]<store>=<constraints>") 25 } 26 var serviceName, storageName string 27 if colon := strings.IndexRune(fields[0], ':'); colon >= 0 { 28 serviceName = fields[0][:colon] 29 storageName = fields[0][colon+1:] 30 } else { 31 storageName = fields[0] 32 } 33 cons, err := storage.ParseConstraints(fields[1]) 34 if err != nil { 35 return errors.Annotate(err, "cannot parse disk constraints") 36 } 37 var stores map[string]storage.Constraints 38 if serviceName != "" { 39 if *f.bundleStores == nil { 40 *f.bundleStores = make(map[string]map[string]storage.Constraints) 41 } 42 stores = (*f.bundleStores)[serviceName] 43 if stores == nil { 44 stores = make(map[string]storage.Constraints) 45 (*f.bundleStores)[serviceName] = stores 46 } 47 } else { 48 if *f.stores == nil { 49 *f.stores = make(map[string]storage.Constraints) 50 } 51 stores = *f.stores 52 } 53 stores[storageName] = cons 54 return nil 55 } 56 57 // String implements gnuflag.Value.String. 58 func (f storageFlag) String() string { 59 strs := make([]string, 0, len(*f.stores)+len(*f.bundleStores)) 60 for store, cons := range *f.stores { 61 strs = append(strs, fmt.Sprintf("%s=%v", store, cons)) 62 } 63 for service, stores := range *f.bundleStores { 64 for store, cons := range stores { 65 strs = append(strs, fmt.Sprintf("%s:%s=%v", service, store, cons)) 66 } 67 } 68 return strings.Join(strs, " ") 69 } 70 71 // stringMap is a type that deserializes a CLI string using gnuflag's Value 72 // semantics. It expects a name=value pair, and supports multiple copies of the 73 // flag adding more pairs, though the names must be unique. 74 type stringMap struct { 75 mapping *map[string]string 76 } 77 78 // Set implements gnuflag.Value's Set method. 79 func (m stringMap) Set(s string) error { 80 if *m.mapping == nil { 81 *m.mapping = map[string]string{} 82 } 83 // make a copy so the following code is less ugly with dereferencing. 84 mapping := *m.mapping 85 86 vals := strings.SplitN(s, "=", 2) 87 if len(vals) != 2 { 88 return errors.NewNotValid(nil, "badly formatted name value pair: "+s) 89 } 90 name, value := vals[0], vals[1] 91 if _, ok := mapping[name]; ok { 92 return errors.Errorf("duplicate name specified: %q", name) 93 } 94 mapping[name] = value 95 return nil 96 } 97 98 // String implements gnuflag.Value's String method 99 func (m stringMap) String() string { 100 pairs := make([]string, 0, len(*m.mapping)) 101 for name, value := range *m.mapping { 102 pairs = append(pairs, name+"="+value) 103 } 104 return strings.Join(pairs, ";") 105 }