Update helpers.go

This commit is contained in:
rajeshwariramya 2024-10-18 22:59:53 +05:30 committed by GitHub
parent b6c62d5887
commit 86026a832c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -14,297 +14,129 @@
// You should have received a copy of the GNU Lesser General Public License // You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package flags // package flags
import ( // import (
"fmt" // "fmt"
"os" // "os"
"regexp" // "regexp"
"sort" // "sort"
"strings" // "strings"
"github.com/ethereum/go-ethereum/internal/version" // "github.com/ethereum/go-ethereum/internal/version"
"github.com/ethereum/go-ethereum/log" // "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params" // "github.com/ethereum/go-ethereum/params"
"github.com/mattn/go-isatty" // "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 // // usecolor defines whether the CLI help should use colored output or normal dumb
// colorless terminal formatting. // // colorless terminal formatting.
var usecolor = (isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd())) && os.Getenv("TERM") != "dumb" // 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()
app := cli.NewApp() // app := cli.NewApp()
app.EnableBashCompletion = true // app.EnableBashCompletion = true
app.Version = params.VersionWithCommit(git.Commit, git.Date) // app.Version = params.VersionWithCommit(git.Commit, git.Date)
app.Usage = usage // app.Usage = usage
app.Copyright = "Copyright 2013-2024 The go-ethereum Authors" // app.Copyright = "Copyright 2013-2024 The go-ethereum Authors"
app.Before = func(ctx *cli.Context) error { // app.Before = func(ctx *cli.Context) error {
MigrateGlobalFlags(ctx) // MigrateGlobalFlags(ctx)
return nil // return nil
} // }
return app // return app
} // }
// Merge merges the given flag slices. // // Merge merges the given flag slices.
func Merge(groups ...[]cli.Flag) []cli.Flag { // func Merge(groups ...[]cli.Flag) []cli.Flag {
var ret []cli.Flag // var ret []cli.Flag
for _, group := range groups { // for _, group := range groups {
ret = append(ret, group...) // ret = append(ret, group...)
} // }
return ret // return ret
} // }
var migrationApplied = map[*cli.Command]struct{}{} // var migrationApplied = map[*cli.Command]struct{}{}
// MigrateGlobalFlags makes all global flag values available in the // // MigrateGlobalFlags makes all global flag values available in the
// context. This should be called as early as possible in app.Before. // // context. This should be called as early as possible in app.Before.
// // func MigrateGlobalFlags(ctx *cli.Context) {
// Example: // var iterate func(cs []*cli.Command, fn func(*cli.Command))
// // iterate = func(cs []*cli.Command, fn func(*cli.Command)) {
// geth account new --keystore /tmp/mykeystore --lightkdf // for _, cmd := range cs {
// // if _, ok := migrationApplied[cmd]; ok {
// is equivalent after calling this method with: // continue
// // }
// geth --keystore /tmp/mykeystore --lightkdf account new // migrationApplied[cmd] = struct{}{}
// // fn(cmd)
// i.e. in the subcommand Action function of 'account new', ctx.Bool("lightkdf) // iterate(cmd.Subcommands, fn)
// will return true even if --lightkdf is set as a global option. // }
// // }
// This function may become unnecessary when https://github.com/urfave/cli/pull/1245 is merged.
func MigrateGlobalFlags(ctx *cli.Context) {
var iterate func(cs []*cli.Command, fn func(*cli.Command))
iterate = func(cs []*cli.Command, fn func(*cli.Command)) {
for _, cmd := range cs {
if _, ok := migrationApplied[cmd]; ok {
continue
}
migrationApplied[cmd] = struct{}{}
fn(cmd)
iterate(cmd.Subcommands, fn)
}
}
// This iterates over all commands and wraps their action function. // // This iterates over all commands and wraps their action function.
iterate(ctx.App.Commands, func(cmd *cli.Command) { // iterate(ctx.App.Commands, func(cmd *cli.Command) {
if cmd.Action == nil { // if cmd.Action == nil {
return // return
} // }
action := cmd.Action // action := cmd.Action
cmd.Action = func(ctx *cli.Context) error { // cmd.Action = func(ctx *cli.Context) error {
doMigrateFlags(ctx) // doMigrateFlags(ctx)
return action(ctx) // return action(ctx)
} // }
}) // })
} // }
func doMigrateFlags(ctx *cli.Context) { // func doMigrateFlags(ctx *cli.Context) {
// Figure out if there are any aliases of commands. If there are, we want // // Figure out if there are any aliases of commands. If there are, we want
// to ignore them when iterating over the flags. // // to ignore them when iterating over the flags.
aliases := make(map[string]bool) // aliases := make(map[string]bool)
for _, fl := range ctx.Command.Flags { // for _, fl := range ctx.Command.Flags {
for _, alias := range fl.Names()[1:] { // for _, alias := range fl.Names()[1:] {
aliases[alias] = true // aliases[alias] = true
} // }
} // }
for _, name := range ctx.FlagNames() { // for _, name := range ctx.FlagNames() {
for _, parent := range ctx.Lineage()[1:] { // for _, parent := range ctx.Lineage()[1:] {
if parent.IsSet(name) { // if parent.IsSet(name) {
// When iterating across the lineage, we will be served both // if _, isAlias := aliases[name]; isAlias {
// the 'canon' and alias formats of all commands. In most cases, // continue
// it's fine to set it in the ctx multiple times (one for each // }
// name), however, the Slice-flags are not fine. // if result := parent.StringSlice(name); len(result) > 0 {
// The slice-flags accumulate, so if we set it once as // ctx.Set(name, strings.Join(result, ","))
// "foo" and once as alias "F", then both will be present in the slice. // } else {
if _, isAlias := aliases[name]; isAlias { // ctx.Set(name, parent.String(name))
continue // }
} // break
// If it is a string-slice, we need to set it as // }
// "alfa, beta, gamma" instead of "[alfa beta gamma]", in order // }
// for the backing StringSlice to parse it properly. // }
if result := parent.StringSlice(name); len(result) > 0 { // }
ctx.Set(name, strings.Join(result, ","))
} else {
ctx.Set(name, parent.String(name))
}
break
}
}
}
}
func init() { // func init() {
if usecolor { // if usecolor {
// Annotate all help categories with colors // cli.AppHelpTemplate = regexp.MustCompile("[A-Z ]+:").ReplaceAllString(cli.AppHelpTemplate, "\u001B[33m$0\u001B[0m")
cli.AppHelpTemplate = regexp.MustCompile("[A-Z ]+:").ReplaceAllString(cli.AppHelpTemplate, "\u001B[33m$0\u001B[0m") // 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
// }
// Annotate flag categories with colors (private template, so need to // // FlagString prints a single flag in help.
// copy-paste the entire thing here...) // func FlagString(f cli.Flag) string {
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}}") // df, ok := f.(cli.DocGenerationFlag)
} // if !ok {
cli.FlagStringer = FlagString // return ""
} // }
// needsPlaceholder := df.TakesValue()
// placeholder := ""
// if needsPlaceholder {
// placeholder = "value"
// }
// FlagString prints a single flag in help. // namesText := cli.FlagNamePrefixer(df.Names(), placeholder)
func FlagString(f cli.Flag) string {
df, ok := f.(cli.DocGenerationFlag)
if !ok {
return ""
}
needsPlaceholder := df.TakesValue()
placeholder := ""
if needsPlaceholder {
placeholder = "value"
}
namesText := cli.FlagNamePrefixer(df.Names(), placeholder) // defaultValueString := ""
// if s := df.GetDefaultText(); s != "" {
defaultValueString := "" // default
if s := df.GetDefaultText(); s != "" {
defaultValueString = " (default: " + s + ")"
}
envHint := strings.TrimSpace(cli.FlagEnvHinter(df.GetEnvVars(), ""))
if envHint != "" {
envHint = " (" + envHint[1:len(envHint)-1] + ")"
}
usage := strings.TrimSpace(df.GetUsage())
usage = wordWrap(usage, 80)
usage = indent(usage, 10)
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 indent(s string, nspace int) string {
ind := strings.Repeat(" ", nspace)
return ind + strings.ReplaceAll(s, "\n", "\n"+ind)
}
func wordWrap(s string, width int) string {
var (
output strings.Builder
lineLength = 0
)
for {
sp := strings.IndexByte(s, ' ')
var word string
if sp == -1 {
word = s
} else {
word = s[:sp]
}
wlen := len(word)
over := lineLength+wlen >= width
if over {
output.WriteByte('\n')
lineLength = 0
} else {
if lineLength != 0 {
output.WriteByte(' ')
lineLength++
}
}
output.WriteString(word)
lineLength += wlen
if sp == -1 {
break
}
s = s[wlen+1:]
}
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.StringSliceFlag:
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.Int64Flag:
flag.EnvVars = append(flag.EnvVars, envvar)
case *cli.Uint64Flag:
flag.EnvVars = append(flag.EnvVars, envvar)
case *cli.Float64Flag:
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)
}
}
}
// CheckEnvVars iterates over all the environment variables and checks if any of
// them look like a CLI flag but is not consumed. This can be used to detect old
// or mistyped names.
func CheckEnvVars(ctx *cli.Context, flags []cli.Flag, prefix string) {
known := make(map[string]string)
for _, flag := range flags {
docflag, ok := flag.(cli.DocGenerationFlag)
if !ok {
continue
}
for _, envvar := range docflag.GetEnvVars() {
known[envvar] = flag.Names()[0]
}
}
keyvals := os.Environ()
sort.Strings(keyvals)
for _, keyval := range keyvals {
key := strings.Split(keyval, "=")[0]
if !strings.HasPrefix(key, prefix) {
continue
}
if flag, ok := known[key]; ok {
if ctx.Count(flag) > 0 {
log.Info("Config environment variable found", "envvar", key, "shadowedby", "--"+flag)
} else {
log.Info("Config environment variable found", "envvar", key)
}
} else {
log.Warn("Unknown config environment variable", "envvar", key)
}
}
}