github.com/mwhudson/juju@v0.0.0-20160512215208-90ff01f3497f/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  }