github.com/aiyaya188/klaytn@v0.0.0-20220629133911-2c66fd5546f4/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/aiyaya188/klaytn/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 var migrationApplied = map[*cli.Command]struct{}{} 42 43 // MigrateGlobalFlags makes all global flag values available in the 44 // context. This should be called as early as possible in app.Before. 45 // 46 // Example: 47 // 48 // geth account new --keystore /tmp/mykeystore --lightkdf 49 // 50 // is equivalent after calling this method with: 51 // 52 // geth --keystore /tmp/mykeystore --lightkdf account new 53 // 54 // i.e. in the subcommand Action function of 'account new', ctx.Bool("lightkdf) 55 // will return true even if --lightkdf is set as a global option. 56 // 57 // This function may become unnecessary when https://github.com/urfave/cli/pull/1245 is merged. 58 func MigrateGlobalFlags(ctx *cli.Context) { 59 var iterate func(cs []*cli.Command, fn func(*cli.Command)) 60 iterate = func(cs []*cli.Command, fn func(*cli.Command)) { 61 for _, cmd := range cs { 62 if _, ok := migrationApplied[cmd]; ok { 63 continue 64 } 65 migrationApplied[cmd] = struct{}{} 66 fn(cmd) 67 iterate(cmd.Subcommands, fn) 68 } 69 } 70 71 // This iterates over all commands and wraps their action function. 72 iterate(ctx.App.Commands, func(cmd *cli.Command) { 73 action := cmd.Action 74 cmd.Action = func(ctx *cli.Context) error { 75 doMigrateFlags(ctx) 76 return action(ctx) 77 } 78 }) 79 } 80 81 func doMigrateFlags(ctx *cli.Context) { 82 for _, name := range ctx.FlagNames() { 83 for _, parent := range ctx.Lineage()[1:] { 84 if parent.IsSet(name) { 85 ctx.Set(name, parent.String(name)) 86 break 87 } 88 } 89 } 90 } 91 92 func init() { 93 cli.FlagStringer = FlagString 94 } 95 96 // FlagString prints a single flag in help. 97 func FlagString(f cli.Flag) string { 98 df, ok := f.(cli.DocGenerationFlag) 99 if !ok { 100 return "" 101 } 102 103 needsPlaceholder := df.TakesValue() 104 placeholder := "" 105 if needsPlaceholder { 106 placeholder = "value" 107 } 108 109 namesText := pad(cli.FlagNamePrefixer(df.Names(), placeholder), 30) 110 111 defaultValueString := "" 112 if s := df.GetDefaultText(); s != "" { 113 defaultValueString = " (default: " + s + ")" 114 } 115 116 usage := strings.TrimSpace(df.GetUsage()) 117 envHint := strings.TrimSpace(cli.FlagEnvHinter(df.GetEnvVars(), "")) 118 if len(envHint) > 0 { 119 usage += " " + envHint 120 } 121 122 usage = wordWrap(usage, 80) 123 usage = indent(usage, 10) 124 125 return fmt.Sprintf("\n %s%s\n%s", namesText, defaultValueString, usage) 126 } 127 128 func pad(s string, length int) string { 129 if len(s) < length { 130 s += strings.Repeat(" ", length-len(s)) 131 } 132 return s 133 } 134 135 func indent(s string, nspace int) string { 136 ind := strings.Repeat(" ", nspace) 137 return ind + strings.ReplaceAll(s, "\n", "\n"+ind) 138 } 139 140 func wordWrap(s string, width int) string { 141 var ( 142 output strings.Builder 143 lineLength = 0 144 ) 145 146 for { 147 sp := strings.IndexByte(s, ' ') 148 var word string 149 if sp == -1 { 150 word = s 151 } else { 152 word = s[:sp] 153 } 154 wlen := len(word) 155 over := lineLength+wlen >= width 156 if over { 157 output.WriteByte('\n') 158 lineLength = 0 159 } else { 160 if lineLength != 0 { 161 output.WriteByte(' ') 162 lineLength++ 163 } 164 } 165 166 output.WriteString(word) 167 lineLength += wlen 168 169 if sp == -1 { 170 break 171 } 172 s = s[wlen+1:] 173 } 174 175 return output.String() 176 }