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 }