Merge pull request #912 from rliebz/clean-help-printer
Simplify HelpPrinter and CustomHelpPrinter behaviors
This commit is contained in:
commit
49ad3dffd0
51
help.go
51
help.go
@ -47,13 +47,18 @@ type helpPrinter func(w io.Writer, templ string, data interface{})
|
||||
// Prints help for the App or Command with custom template function.
|
||||
type helpPrinterCustom func(w io.Writer, templ string, data interface{}, customFunc map[string]interface{})
|
||||
|
||||
// HelpPrinter is a function that writes the help output. If not set a default
|
||||
// is used. The function signature is:
|
||||
// func(w io.Writer, templ string, data interface{})
|
||||
// HelpPrinter is a function that writes the help output. If not set explicitly,
|
||||
// this calls HelpPrinterCustom using only the default template functions.
|
||||
//
|
||||
// If custom logic for printing help is required, this function can be
|
||||
// overridden. If the ExtraInfo field is defined on an App, this function
|
||||
// should not be modified, as HelpPrinterCustom will be used directly in order
|
||||
// to capture the extra information.
|
||||
var HelpPrinter helpPrinter = printHelp
|
||||
|
||||
// HelpPrinterCustom is same as HelpPrinter but
|
||||
// takes a custom function for template function map.
|
||||
// HelpPrinterCustom is a function that writes the help output. It is used as
|
||||
// the default implementation of HelpPrinter, and may be called directly if
|
||||
// the ExtraInfo field is set on an App.
|
||||
var HelpPrinterCustom helpPrinterCustom = printHelpCustom
|
||||
|
||||
// VersionPrinter prints the version for the App
|
||||
@ -66,20 +71,24 @@ func ShowAppHelpAndExit(c *Context, exitCode int) {
|
||||
}
|
||||
|
||||
// ShowAppHelp is an action that displays the help.
|
||||
func ShowAppHelp(c *Context) (err error) {
|
||||
if c.App.CustomAppHelpTemplate == "" {
|
||||
HelpPrinter(c.App.Writer, AppHelpTemplate, c.App)
|
||||
return
|
||||
func ShowAppHelp(c *Context) error {
|
||||
template := c.App.CustomAppHelpTemplate
|
||||
if template == "" {
|
||||
template = AppHelpTemplate
|
||||
}
|
||||
customAppData := func() map[string]interface{} {
|
||||
|
||||
if c.App.ExtraInfo == nil {
|
||||
HelpPrinter(c.App.Writer, template, c.App)
|
||||
return nil
|
||||
}
|
||||
|
||||
customAppData := func() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"ExtraInfo": c.App.ExtraInfo,
|
||||
}
|
||||
}
|
||||
HelpPrinterCustom(c.App.Writer, c.App.CustomAppHelpTemplate, c.App, customAppData())
|
||||
HelpPrinterCustom(c.App.Writer, template, c.App, customAppData())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -186,11 +195,13 @@ func ShowCommandHelp(ctx *Context, command string) error {
|
||||
|
||||
for _, c := range ctx.App.Commands {
|
||||
if c.HasName(command) {
|
||||
if c.CustomHelpTemplate != "" {
|
||||
HelpPrinterCustom(ctx.App.Writer, c.CustomHelpTemplate, c, nil)
|
||||
} else {
|
||||
HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c)
|
||||
templ := c.CustomHelpTemplate
|
||||
if templ == "" {
|
||||
templ = CommandHelpTemplate
|
||||
}
|
||||
|
||||
HelpPrinter(ctx.App.Writer, templ, c)
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@ -238,11 +249,15 @@ func ShowCommandCompletions(ctx *Context, command string) {
|
||||
|
||||
}
|
||||
|
||||
func printHelpCustom(out io.Writer, templ string, data interface{}, customFunc map[string]interface{}) {
|
||||
// printHelpCustom is the default implementation of HelpPrinterCustom.
|
||||
//
|
||||
// The customFuncs map will be combined with a default template.FuncMap to
|
||||
// allow using arbitrary functions in template rendering.
|
||||
func printHelpCustom(out io.Writer, templ string, data interface{}, customFuncs map[string]interface{}) {
|
||||
funcMap := template.FuncMap{
|
||||
"join": strings.Join,
|
||||
}
|
||||
for key, value := range customFunc {
|
||||
for key, value := range customFuncs {
|
||||
funcMap[key] = value
|
||||
}
|
||||
|
||||
@ -261,7 +276,7 @@ func printHelpCustom(out io.Writer, templ string, data interface{}, customFunc m
|
||||
}
|
||||
|
||||
func printHelp(out io.Writer, templ string, data interface{}) {
|
||||
printHelpCustom(out, templ, data, nil)
|
||||
HelpPrinterCustom(out, templ, data, nil)
|
||||
}
|
||||
|
||||
func checkVersion(c *Context) bool {
|
||||
|
313
help_test.go
313
help_test.go
@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
@ -210,6 +211,180 @@ func TestShowAppHelp_CommandAliases(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestShowCommandHelp_HelpPrinter(t *testing.T) {
|
||||
doublecho := func(text string) string {
|
||||
return text + " " + text
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
template string
|
||||
printer helpPrinter
|
||||
command string
|
||||
wantTemplate string
|
||||
wantOutput string
|
||||
}{
|
||||
{
|
||||
name: "no-command",
|
||||
template: "",
|
||||
printer: func(w io.Writer, templ string, data interface{}) {
|
||||
fmt.Fprint(w, "yo")
|
||||
},
|
||||
command: "",
|
||||
wantTemplate: SubcommandHelpTemplate,
|
||||
wantOutput: "yo",
|
||||
},
|
||||
{
|
||||
name: "standard-command",
|
||||
template: "",
|
||||
printer: func(w io.Writer, templ string, data interface{}) {
|
||||
fmt.Fprint(w, "yo")
|
||||
},
|
||||
command: "my-command",
|
||||
wantTemplate: CommandHelpTemplate,
|
||||
wantOutput: "yo",
|
||||
},
|
||||
{
|
||||
name: "custom-template-command",
|
||||
template: "{{doublecho .Name}}",
|
||||
printer: func(w io.Writer, templ string, data interface{}) {
|
||||
// Pass a custom function to ensure it gets used
|
||||
fm := map[string]interface{}{"doublecho": doublecho}
|
||||
HelpPrinterCustom(w, templ, data, fm)
|
||||
},
|
||||
command: "my-command",
|
||||
wantTemplate: "{{doublecho .Name}}",
|
||||
wantOutput: "my-command my-command",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
defer func(old helpPrinter) {
|
||||
HelpPrinter = old
|
||||
}(HelpPrinter)
|
||||
HelpPrinter = func(w io.Writer, templ string, data interface{}) {
|
||||
if templ != tt.wantTemplate {
|
||||
t.Errorf("want template:\n%s\ngot template:\n%s", tt.wantTemplate, templ)
|
||||
}
|
||||
|
||||
tt.printer(w, templ, data)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
app := &App{
|
||||
Name: "my-app",
|
||||
Writer: &buf,
|
||||
Commands: []Command{
|
||||
{
|
||||
Name: "my-command",
|
||||
CustomHelpTemplate: tt.template,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := app.Run([]string{"my-app", "help", tt.command})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
got := buf.String()
|
||||
if got != tt.wantOutput {
|
||||
t.Errorf("want output %q, got %q", tt.wantOutput, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestShowCommandHelp_HelpPrinterCustom(t *testing.T) {
|
||||
doublecho := func(text string) string {
|
||||
return text + " " + text
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
template string
|
||||
printer helpPrinterCustom
|
||||
command string
|
||||
wantTemplate string
|
||||
wantOutput string
|
||||
}{
|
||||
{
|
||||
name: "no-command",
|
||||
template: "",
|
||||
printer: func(w io.Writer, templ string, data interface{}, fm map[string]interface{}) {
|
||||
fmt.Fprint(w, "yo")
|
||||
},
|
||||
command: "",
|
||||
wantTemplate: SubcommandHelpTemplate,
|
||||
wantOutput: "yo",
|
||||
},
|
||||
{
|
||||
name: "standard-command",
|
||||
template: "",
|
||||
printer: func(w io.Writer, templ string, data interface{}, fm map[string]interface{}) {
|
||||
fmt.Fprint(w, "yo")
|
||||
},
|
||||
command: "my-command",
|
||||
wantTemplate: CommandHelpTemplate,
|
||||
wantOutput: "yo",
|
||||
},
|
||||
{
|
||||
name: "custom-template-command",
|
||||
template: "{{doublecho .Name}}",
|
||||
printer: func(w io.Writer, templ string, data interface{}, _ map[string]interface{}) {
|
||||
// Pass a custom function to ensure it gets used
|
||||
fm := map[string]interface{}{"doublecho": doublecho}
|
||||
printHelpCustom(w, templ, data, fm)
|
||||
},
|
||||
command: "my-command",
|
||||
wantTemplate: "{{doublecho .Name}}",
|
||||
wantOutput: "my-command my-command",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
defer func(old helpPrinterCustom) {
|
||||
HelpPrinterCustom = old
|
||||
}(HelpPrinterCustom)
|
||||
HelpPrinterCustom = func(w io.Writer, templ string, data interface{}, fm map[string]interface{}) {
|
||||
if fm != nil {
|
||||
t.Error("unexpected function map passed")
|
||||
}
|
||||
|
||||
if templ != tt.wantTemplate {
|
||||
t.Errorf("want template:\n%s\ngot template:\n%s", tt.wantTemplate, templ)
|
||||
}
|
||||
|
||||
tt.printer(w, templ, data, fm)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
app := &App{
|
||||
Name: "my-app",
|
||||
Writer: &buf,
|
||||
Commands: []Command{
|
||||
{
|
||||
Name: "my-command",
|
||||
CustomHelpTemplate: tt.template,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := app.Run([]string{"my-app", "help", tt.command})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
got := buf.String()
|
||||
if got != tt.wantOutput {
|
||||
t.Errorf("want output %q, got %q", tt.wantOutput, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestShowCommandHelp_CommandAliases(t *testing.T) {
|
||||
app := &App{
|
||||
Commands: []Command{
|
||||
@ -376,6 +551,144 @@ func TestShowAppHelp_HiddenCommand(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestShowAppHelp_HelpPrinter(t *testing.T) {
|
||||
doublecho := func(text string) string {
|
||||
return text + " " + text
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
template string
|
||||
printer helpPrinter
|
||||
wantTemplate string
|
||||
wantOutput string
|
||||
}{
|
||||
{
|
||||
name: "standard-command",
|
||||
template: "",
|
||||
printer: func(w io.Writer, templ string, data interface{}) {
|
||||
fmt.Fprint(w, "yo")
|
||||
},
|
||||
wantTemplate: AppHelpTemplate,
|
||||
wantOutput: "yo",
|
||||
},
|
||||
{
|
||||
name: "custom-template-command",
|
||||
template: "{{doublecho .Name}}",
|
||||
printer: func(w io.Writer, templ string, data interface{}) {
|
||||
// Pass a custom function to ensure it gets used
|
||||
fm := map[string]interface{}{"doublecho": doublecho}
|
||||
printHelpCustom(w, templ, data, fm)
|
||||
},
|
||||
wantTemplate: "{{doublecho .Name}}",
|
||||
wantOutput: "my-app my-app",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
defer func(old helpPrinter) {
|
||||
HelpPrinter = old
|
||||
}(HelpPrinter)
|
||||
HelpPrinter = func(w io.Writer, templ string, data interface{}) {
|
||||
if templ != tt.wantTemplate {
|
||||
t.Errorf("want template:\n%s\ngot template:\n%s", tt.wantTemplate, templ)
|
||||
}
|
||||
|
||||
tt.printer(w, templ, data)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
app := &App{
|
||||
Name: "my-app",
|
||||
Writer: &buf,
|
||||
CustomAppHelpTemplate: tt.template,
|
||||
}
|
||||
|
||||
err := app.Run([]string{"my-app", "help"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
got := buf.String()
|
||||
if got != tt.wantOutput {
|
||||
t.Errorf("want output %q, got %q", tt.wantOutput, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestShowAppHelp_HelpPrinterCustom(t *testing.T) {
|
||||
doublecho := func(text string) string {
|
||||
return text + " " + text
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
template string
|
||||
printer helpPrinterCustom
|
||||
wantTemplate string
|
||||
wantOutput string
|
||||
}{
|
||||
{
|
||||
name: "standard-command",
|
||||
template: "",
|
||||
printer: func(w io.Writer, templ string, data interface{}, fm map[string]interface{}) {
|
||||
fmt.Fprint(w, "yo")
|
||||
},
|
||||
wantTemplate: AppHelpTemplate,
|
||||
wantOutput: "yo",
|
||||
},
|
||||
{
|
||||
name: "custom-template-command",
|
||||
template: "{{doublecho .Name}}",
|
||||
printer: func(w io.Writer, templ string, data interface{}, _ map[string]interface{}) {
|
||||
// Pass a custom function to ensure it gets used
|
||||
fm := map[string]interface{}{"doublecho": doublecho}
|
||||
printHelpCustom(w, templ, data, fm)
|
||||
},
|
||||
wantTemplate: "{{doublecho .Name}}",
|
||||
wantOutput: "my-app my-app",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
defer func(old helpPrinterCustom) {
|
||||
HelpPrinterCustom = old
|
||||
}(HelpPrinterCustom)
|
||||
HelpPrinterCustom = func(w io.Writer, templ string, data interface{}, fm map[string]interface{}) {
|
||||
if fm != nil {
|
||||
t.Error("unexpected function map passed")
|
||||
}
|
||||
|
||||
if templ != tt.wantTemplate {
|
||||
t.Errorf("want template:\n%s\ngot template:\n%s", tt.wantTemplate, templ)
|
||||
}
|
||||
|
||||
tt.printer(w, templ, data, fm)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
app := &App{
|
||||
Name: "my-app",
|
||||
Writer: &buf,
|
||||
CustomAppHelpTemplate: tt.template,
|
||||
}
|
||||
|
||||
err := app.Run([]string{"my-app", "help"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
got := buf.String()
|
||||
if got != tt.wantOutput {
|
||||
t.Errorf("want output %q, got %q", tt.wantOutput, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestShowAppHelp_CustomAppTemplate(t *testing.T) {
|
||||
app := &App{
|
||||
Commands: []Command{
|
||||
|
Loading…
Reference in New Issue
Block a user