github.com/scaleway/scaleway-cli@v1.11.1/pkg/cli/command.go (about) 1 // Copyright (C) 2015 Scaleway. All rights reserved. 2 // Use of this source code is governed by a MIT-style 3 // license that can be found in the LICENSE.md file. 4 5 package cli 6 7 // Command is a Scaleway command 8 import ( 9 "bytes" 10 "errors" 11 "fmt" 12 "os" 13 "strings" 14 "text/template" 15 16 flag "github.com/docker/docker/pkg/mflag" 17 18 "github.com/scaleway/scaleway-cli/pkg/api" 19 "github.com/scaleway/scaleway-cli/pkg/commands" 20 ) 21 22 // errors 23 var ( 24 ErrExitFailure = errors.New("exit 1") 25 ErrExitSuccess = errors.New("exit 0") 26 ) 27 28 // Command contains everything needed by the cli main loop to calls the workflow, display help and usage, and the context 29 type Command struct { 30 // Exec executes the command 31 Exec func(cmd *Command, args []string) error 32 33 // Usage is the one-line usage message. 34 UsageLine string 35 36 // Description is the description of the command 37 Description string 38 39 // Help is the full description of the command 40 Help string 41 42 // Examples are some examples of the command 43 Examples string 44 45 // Flag is a set of flags specific to this command. 46 Flag flag.FlagSet 47 48 // Hidden is a flat to hide command from global help commands listing 49 Hidden bool 50 51 // API is the interface used to communicate with Scaleway's API 52 API *api.ScalewayAPI 53 54 streams *commands.Streams 55 } 56 57 // GetContext returns a standard context, with real stdin, stdout, stderr, a configured API and raw arguments 58 func (c *Command) GetContext(rawArgs []string) commands.CommandContext { 59 ctx := commands.CommandContext{ 60 Env: os.Environ(), 61 RawArgs: rawArgs, 62 API: c.API, 63 } 64 65 if c.streams != nil { 66 ctx.Streams = *c.streams 67 } else { 68 ctx.Streams = commands.Streams{ 69 Stdin: os.Stdin, 70 Stdout: os.Stdout, 71 Stderr: os.Stderr, 72 } 73 } 74 75 return ctx 76 } 77 78 // Streams returns command streams with default os streams if unset 79 func (c *Command) Streams() *commands.Streams { 80 if c.streams != nil { 81 return c.streams 82 } 83 return &commands.Streams{ 84 Stdin: os.Stdin, 85 Stdout: os.Stdout, 86 Stderr: os.Stderr, 87 } 88 89 } 90 91 // Name returns the command's name 92 func (c *Command) Name() string { 93 name := c.UsageLine 94 i := strings.Index(name, " ") 95 if i >= 0 { 96 name = name[:i] 97 } 98 return name 99 } 100 101 // PrintUsage prints a full command usage 102 func (c *Command) PrintUsage() error { 103 helpMessage, err := commandHelpMessage(c) 104 if err != nil { 105 return err 106 } 107 fmt.Fprintf(c.Streams().Stdout, "%s\n", helpMessage) 108 return ErrExitFailure 109 } 110 111 // PrintShortUsage prints a short command usage 112 func (c *Command) PrintShortUsage() error { 113 fmt.Fprintf(c.Streams().Stderr, "usage: scw %s. See 'scw %s --help'.\n", c.UsageLine, c.Name()) 114 return ErrExitFailure 115 } 116 117 // Options returns a string describing options of the command 118 func (c *Command) Options() string { 119 var options string 120 visitor := func(flag *flag.Flag) { 121 name := strings.Join(flag.Names, ", -") 122 var optionUsage string 123 if flag.DefValue == "" { 124 optionUsage = fmt.Sprintf("%s=\"\"", name) 125 } else { 126 optionUsage = fmt.Sprintf("%s=%s", name, flag.DefValue) 127 } 128 options += fmt.Sprintf(" -%-20s %s\n", optionUsage, flag.Usage) 129 } 130 c.Flag.VisitAll(visitor) 131 if len(options) == 0 { 132 return "" 133 } 134 return fmt.Sprintf("Options:\n\n%s", options) 135 } 136 137 // ExamplesHelp returns a string describing examples of the command 138 func (c *Command) ExamplesHelp() string { 139 if c.Examples == "" { 140 return "" 141 } 142 return fmt.Sprintf("Examples:\n\n%s", strings.Trim(c.Examples, "\n")) 143 } 144 145 var fullHelpTemplate = ` 146 Usage: scw {{.UsageLine}} 147 148 {{.Help}} 149 150 {{.Options}} 151 {{.ExamplesHelp}} 152 ` 153 154 func commandHelpMessage(cmd *Command) (string, error) { 155 t := template.New("full") 156 template.Must(t.Parse(fullHelpTemplate)) 157 var output bytes.Buffer 158 err := t.Execute(&output, cmd) 159 if err != nil { 160 return "", err 161 } 162 return strings.Trim(output.String(), "\n"), nil 163 }