Merge pull request #7519 from hashicorp/dnephin/help-to-stdout

cli: send requested help text to stdout
This commit is contained in:
Daniel Nephin 2020-04-01 11:26:12 -04:00 committed by GitHub
commit 5f44bbcac2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 57 additions and 42 deletions

2
go.mod
View File

@ -58,7 +58,7 @@ require (
github.com/imdario/mergo v0.3.6 github.com/imdario/mergo v0.3.6
github.com/kr/text v0.1.0 github.com/kr/text v0.1.0
github.com/miekg/dns v1.1.26 github.com/miekg/dns v1.1.26
github.com/mitchellh/cli v1.0.0 github.com/mitchellh/cli v1.1.0
github.com/mitchellh/copystructure v1.0.0 github.com/mitchellh/copystructure v1.0.0
github.com/mitchellh/go-testing-interface v1.0.0 github.com/mitchellh/go-testing-interface v1.0.0
github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452 github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452

2
go.sum
View File

@ -259,6 +259,8 @@ github.com/miekg/dns v1.1.26 h1:gPxPSwALAeHJSjarOs00QjVdV9QoBvc1D2ujQUr5BzU=
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/mitchellh/cli v1.0.0 h1:iGBIsUe3+HZ/AD/Vd7DErOt5sU9fa8Uj7A2s1aggv1Y= github.com/mitchellh/cli v1.0.0 h1:iGBIsUe3+HZ/AD/Vd7DErOt5sU9fa8Uj7A2s1aggv1Y=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/cli v1.1.0 h1:tEElEatulEHDeedTxwckzyYMA5c86fbmNIUL1hBIiTg=
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0= github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0=

23
main.go
View File

@ -7,8 +7,10 @@ import (
"os" "os"
"github.com/hashicorp/consul/command" "github.com/hashicorp/consul/command"
"github.com/hashicorp/consul/command/version"
"github.com/hashicorp/consul/lib" "github.com/hashicorp/consul/lib"
_ "github.com/hashicorp/consul/service_os" _ "github.com/hashicorp/consul/service_os"
consulversion "github.com/hashicorp/consul/version"
"github.com/mitchellh/cli" "github.com/mitchellh/cli"
) )
@ -23,18 +25,6 @@ func main() {
func realMain() int { func realMain() int {
log.SetOutput(ioutil.Discard) log.SetOutput(ioutil.Discard)
args := os.Args[1:]
for _, arg := range args {
if arg == "--" {
break
}
if arg == "-v" || arg == "--version" {
args = []string{"version"}
break
}
}
ui := &cli.BasicUi{Writer: os.Stdout, ErrorWriter: os.Stderr} ui := &cli.BasicUi{Writer: os.Stdout, ErrorWriter: os.Stderr}
cmds := command.Map(ui) cmds := command.Map(ui)
var names []string var names []string
@ -43,11 +33,18 @@ func realMain() int {
} }
cli := &cli.CLI{ cli := &cli.CLI{
Args: args, Args: os.Args[1:],
Commands: cmds, Commands: cmds,
Autocomplete: true, Autocomplete: true,
Name: "consul", Name: "consul",
HelpFunc: cli.FilteredHelpFunc(names, cli.BasicHelpFunc("consul")), HelpFunc: cli.FilteredHelpFunc(names, cli.BasicHelpFunc("consul")),
HelpWriter: os.Stdout,
ErrorWriter: os.Stderr,
}
if cli.IsVersion() {
cmd := version.New(ui, consulversion.GetHumanVersion())
return cmd.Run(nil)
} }
exitCode, err := cli.Run() exitCode, err := cli.Run()

View File

@ -2,10 +2,14 @@ sudo: false
language: go language: go
env:
- GO111MODULE=on
go: go:
- "1.8" - "1.11"
- "1.9" - "1.12"
- "1.10" - "1.13"
- "1.14"
branches: branches:
only: only:

View File

@ -12,9 +12,6 @@ testrace:
# updatedeps installs all the dependencies to run and build # updatedeps installs all the dependencies to run and build
updatedeps: updatedeps:
go list ./... \ go mod download
| xargs go list -f '{{ join .Deps "\n" }}{{ printf "\n" }}{{ join .TestImports "\n" }}' \
| grep -v github.com/mitchellh/cli \
| xargs go get -f -u -v
.PHONY: test testrace updatedeps .PHONY: test testrace updatedeps

View File

@ -109,18 +109,23 @@ type CLI struct {
AutocompleteGlobalFlags complete.Flags AutocompleteGlobalFlags complete.Flags
autocompleteInstaller autocompleteInstaller // For tests autocompleteInstaller autocompleteInstaller // For tests
// HelpFunc and HelpWriter are used to output help information, if
// requested.
//
// HelpFunc is the function called to generate the generic help // HelpFunc is the function called to generate the generic help
// text that is shown if help must be shown for the CLI that doesn't // text that is shown if help must be shown for the CLI that doesn't
// pertain to a specific command. // pertain to a specific command.
// HelpFunc HelpFunc
// HelpWriter is the Writer where the help text is outputted to. If
// not specified, it will default to Stderr. // HelpWriter is used to print help text and version when requested.
HelpFunc HelpFunc // Defaults to os.Stderr for backwards compatibility.
// It is recommended that you set HelpWriter to os.Stdout, and
// ErrorWriter to os.Stderr.
HelpWriter io.Writer HelpWriter io.Writer
// ErrorWriter used to output errors when a command can not be run.
// Defaults to the value of HelpWriter for backwards compatibility.
// It is recommended that you set HelpWriter to os.Stdout, and
// ErrorWriter to os.Stderr.
ErrorWriter io.Writer
//--------------------------------------------------------------- //---------------------------------------------------------------
// Internal fields set automatically // Internal fields set automatically
@ -228,7 +233,7 @@ func (c *CLI) Run() (int, error) {
// implementation. If the command is invalid or blank, it is an error. // implementation. If the command is invalid or blank, it is an error.
raw, ok := c.commandTree.Get(c.Subcommand()) raw, ok := c.commandTree.Get(c.Subcommand())
if !ok { if !ok {
c.HelpWriter.Write([]byte(c.HelpFunc(c.helpCommands(c.subcommandParent())) + "\n")) c.ErrorWriter.Write([]byte(c.HelpFunc(c.helpCommands(c.subcommandParent())) + "\n"))
return 127, nil return 127, nil
} }
@ -239,23 +244,23 @@ func (c *CLI) Run() (int, error) {
// If we've been instructed to just print the help, then print it // If we've been instructed to just print the help, then print it
if c.IsHelp() { if c.IsHelp() {
c.commandHelp(command) c.commandHelp(c.HelpWriter, command)
return 0, nil return 0, nil
} }
// If there is an invalid flag, then error // If there is an invalid flag, then error
if len(c.topFlags) > 0 { if len(c.topFlags) > 0 {
c.HelpWriter.Write([]byte( c.ErrorWriter.Write([]byte(
"Invalid flags before the subcommand. If these flags are for\n" + "Invalid flags before the subcommand. If these flags are for\n" +
"the subcommand, please put them after the subcommand.\n\n")) "the subcommand, please put them after the subcommand.\n\n"))
c.commandHelp(command) c.commandHelp(c.ErrorWriter, command)
return 1, nil return 1, nil
} }
code := command.Run(c.SubcommandArgs()) code := command.Run(c.SubcommandArgs())
if code == RunResultHelp { if code == RunResultHelp {
// Requesting help // Requesting help
c.commandHelp(command) c.commandHelp(c.ErrorWriter, command)
return 1, nil return 1, nil
} }
@ -310,6 +315,9 @@ func (c *CLI) init() {
if c.HelpWriter == nil { if c.HelpWriter == nil {
c.HelpWriter = os.Stderr c.HelpWriter = os.Stderr
} }
if c.ErrorWriter == nil {
c.ErrorWriter = c.HelpWriter
}
// Build our hidden commands // Build our hidden commands
if len(c.HiddenCommands) > 0 { if len(c.HiddenCommands) > 0 {
@ -404,8 +412,8 @@ func (c *CLI) initAutocomplete() {
cmd.Flags = map[string]complete.Predictor{ cmd.Flags = map[string]complete.Predictor{
"-" + c.AutocompleteInstall: complete.PredictNothing, "-" + c.AutocompleteInstall: complete.PredictNothing,
"-" + c.AutocompleteUninstall: complete.PredictNothing, "-" + c.AutocompleteUninstall: complete.PredictNothing,
"-help": complete.PredictNothing, "-help": complete.PredictNothing,
"-version": complete.PredictNothing, "-version": complete.PredictNothing,
} }
} }
cmd.GlobalFlags = c.AutocompleteGlobalFlags cmd.GlobalFlags = c.AutocompleteGlobalFlags
@ -483,7 +491,7 @@ func (c *CLI) initAutocompleteSub(prefix string) complete.Command {
return cmd return cmd
} }
func (c *CLI) commandHelp(command Command) { func (c *CLI) commandHelp(out io.Writer, command Command) {
// Get the template to use // Get the template to use
tpl := strings.TrimSpace(defaultHelpTemplate) tpl := strings.TrimSpace(defaultHelpTemplate)
if t, ok := command.(CommandHelpTemplate); ok { if t, ok := command.(CommandHelpTemplate); ok {
@ -533,12 +541,12 @@ func (c *CLI) commandHelp(command Command) {
// Get the command // Get the command
raw, ok := subcommands[k] raw, ok := subcommands[k]
if !ok { if !ok {
c.HelpWriter.Write([]byte(fmt.Sprintf( c.ErrorWriter.Write([]byte(fmt.Sprintf(
"Error getting subcommand %q", k))) "Error getting subcommand %q", k)))
} }
sub, err := raw() sub, err := raw()
if err != nil { if err != nil {
c.HelpWriter.Write([]byte(fmt.Sprintf( c.ErrorWriter.Write([]byte(fmt.Sprintf(
"Error instantiating %q: %s", k, err))) "Error instantiating %q: %s", k, err)))
} }
@ -559,13 +567,13 @@ func (c *CLI) commandHelp(command Command) {
data["Subcommands"] = subcommandsTpl data["Subcommands"] = subcommandsTpl
// Write // Write
err = t.Execute(c.HelpWriter, data) err = t.Execute(out, data)
if err == nil { if err == nil {
return return
} }
// An error, just output... // An error, just output...
c.HelpWriter.Write([]byte(fmt.Sprintf( c.ErrorWriter.Write([]byte(fmt.Sprintf(
"Internal error rendering help: %s", err))) "Internal error rendering help: %s", err)))
} }

View File

@ -1,5 +1,7 @@
module github.com/mitchellh/cli module github.com/mitchellh/cli
go 1.11
require ( require (
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310
github.com/bgentry/speakeasy v0.1.0 github.com/bgentry/speakeasy v0.1.0

View File

@ -1,9 +1,11 @@
package cli package cli
import ( import (
"bufio"
"bytes" "bytes"
"fmt" "fmt"
"io" "io"
"strings"
"sync" "sync"
) )
@ -35,9 +37,12 @@ func (u *MockUi) Ask(query string) (string, error) {
var result string var result string
fmt.Fprint(u.OutputWriter, query) fmt.Fprint(u.OutputWriter, query)
if _, err := fmt.Fscanln(u.InputReader, &result); err != nil { r := bufio.NewReader(u.InputReader)
line, err := r.ReadString('\n')
if err != nil {
return "", err return "", err
} }
result = strings.TrimRight(line, "\r\n")
return result, nil return result, nil
} }

2
vendor/modules.txt vendored
View File

@ -291,7 +291,7 @@ github.com/mattn/go-isatty
github.com/matttproud/golang_protobuf_extensions/pbutil github.com/matttproud/golang_protobuf_extensions/pbutil
# github.com/miekg/dns v1.1.26 # github.com/miekg/dns v1.1.26
github.com/miekg/dns github.com/miekg/dns
# github.com/mitchellh/cli v1.0.0 # github.com/mitchellh/cli v1.1.0
github.com/mitchellh/cli github.com/mitchellh/cli
# github.com/mitchellh/copystructure v1.0.0 # github.com/mitchellh/copystructure v1.0.0
github.com/mitchellh/copystructure github.com/mitchellh/copystructure