| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- // Copyright 2020 The go-ethereum Authors
- // This file is part of the go-ethereum library.
- //
- // The go-ethereum library is free software: you can redistribute it and/or modify
- // it under the terms of the GNU Lesser General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // The go-ethereum library is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU Lesser General Public License for more details.
- //
- // 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/>.
- package flags
- import (
- "fmt"
- "strings"
- "github.com/ethereum/go-ethereum/params"
- "github.com/urfave/cli/v2"
- )
- // NewApp creates an app with sane defaults.
- func NewApp(gitCommit, gitDate, usage string) *cli.App {
- app := cli.NewApp()
- app.EnableBashCompletion = true
- app.Version = params.VersionWithCommit(gitCommit, gitDate)
- app.Usage = usage
- app.Copyright = "Copyright 2013-2022 The go-ethereum Authors"
- app.Before = func(ctx *cli.Context) error {
- MigrateGlobalFlags(ctx)
- return nil
- }
- return app
- }
- // Merge merges the given flag slices.
- func Merge(groups ...[]cli.Flag) []cli.Flag {
- var ret []cli.Flag
- for _, group := range groups {
- ret = append(ret, group...)
- }
- return ret
- }
- var migrationApplied = map[*cli.Command]struct{}{}
- // MigrateGlobalFlags makes all global flag values available in the
- // context. This should be called as early as possible in app.Before.
- //
- // Example:
- //
- // geth account new --keystore /tmp/mykeystore --lightkdf
- //
- // is equivalent after calling this method with:
- //
- // geth --keystore /tmp/mykeystore --lightkdf account new
- //
- // i.e. in the subcommand Action function of 'account new', ctx.Bool("lightkdf)
- // 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.
- iterate(ctx.App.Commands, func(cmd *cli.Command) {
- if cmd.Action == nil {
- return
- }
- action := cmd.Action
- cmd.Action = func(ctx *cli.Context) error {
- doMigrateFlags(ctx)
- return action(ctx)
- }
- })
- }
- func doMigrateFlags(ctx *cli.Context) {
- for _, name := range ctx.FlagNames() {
- for _, parent := range ctx.Lineage()[1:] {
- if parent.IsSet(name) {
- ctx.Set(name, parent.String(name))
- break
- }
- }
- }
- }
- func init() {
- cli.FlagStringer = FlagString
- }
- // FlagString prints a single flag in help.
- func FlagString(f cli.Flag) string {
- df, ok := f.(cli.DocGenerationFlag)
- if !ok {
- return ""
- }
- needsPlaceholder := df.TakesValue()
- placeholder := ""
- if needsPlaceholder {
- placeholder = "value"
- }
- namesText := pad(cli.FlagNamePrefixer(df.Names(), placeholder), 30)
- 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
- }
- 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))
- }
- return s
- }
- 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()
- }
|