github.com/MetalBlockchain/subnet-evm@v0.4.9/internal/flags/helpers.go (about)

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