github.com/ethw3/go-ethereuma@v0.0.0-20221013053120-c14602a4c23c/internal/flags/helpers.go (about)

     1  // Copyright 2020 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package flags
    18  
    19  import (
    20  	"fmt"
    21  	"strings"
    22  
    23  	"github.com/ethw3/go-ethereuma/params"
    24  	"github.com/urfave/cli/v2"
    25  )
    26  
    27  // NewApp creates an app with sane defaults.
    28  func NewApp(gitCommit, gitDate, usage string) *cli.App {
    29  	app := cli.NewApp()
    30  	app.EnableBashCompletion = true
    31  	app.Version = params.VersionWithCommit(gitCommit, gitDate)
    32  	app.Usage = usage
    33  	app.Copyright = "Copyright 2013-2022 The go-ethereum Authors"
    34  	app.Before = func(ctx *cli.Context) error {
    35  		MigrateGlobalFlags(ctx)
    36  		return nil
    37  	}
    38  	return app
    39  }
    40  
    41  // Merge merges the given flag slices.
    42  func Merge(groups ...[]cli.Flag) []cli.Flag {
    43  	var ret []cli.Flag
    44  	for _, group := range groups {
    45  		ret = append(ret, group...)
    46  	}
    47  	return ret
    48  }
    49  
    50  var migrationApplied = map[*cli.Command]struct{}{}
    51  
    52  // MigrateGlobalFlags makes all global flag values available in the
    53  // context. This should be called as early as possible in app.Before.
    54  //
    55  // Example:
    56  //
    57  //    geth account new --keystore /tmp/mykeystore --lightkdf
    58  //
    59  // is equivalent after calling this method with:
    60  //
    61  //    geth --keystore /tmp/mykeystore --lightkdf account new
    62  //
    63  // i.e. in the subcommand Action function of 'account new', ctx.Bool("lightkdf)
    64  // will return true even if --lightkdf is set as a global option.
    65  //
    66  // This function may become unnecessary when https://github.com/urfave/cli/pull/1245 is merged.
    67  func MigrateGlobalFlags(ctx *cli.Context) {
    68  	var iterate func(cs []*cli.Command, fn func(*cli.Command))
    69  	iterate = func(cs []*cli.Command, fn func(*cli.Command)) {
    70  		for _, cmd := range cs {
    71  			if _, ok := migrationApplied[cmd]; ok {
    72  				continue
    73  			}
    74  			migrationApplied[cmd] = struct{}{}
    75  			fn(cmd)
    76  			iterate(cmd.Subcommands, fn)
    77  		}
    78  	}
    79  
    80  	// This iterates over all commands and wraps their action function.
    81  	iterate(ctx.App.Commands, func(cmd *cli.Command) {
    82  		if cmd.Action == nil {
    83  			return
    84  		}
    85  
    86  		action := cmd.Action
    87  		cmd.Action = func(ctx *cli.Context) error {
    88  			doMigrateFlags(ctx)
    89  			return action(ctx)
    90  		}
    91  	})
    92  }
    93  
    94  func doMigrateFlags(ctx *cli.Context) {
    95  	for _, name := range ctx.FlagNames() {
    96  		for _, parent := range ctx.Lineage()[1:] {
    97  			if parent.IsSet(name) {
    98  				ctx.Set(name, parent.String(name))
    99  				break
   100  			}
   101  		}
   102  	}
   103  }
   104  
   105  func init() {
   106  	cli.FlagStringer = FlagString
   107  }
   108  
   109  // FlagString prints a single flag in help.
   110  func FlagString(f cli.Flag) string {
   111  	df, ok := f.(cli.DocGenerationFlag)
   112  	if !ok {
   113  		return ""
   114  	}
   115  
   116  	needsPlaceholder := df.TakesValue()
   117  	placeholder := ""
   118  	if needsPlaceholder {
   119  		placeholder = "value"
   120  	}
   121  
   122  	namesText := pad(cli.FlagNamePrefixer(df.Names(), placeholder), 30)
   123  
   124  	defaultValueString := ""
   125  	if s := df.GetDefaultText(); s != "" {
   126  		defaultValueString = " (default: " + s + ")"
   127  	}
   128  
   129  	usage := strings.TrimSpace(df.GetUsage())
   130  	envHint := strings.TrimSpace(cli.FlagEnvHinter(df.GetEnvVars(), ""))
   131  	if len(envHint) > 0 {
   132  		usage += " " + envHint
   133  	}
   134  
   135  	usage = wordWrap(usage, 80)
   136  	usage = indent(usage, 10)
   137  
   138  	return fmt.Sprintf("\n    %s%s\n%s", namesText, defaultValueString, usage)
   139  }
   140  
   141  func pad(s string, length int) string {
   142  	if len(s) < length {
   143  		s += strings.Repeat(" ", length-len(s))
   144  	}
   145  	return s
   146  }
   147  
   148  func indent(s string, nspace int) string {
   149  	ind := strings.Repeat(" ", nspace)
   150  	return ind + strings.ReplaceAll(s, "\n", "\n"+ind)
   151  }
   152  
   153  func wordWrap(s string, width int) string {
   154  	var (
   155  		output     strings.Builder
   156  		lineLength = 0
   157  	)
   158  
   159  	for {
   160  		sp := strings.IndexByte(s, ' ')
   161  		var word string
   162  		if sp == -1 {
   163  			word = s
   164  		} else {
   165  			word = s[:sp]
   166  		}
   167  		wlen := len(word)
   168  		over := lineLength+wlen >= width
   169  		if over {
   170  			output.WriteByte('\n')
   171  			lineLength = 0
   172  		} else {
   173  			if lineLength != 0 {
   174  				output.WriteByte(' ')
   175  				lineLength++
   176  			}
   177  		}
   178  
   179  		output.WriteString(word)
   180  		lineLength += wlen
   181  
   182  		if sp == -1 {
   183  			break
   184  		}
   185  		s = s[wlen+1:]
   186  	}
   187  
   188  	return output.String()
   189  }