github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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 "gopkg.in/juju/charm.v6-unstable" 10 charmresource "gopkg.in/juju/charm.v6-unstable/resource" 11 csparams "gopkg.in/juju/charmrepo.v2-unstable/csclient/params" 12 "launchpad.net/gnuflag" 13 14 "github.com/juju/juju/charmstore" 15 "github.com/juju/juju/cmd/modelcmd" 16 ) 17 18 // CharmCommandBase exposes the functionality of charmcmd.CommandBase 19 // needed here. 20 type CharmCommandBase interface { 21 // Connect connects to the charm store and returns a client. 22 // cmd.Context needs to be passed in so that we can do authentication 23 // via the cli if available. 24 Connect(*cmd.Context) (CharmResourceLister, error) 25 } 26 27 // CharmResourceLister has the charm store API methods needed by ListCharmResourcesCommand. 28 type CharmResourceLister interface { 29 // ListResources lists the resources for each of the identified charms. 30 ListResources([]charmstore.CharmID) ([][]charmresource.Resource, error) 31 32 // Close closes the client. 33 Close() error 34 } 35 36 // ListCharmResourcesCommand implements the "juju charm list-resources" command. 37 type ListCharmResourcesCommand struct { 38 modelcmd.ModelCommandBase 39 CharmCommandBase 40 out cmd.Output 41 channel string 42 charm string 43 } 44 45 // NewListCharmResourcesCommand returns a new command that lists resources defined 46 // by a charm. 47 func NewListCharmResourcesCommand(base CharmCommandBase) *ListCharmResourcesCommand { 48 cmd := &ListCharmResourcesCommand{ 49 CharmCommandBase: base, 50 } 51 return cmd 52 } 53 54 var listCharmResourcesDoc = ` 55 This command will report the resources for a charm in the charm store. 56 57 <charm> can be a charm URL, or an unambiguously condensed form of it, 58 just like the deploy command. So the following forms will be accepted: 59 60 For cs:trusty/mysql 61 mysql 62 trusty/mysql 63 64 For cs:~user/trusty/mysql 65 cs:~user/mysql 66 67 Where the series is not supplied, the series from your local host is used. 68 Thus the above examples imply that the local series is trusty. 69 ` 70 71 // Info implements cmd.Command. 72 func (c *ListCharmResourcesCommand) Info() *cmd.Info { 73 return &cmd.Info{ 74 Name: "list-resources", 75 Args: "<charm>", 76 Purpose: "display the resources for a charm in the charm store", 77 Doc: listCharmResourcesDoc, 78 Aliases: []string{"resources"}, 79 } 80 } 81 82 // SetFlags implements cmd.Command. 83 func (c *ListCharmResourcesCommand) SetFlags(f *gnuflag.FlagSet) { 84 defaultFormat := "tabular" 85 c.out.AddFlags(f, defaultFormat, map[string]cmd.Formatter{ 86 "tabular": FormatCharmTabular, 87 "yaml": cmd.FormatYaml, 88 "json": cmd.FormatJson, 89 }) 90 f.StringVar(&c.channel, "channel", "stable", "the charmstore channel of the charm") 91 } 92 93 // Init implements cmd.Command. 94 func (c *ListCharmResourcesCommand) Init(args []string) error { 95 if len(args) == 0 { 96 return errors.New("missing charm") 97 } 98 c.charm = args[0] 99 100 if err := cmd.CheckEmpty(args[1:]); err != nil { 101 return errors.Trace(err) 102 } 103 104 return nil 105 } 106 107 // Run implements cmd.Command. 108 func (c *ListCharmResourcesCommand) Run(ctx *cmd.Context) error { 109 // TODO(ericsnow) Adjust this to the charm store. 110 111 apiclient, err := c.Connect(ctx) 112 if err != nil { 113 // TODO(ericsnow) Return a more user-friendly error? 114 return errors.Trace(err) 115 } 116 defer apiclient.Close() 117 118 charmURLs, err := resolveCharms([]string{c.charm}) 119 if err != nil { 120 return errors.Trace(err) 121 } 122 123 charms := make([]charmstore.CharmID, len(charmURLs)) 124 for i, id := range charmURLs { 125 charms[i] = charmstore.CharmID{URL: id, Channel: csparams.Channel(c.channel)} 126 } 127 128 resources, err := apiclient.ListResources(charms) 129 if err != nil { 130 return errors.Trace(err) 131 } 132 if len(resources) != 1 { 133 return errors.New("got bad data from charm store") 134 } 135 136 // Note that we do not worry about c.CompatVersion 137 // for show-charm-resources... 138 formatter := newCharmResourcesFormatter(resources[0]) 139 formatted := formatter.format() 140 return c.out.Write(ctx, formatted) 141 } 142 143 func resolveCharms(charms []string) ([]*charm.URL, error) { 144 var charmURLs []*charm.URL 145 for _, raw := range charms { 146 charmURL, err := resolveCharm(raw) 147 if err != nil { 148 return nil, errors.Trace(err) 149 } 150 charmURLs = append(charmURLs, charmURL) 151 } 152 return charmURLs, nil 153 } 154 155 func resolveCharm(raw string) (*charm.URL, error) { 156 charmURL, err := charm.ParseURL(raw) 157 if err != nil { 158 return charmURL, errors.Trace(err) 159 } 160 161 if charmURL.Series == "bundle" { 162 return charmURL, errors.Errorf("charm bundles are not supported") 163 } 164 165 return charmURL, nil 166 }