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  }