github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/cmd/juju/action/common.go (about)

     1  // Copyright 2014-2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package action
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/loggo"
     9  	"github.com/juju/names"
    10  
    11  	"github.com/juju/juju/apiserver/params"
    12  )
    13  
    14  var logger = loggo.GetLogger("juju.cmd.juju.action")
    15  
    16  // getActionTagByPrefix uses the APIClient to get all ActionTags matching a prefix.
    17  func getActionTagsByPrefix(api APIClient, prefix string) ([]names.ActionTag, error) {
    18  	results := []names.ActionTag{}
    19  
    20  	tags, err := api.FindActionTagsByPrefix(params.FindTags{Prefixes: []string{prefix}})
    21  	if err != nil {
    22  		return results, err
    23  	}
    24  
    25  	matches, ok := tags.Matches[prefix]
    26  	if !ok || len(matches) < 1 {
    27  		return results, nil
    28  	}
    29  
    30  	results, rejects := getActionTags(matches)
    31  	if len(rejects) > 0 {
    32  		logger.Errorf("FindActionTagsByPrefix for prefix %q found invalid tags %v", prefix, rejects)
    33  	}
    34  	return results, nil
    35  }
    36  
    37  // getActionTagByPrefix uses the APIClient to get an ActionTag from a prefix.
    38  func getActionTagByPrefix(api APIClient, prefix string) (names.ActionTag, error) {
    39  	tag := names.ActionTag{}
    40  	actiontags, err := getActionTagsByPrefix(api, prefix)
    41  	if err != nil {
    42  		return tag, err
    43  	}
    44  
    45  	if len(actiontags) < 1 {
    46  		return tag, errors.Errorf("actions for identifier %q not found", prefix)
    47  	}
    48  
    49  	if len(actiontags) > 1 {
    50  		return tag, errors.Errorf("identifier %q matched multiple actions %v", prefix, actiontags)
    51  	}
    52  
    53  	return actiontags[0], nil
    54  }
    55  
    56  // getActionTags converts a slice of params.Entity to a slice of names.ActionTag, and
    57  // also populates a slice of strings for the params.Entity.Tag that are not a valid
    58  // names.ActionTag.
    59  func getActionTags(entities []params.Entity) (good []names.ActionTag, bad []string) {
    60  	for _, entity := range entities {
    61  		if tag, err := entityToActionTag(entity); err != nil {
    62  			bad = append(bad, entity.Tag)
    63  		} else {
    64  			good = append(good, tag)
    65  		}
    66  	}
    67  	return
    68  }
    69  
    70  // entityToActionTag converts the params.Entity type to a names.ActionTag
    71  func entityToActionTag(entity params.Entity) (names.ActionTag, error) {
    72  	return names.ParseActionTag(entity.Tag)
    73  }
    74  
    75  // addValueToMap adds the given value to the map on which the method is run.
    76  // This allows us to merge maps such as {foo: {bar: baz}} and {foo: {baz: faz}}
    77  // into {foo: {bar: baz, baz: faz}}.
    78  func addValueToMap(keys []string, value interface{}, target map[string]interface{}) {
    79  	next := target
    80  
    81  	for i := range keys {
    82  		// If we are on last key set or overwrite the val.
    83  		if i == len(keys)-1 {
    84  			next[keys[i]] = value
    85  			break
    86  		}
    87  
    88  		if iface, ok := next[keys[i]]; ok {
    89  			switch typed := iface.(type) {
    90  			case map[string]interface{}:
    91  				// If we already had a map inside, keep
    92  				// stepping through.
    93  				next = typed
    94  			default:
    95  				// If we didn't, then overwrite value
    96  				// with a map and iterate with that.
    97  				m := map[string]interface{}{}
    98  				next[keys[i]] = m
    99  				next = m
   100  			}
   101  			continue
   102  		}
   103  
   104  		// Otherwise, it wasn't present, so make it and step
   105  		// into.
   106  		m := map[string]interface{}{}
   107  		next[keys[i]] = m
   108  		next = m
   109  	}
   110  }