github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/resource/cmd/list_charm_resources.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package cmd
     5  
     6  import (
     7  	"github.com/juju/cmd"
     8  	"github.com/juju/errors"
     9  	"github.com/juju/gnuflag"
    10  	"gopkg.in/juju/charm.v6-unstable"
    11  	charmresource "gopkg.in/juju/charm.v6-unstable/resource"
    12  	csparams "gopkg.in/juju/charmrepo.v2-unstable/csclient/params"
    13  
    14  	"github.com/juju/juju/charmstore"
    15  	"github.com/juju/juju/cmd/modelcmd"
    16  )
    17  
    18  // CharmResourceLister lists resources for the given charm ids.
    19  type ResourceLister interface {
    20  	ListResources(ids []charmstore.CharmID) ([][]charmresource.Resource, error)
    21  }
    22  
    23  // ListCharmResourcesCommand implements the "juju charm resources" command.
    24  type ListCharmResourcesCommand struct {
    25  	modelcmd.ModelCommandBase
    26  
    27  	// ResourceLister is called by Run to list charm resources. The
    28  	// default implementation uses juju/juju/charmstore.Client, but
    29  	// it may be set to mock out the call to that method.
    30  	ResourceLister ResourceLister
    31  
    32  	out     cmd.Output
    33  	channel string
    34  	charm   string
    35  }
    36  
    37  // NewListCharmResourcesCommand returns a new command that lists resources defined
    38  // by a charm.
    39  func NewListCharmResourcesCommand() *ListCharmResourcesCommand {
    40  	var c ListCharmResourcesCommand
    41  	c.ResourceLister = &c
    42  	return &c
    43  }
    44  
    45  var listCharmResourcesDoc = `
    46  This command will report the resources for a charm in the charm store.
    47  
    48  <charm> can be a charm URL, or an unambiguously condensed form of it,
    49  just like the deploy command. So the following forms will be accepted:
    50  
    51  For cs:trusty/mysql
    52    mysql
    53    trusty/mysql
    54  
    55  For cs:~user/trusty/mysql
    56    cs:~user/mysql
    57  
    58  Where the series is not supplied, the series from your local host is used.
    59  Thus the above examples imply that the local series is trusty.
    60  `
    61  
    62  // Info implements cmd.Command.
    63  func (c *ListCharmResourcesCommand) Info() *cmd.Info {
    64  	return &cmd.Info{
    65  		Name:    "resources",
    66  		Args:    "<charm>",
    67  		Purpose: "display the resources for a charm in the charm store",
    68  		Doc:     listCharmResourcesDoc,
    69  		Aliases: []string{"list-resources"},
    70  	}
    71  }
    72  
    73  // SetFlags implements cmd.Command.
    74  func (c *ListCharmResourcesCommand) SetFlags(f *gnuflag.FlagSet) {
    75  	c.ModelCommandBase.SetFlags(f)
    76  	defaultFormat := "tabular"
    77  	c.out.AddFlags(f, defaultFormat, map[string]cmd.Formatter{
    78  		"tabular": FormatCharmTabular,
    79  		"yaml":    cmd.FormatYaml,
    80  		"json":    cmd.FormatJson,
    81  	})
    82  	f.StringVar(&c.channel, "channel", "stable", "the charmstore channel of the charm")
    83  }
    84  
    85  // Init implements cmd.Command.
    86  func (c *ListCharmResourcesCommand) Init(args []string) error {
    87  	if len(args) == 0 {
    88  		return errors.New("missing charm")
    89  	}
    90  	c.charm = args[0]
    91  
    92  	if err := cmd.CheckEmpty(args[1:]); err != nil {
    93  		return errors.Trace(err)
    94  	}
    95  	return nil
    96  }
    97  
    98  // Run implements cmd.Command.
    99  func (c *ListCharmResourcesCommand) Run(ctx *cmd.Context) error {
   100  	// TODO(ericsnow) Adjust this to the charm store.
   101  
   102  	charmURLs, err := resolveCharms([]string{c.charm})
   103  	if err != nil {
   104  		return errors.Trace(err)
   105  	}
   106  
   107  	charms := make([]charmstore.CharmID, len(charmURLs))
   108  	for i, id := range charmURLs {
   109  		charms[i] = charmstore.CharmID{URL: id, Channel: csparams.Channel(c.channel)}
   110  	}
   111  
   112  	resources, err := c.ResourceLister.ListResources(charms)
   113  	if err != nil {
   114  		return errors.Trace(err)
   115  	}
   116  	if len(resources) != 1 {
   117  		return errors.New("got bad data from charm store")
   118  	}
   119  	res := resources[0]
   120  
   121  	if len(res) == 0 && c.out.Name() == "tabular" {
   122  		ctx.Infof("No resources to display.")
   123  		return nil
   124  	}
   125  
   126  	// Note that we do not worry about c.CompatVersion
   127  	// for show-charm-resources...
   128  	formatter := newCharmResourcesFormatter(resources[0])
   129  	formatted := formatter.format()
   130  	return c.out.Write(ctx, formatted)
   131  }
   132  
   133  // ListCharmResources implements CharmResourceLister by getting the charmstore client
   134  // from the command's ModelCommandBase.
   135  func (c *ListCharmResourcesCommand) ListResources(ids []charmstore.CharmID) ([][]charmresource.Resource, error) {
   136  	bakeryClient, err := c.BakeryClient()
   137  	if err != nil {
   138  		return nil, errors.Trace(err)
   139  	}
   140  	client, err := charmstore.NewCustomClient(bakeryClient, nil)
   141  	if err != nil {
   142  		return nil, errors.Trace(err)
   143  	}
   144  	return client.ListResources(ids)
   145  }
   146  
   147  func resolveCharms(charms []string) ([]*charm.URL, error) {
   148  	var charmURLs []*charm.URL
   149  	for _, raw := range charms {
   150  		charmURL, err := resolveCharm(raw)
   151  		if err != nil {
   152  			return nil, errors.Trace(err)
   153  		}
   154  		charmURLs = append(charmURLs, charmURL)
   155  	}
   156  	return charmURLs, nil
   157  }
   158  
   159  func resolveCharm(raw string) (*charm.URL, error) {
   160  	charmURL, err := charm.ParseURL(raw)
   161  	if err != nil {
   162  		return charmURL, errors.Trace(err)
   163  	}
   164  
   165  	if charmURL.Series == "bundle" {
   166  		return charmURL, errors.Errorf("charm bundles are not supported")
   167  	}
   168  
   169  	return charmURL, nil
   170  }