cmd/geth, internal/flags, go.mod: colorize cli help, support env vars (#28103)

This commit is contained in:
Daniel Liu 2024-11-25 16:39:29 +08:00
parent bda88affe6
commit 197551c729
3 changed files with 71 additions and 17 deletions

View file

@ -193,6 +193,7 @@ func init() {
app.Flags = append(app.Flags, rpcFlags...)
app.Flags = append(app.Flags, consoleFlags...)
app.Flags = append(app.Flags, debug.Flags...)
flags.AutoEnvVars(app.Flags, "XDC")
app.Before = func(ctx *cli.Context) error {
runtime.GOMAXPROCS(runtime.NumCPU())

View file

@ -68,6 +68,7 @@ type DirectoryFlag struct {
Value DirectoryString
Aliases []string
EnvVars []string
}
// For cli.Flag:
@ -102,7 +103,7 @@ func (f *DirectoryFlag) GetCategory() string { return f.Category }
func (f *DirectoryFlag) TakesValue() bool { return true }
func (f *DirectoryFlag) GetUsage() string { return f.Usage }
func (f *DirectoryFlag) GetValue() string { return f.Value.String() }
func (f *DirectoryFlag) GetEnvVars() []string { return nil } // env not supported
func (f *DirectoryFlag) GetEnvVars() []string { return f.EnvVars }
func (f *DirectoryFlag) GetDefaultText() string {
if f.DefaultText != "" {
@ -156,6 +157,7 @@ type TextMarshalerFlag struct {
Value TextMarshaler
Aliases []string
EnvVars []string
}
// For cli.Flag:
@ -187,7 +189,7 @@ func (f *TextMarshalerFlag) GetCategory() string { return f.Category }
func (f *TextMarshalerFlag) TakesValue() bool { return true }
func (f *TextMarshalerFlag) GetUsage() string { return f.Usage }
func (f *TextMarshalerFlag) GetEnvVars() []string { return nil } // env not supported
func (f *TextMarshalerFlag) GetEnvVars() []string { return f.EnvVars }
func (f *TextMarshalerFlag) GetValue() string {
t, err := f.Value.MarshalText()
@ -237,6 +239,7 @@ type BigFlag struct {
Value *big.Int
Aliases []string
EnvVars []string
}
// For cli.Flag:
@ -271,7 +274,7 @@ func (f *BigFlag) GetCategory() string { return f.Category }
func (f *BigFlag) TakesValue() bool { return true }
func (f *BigFlag) GetUsage() string { return f.Usage }
func (f *BigFlag) GetValue() string { return f.Value.String() }
func (f *BigFlag) GetEnvVars() []string { return nil } // env not supported
func (f *BigFlag) GetEnvVars() []string { return f.EnvVars }
func (f *BigFlag) GetDefaultText() string {
if f.DefaultText != "" {

View file

@ -18,12 +18,19 @@ package flags
import (
"fmt"
"os"
"regexp"
"strings"
"github.com/XinFinOrg/XDPoSChain/params"
"github.com/mattn/go-isatty"
"github.com/urfave/cli/v2"
)
// usecolor defines whether the CLI help should use colored output or normal dumb
// colorless terminal formatting.
var usecolor = (isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd())) && os.Getenv("TERM") != "dumb"
// NewApp creates an app with sane defaults.
func NewApp(gitCommit, usage string) *cli.App {
app := cli.NewApp()
@ -118,6 +125,14 @@ func doMigrateFlags(ctx *cli.Context) {
}
func init() {
if usecolor {
// Annotate all help categories with colors
cli.AppHelpTemplate = regexp.MustCompile("[A-Z ]+:").ReplaceAllString(cli.AppHelpTemplate, "\u001B[33m$0\u001B[0m")
// Annotate flag categories with colors (private template, so need to
// copy-paste the entire thing here...)
cli.AppHelpTemplate = strings.ReplaceAll(cli.AppHelpTemplate, "{{template \"visibleFlagCategoryTemplate\" .}}", "{{range .VisibleFlagCategories}}\n {{if .Name}}\u001B[33m{{.Name}}\u001B[0m\n\n {{end}}{{$flglen := len .Flags}}{{range $i, $e := .Flags}}{{if eq (subtract $flglen $i) 1}}{{$e}}\n{{else}}{{$e}}\n {{end}}{{end}}{{end}}")
}
cli.FlagStringer = FlagString
}
@ -127,37 +142,31 @@ func FlagString(f cli.Flag) string {
if !ok {
return ""
}
needsPlaceholder := df.TakesValue()
placeholder := ""
if needsPlaceholder {
placeholder = "value"
}
namesText := pad(cli.FlagNamePrefixer(df.Names(), placeholder), 30)
namesText := cli.FlagNamePrefixer(df.Names(), placeholder)
defaultValueString := ""
if s := df.GetDefaultText(); s != "" {
defaultValueString = " (default: " + s + ")"
}
usage := strings.TrimSpace(df.GetUsage())
envHint := strings.TrimSpace(cli.FlagEnvHinter(df.GetEnvVars(), ""))
if len(envHint) > 0 {
usage += " " + envHint
if envHint != "" {
envHint = " (" + envHint[1:len(envHint)-1] + ")"
}
usage := strings.TrimSpace(df.GetUsage())
usage = wordWrap(usage, 80)
usage = indent(usage, 10)
return fmt.Sprintf("\n %s%s\n%s", namesText, defaultValueString, usage)
}
func pad(s string, length int) string {
if len(s) < length {
s += strings.Repeat(" ", length-len(s))
if usecolor {
return fmt.Sprintf("\n \u001B[32m%-35s%-35s\u001B[0m%s\n%s", namesText, defaultValueString, envHint, usage)
} else {
return fmt.Sprintf("\n %-35s%-35s%s\n%s", namesText, defaultValueString, envHint, usage)
}
return s
}
func indent(s string, nspace int) string {
@ -202,3 +211,44 @@ func wordWrap(s string, width int) string {
return output.String()
}
// AutoEnvVars extends all the specific CLI flags with automatically generated
// env vars by capitalizing the flag, replacing . with _ and prefixing it with
// the specified string.
//
// Note, the prefix should *not* contain the separator underscore, that will be
// added automatically.
func AutoEnvVars(flags []cli.Flag, prefix string) {
for _, flag := range flags {
envvar := strings.ToUpper(prefix + "_" + strings.ReplaceAll(strings.ReplaceAll(flag.Names()[0], ".", "_"), "-", "_"))
switch flag := flag.(type) {
case *cli.StringFlag:
flag.EnvVars = append(flag.EnvVars, envvar)
case *cli.BoolFlag:
flag.EnvVars = append(flag.EnvVars, envvar)
case *cli.IntFlag:
flag.EnvVars = append(flag.EnvVars, envvar)
case *cli.Uint64Flag:
flag.EnvVars = append(flag.EnvVars, envvar)
case *cli.DurationFlag:
flag.EnvVars = append(flag.EnvVars, envvar)
case *cli.PathFlag:
flag.EnvVars = append(flag.EnvVars, envvar)
case *BigFlag:
flag.EnvVars = append(flag.EnvVars, envvar)
case *TextMarshalerFlag:
flag.EnvVars = append(flag.EnvVars, envvar)
case *DirectoryFlag:
flag.EnvVars = append(flag.EnvVars, envvar)
}
}
}