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

* cmd/geth, internal/flags, go.mod: colorize cli help, support env vars

* internal/flags: use stdout, not stderr for terminal detection
This commit is contained in:
Péter Szilágyi
2023-09-14 10:33:59 +03:00
committed by GitHub
parent b9b99a12e5
commit d9fbb71d63
5 changed files with 76 additions and 15 deletions
+6 -3
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 != "" {
+65 -8
View File
@@ -18,13 +18,20 @@ package flags
import (
"fmt"
"os"
"regexp"
"strings"
"github.com/ethereum/go-ethereum/internal/version"
"github.com/ethereum/go-ethereum/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(usage string) *cli.App {
git, _ := version.VCS()
@@ -129,6 +136,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
}
@@ -138,30 +153,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)
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)
}
}
func pad(s string, length int) string {
@@ -213,3 +229,44 @@ func wordWrap(s string, width int) string {
return output.String()
}
// AutoEnvVars extens 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)
}
}
}