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