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:
parent
b9b99a12e5
commit
d9fbb71d63
@ -244,6 +244,7 @@ func init() {
|
|||||||
debug.Flags,
|
debug.Flags,
|
||||||
metricsFlags,
|
metricsFlags,
|
||||||
)
|
)
|
||||||
|
flags.AutoEnvVars(app.Flags, "GETH")
|
||||||
|
|
||||||
app.Before = func(ctx *cli.Context) error {
|
app.Before = func(ctx *cli.Context) error {
|
||||||
maxprocs.Set() // Automatically set GOMAXPROCS to match Linux container CPU quota.
|
maxprocs.Set() // Automatically set GOMAXPROCS to match Linux container CPU quota.
|
||||||
|
2
go.mod
2
go.mod
@ -61,7 +61,7 @@ require (
|
|||||||
github.com/supranational/blst v0.3.11
|
github.com/supranational/blst v0.3.11
|
||||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
|
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
|
||||||
github.com/tyler-smith/go-bip39 v1.1.0
|
github.com/tyler-smith/go-bip39 v1.1.0
|
||||||
github.com/urfave/cli/v2 v2.24.1
|
github.com/urfave/cli/v2 v2.25.7
|
||||||
go.uber.org/automaxprocs v1.5.2
|
go.uber.org/automaxprocs v1.5.2
|
||||||
golang.org/x/crypto v0.12.0
|
golang.org/x/crypto v0.12.0
|
||||||
golang.org/x/exp v0.0.0-20230810033253-352e893a4cad
|
golang.org/x/exp v0.0.0-20230810033253-352e893a4cad
|
||||||
|
6
go.sum
6
go.sum
@ -39,7 +39,7 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSu
|
|||||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 h1:Px2UA+2RvSSvv+RvJNuUB6n7rs5Wsel4dXLe90Um2n4=
|
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 h1:Px2UA+2RvSSvv+RvJNuUB6n7rs5Wsel4dXLe90Um2n4=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo=
|
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
|
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw=
|
github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw=
|
||||||
github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w=
|
github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w=
|
||||||
@ -551,8 +551,8 @@ github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3C
|
|||||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||||
github.com/urfave/cli/v2 v2.24.1 h1:/QYYr7g0EhwXEML8jO+8OYt5trPnLHS0p3mrgExJ5NU=
|
github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs=
|
||||||
github.com/urfave/cli/v2 v2.24.1/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
|
github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
||||||
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
|
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
|
github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
|
||||||
|
@ -68,6 +68,7 @@ type DirectoryFlag struct {
|
|||||||
Value DirectoryString
|
Value DirectoryString
|
||||||
|
|
||||||
Aliases []string
|
Aliases []string
|
||||||
|
EnvVars []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// For cli.Flag:
|
// 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) TakesValue() bool { return true }
|
||||||
func (f *DirectoryFlag) GetUsage() string { return f.Usage }
|
func (f *DirectoryFlag) GetUsage() string { return f.Usage }
|
||||||
func (f *DirectoryFlag) GetValue() string { return f.Value.String() }
|
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 {
|
func (f *DirectoryFlag) GetDefaultText() string {
|
||||||
if f.DefaultText != "" {
|
if f.DefaultText != "" {
|
||||||
@ -156,6 +157,7 @@ type TextMarshalerFlag struct {
|
|||||||
Value TextMarshaler
|
Value TextMarshaler
|
||||||
|
|
||||||
Aliases []string
|
Aliases []string
|
||||||
|
EnvVars []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// For cli.Flag:
|
// 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) TakesValue() bool { return true }
|
||||||
func (f *TextMarshalerFlag) GetUsage() string { return f.Usage }
|
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 {
|
func (f *TextMarshalerFlag) GetValue() string {
|
||||||
t, err := f.Value.MarshalText()
|
t, err := f.Value.MarshalText()
|
||||||
@ -237,6 +239,7 @@ type BigFlag struct {
|
|||||||
Value *big.Int
|
Value *big.Int
|
||||||
|
|
||||||
Aliases []string
|
Aliases []string
|
||||||
|
EnvVars []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// For cli.Flag:
|
// 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) TakesValue() bool { return true }
|
||||||
func (f *BigFlag) GetUsage() string { return f.Usage }
|
func (f *BigFlag) GetUsage() string { return f.Usage }
|
||||||
func (f *BigFlag) GetValue() string { return f.Value.String() }
|
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 {
|
func (f *BigFlag) GetDefaultText() string {
|
||||||
if f.DefaultText != "" {
|
if f.DefaultText != "" {
|
||||||
|
@ -18,13 +18,20 @@ package flags
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/internal/version"
|
"github.com/ethereum/go-ethereum/internal/version"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/mattn/go-isatty"
|
||||||
"github.com/urfave/cli/v2"
|
"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.
|
// NewApp creates an app with sane defaults.
|
||||||
func NewApp(usage string) *cli.App {
|
func NewApp(usage string) *cli.App {
|
||||||
git, _ := version.VCS()
|
git, _ := version.VCS()
|
||||||
@ -129,6 +136,14 @@ func doMigrateFlags(ctx *cli.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
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
|
cli.FlagStringer = FlagString
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,30 +153,31 @@ func FlagString(f cli.Flag) string {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
needsPlaceholder := df.TakesValue()
|
needsPlaceholder := df.TakesValue()
|
||||||
placeholder := ""
|
placeholder := ""
|
||||||
if needsPlaceholder {
|
if needsPlaceholder {
|
||||||
placeholder = "value"
|
placeholder = "value"
|
||||||
}
|
}
|
||||||
|
|
||||||
namesText := pad(cli.FlagNamePrefixer(df.Names(), placeholder), 30)
|
namesText := cli.FlagNamePrefixer(df.Names(), placeholder)
|
||||||
|
|
||||||
defaultValueString := ""
|
defaultValueString := ""
|
||||||
if s := df.GetDefaultText(); s != "" {
|
if s := df.GetDefaultText(); s != "" {
|
||||||
defaultValueString = " (default: " + s + ")"
|
defaultValueString = " (default: " + s + ")"
|
||||||
}
|
}
|
||||||
|
|
||||||
usage := strings.TrimSpace(df.GetUsage())
|
|
||||||
envHint := strings.TrimSpace(cli.FlagEnvHinter(df.GetEnvVars(), ""))
|
envHint := strings.TrimSpace(cli.FlagEnvHinter(df.GetEnvVars(), ""))
|
||||||
if len(envHint) > 0 {
|
if envHint != "" {
|
||||||
usage += " " + envHint
|
envHint = " (" + envHint[1:len(envHint)-1] + ")"
|
||||||
}
|
}
|
||||||
|
usage := strings.TrimSpace(df.GetUsage())
|
||||||
usage = wordWrap(usage, 80)
|
usage = wordWrap(usage, 80)
|
||||||
usage = indent(usage, 10)
|
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 {
|
func pad(s string, length int) string {
|
||||||
@ -213,3 +229,44 @@ func wordWrap(s string, width int) string {
|
|||||||
|
|
||||||
return output.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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user