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  }