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 }