cmd: introduce a shim to expose Stdout/Stderr writers

This will allow commands to do the right thing, and write to the proper
output stream.
pull/10338/head
Daniel Nephin 2021-06-02 16:51:34 -04:00
parent e573641995
commit 2fc988d51d
4 changed files with 49 additions and 12 deletions

32
command/cli/cli.go Normal file
View File

@ -0,0 +1,32 @@
package cli
import (
"io"
mcli "github.com/mitchellh/cli"
)
// Ui implements the mitchellh/cli.Ui interface, while exposing the underlying
// io.Writer used for stdout and stderr.
// TODO: rename to UI to match golang style guide
type Ui interface {
mcli.Ui
Stdout() io.Writer
Stderr() io.Writer
}
// BasicUI augments mitchellh/cli.BasicUi by exposing the underlying io.Writer.
type BasicUI struct {
mcli.BasicUi
}
func (b *BasicUI) Stdout() io.Writer {
return b.BasicUi.Writer
}
func (b *BasicUI) Stderr() io.Writer {
return b.BasicUi.ErrorWriter
}
// Command is an alias to reduce the diff. It can be removed at any time.
type Command mcli.Command

View File

@ -41,6 +41,7 @@ import (
catlistdc "github.com/hashicorp/consul/command/catalog/list/dc" catlistdc "github.com/hashicorp/consul/command/catalog/list/dc"
catlistnodes "github.com/hashicorp/consul/command/catalog/list/nodes" catlistnodes "github.com/hashicorp/consul/command/catalog/list/nodes"
catlistsvc "github.com/hashicorp/consul/command/catalog/list/services" catlistsvc "github.com/hashicorp/consul/command/catalog/list/services"
"github.com/hashicorp/consul/command/cli"
"github.com/hashicorp/consul/command/config" "github.com/hashicorp/consul/command/config"
configdelete "github.com/hashicorp/consul/command/config/delete" configdelete "github.com/hashicorp/consul/command/config/delete"
configlist "github.com/hashicorp/consul/command/config/list" configlist "github.com/hashicorp/consul/command/config/list"
@ -108,8 +109,6 @@ import (
"github.com/hashicorp/consul/command/validate" "github.com/hashicorp/consul/command/validate"
"github.com/hashicorp/consul/command/version" "github.com/hashicorp/consul/command/version"
"github.com/hashicorp/consul/command/watch" "github.com/hashicorp/consul/command/watch"
"github.com/mitchellh/cli"
) )
func init() { func init() {

View File

@ -6,7 +6,9 @@ import (
"os/signal" "os/signal"
"syscall" "syscall"
"github.com/mitchellh/cli" mcli "github.com/mitchellh/cli"
"github.com/hashicorp/consul/command/cli"
) )
// Factory is a function that returns a new instance of a CLI-sub command. // Factory is a function that returns a new instance of a CLI-sub command.
@ -24,14 +26,14 @@ func Register(name string, fn Factory) {
registry[name] = fn registry[name] = fn
} }
// Map returns a realized mapping of available CLI commands in a format that // CommandsFromRegistry returns a realized mapping of available CLI commands in a format that
// the CLI class can consume. This should be called after all registration is // the CLI class can consume. This should be called after all registration is
// complete. // complete.
func Map(ui cli.Ui) map[string]cli.CommandFactory { func CommandsFromRegistry(ui cli.Ui) map[string]mcli.CommandFactory {
m := make(map[string]cli.CommandFactory) m := make(map[string]mcli.CommandFactory)
for name, fn := range registry { for name, fn := range registry {
thisFn := fn thisFn := fn
m[name] = func() (cli.Command, error) { m[name] = func() (mcli.Command, error) {
return thisFn(ui) return thisFn(ui)
} }
} }

14
main.go
View File

@ -6,11 +6,13 @@ import (
"log" "log"
"os" "os"
mcli "github.com/mitchellh/cli"
"github.com/hashicorp/consul/command" "github.com/hashicorp/consul/command"
"github.com/hashicorp/consul/command/cli"
"github.com/hashicorp/consul/command/version" "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"
"github.com/mitchellh/cli"
) )
func init() { func init() {
@ -24,19 +26,21 @@ func main() {
func realMain() int { func realMain() int {
log.SetOutput(ioutil.Discard) log.SetOutput(ioutil.Discard)
ui := &cli.BasicUi{Writer: os.Stdout, ErrorWriter: os.Stderr} ui := &cli.BasicUI{
cmds := command.Map(ui) BasicUi: mcli.BasicUi{Writer: os.Stdout, ErrorWriter: os.Stderr},
}
cmds := command.CommandsFromRegistry(ui)
var names []string var names []string
for c := range cmds { for c := range cmds {
names = append(names, c) names = append(names, c)
} }
cli := &cli.CLI{ cli := &mcli.CLI{
Args: os.Args[1:], Args: os.Args[1:],
Commands: cmds, Commands: cmds,
Autocomplete: true, Autocomplete: true,
Name: "consul", Name: "consul",
HelpFunc: cli.FilteredHelpFunc(names, cli.BasicHelpFunc("consul")), HelpFunc: mcli.FilteredHelpFunc(names, mcli.BasicHelpFunc("consul")),
HelpWriter: os.Stdout, HelpWriter: os.Stdout,
ErrorWriter: os.Stderr, ErrorWriter: os.Stderr,
} }