github.com/ethereum/go-ethereum@v1.16.1/internal/flags/flags.go (about) 1 // Copyright 2015 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 "errors" 21 "flag" 22 "fmt" 23 "math/big" 24 "os" 25 "os/user" 26 "path/filepath" 27 "strings" 28 "syscall" 29 30 "github.com/ethereum/go-ethereum/common/math" 31 "github.com/urfave/cli/v2" 32 ) 33 34 // DirectoryString is custom type which is registered in the flags library which cli uses for 35 // argument parsing. This allows us to expand Value to an absolute path when 36 // the argument is parsed 37 type DirectoryString string 38 39 func (s *DirectoryString) String() string { 40 return string(*s) 41 } 42 43 func (s *DirectoryString) Set(value string) error { 44 *s = DirectoryString(expandPath(value)) 45 return nil 46 } 47 48 var ( 49 _ cli.Flag = (*DirectoryFlag)(nil) 50 _ cli.RequiredFlag = (*DirectoryFlag)(nil) 51 _ cli.VisibleFlag = (*DirectoryFlag)(nil) 52 _ cli.DocGenerationFlag = (*DirectoryFlag)(nil) 53 _ cli.CategorizableFlag = (*DirectoryFlag)(nil) 54 ) 55 56 // DirectoryFlag is custom cli.Flag type which expand the received string to an absolute path. 57 // e.g. ~/.ethereum -> /home/username/.ethereum 58 type DirectoryFlag struct { 59 Name string 60 61 Category string 62 DefaultText string 63 Usage string 64 65 Required bool 66 Hidden bool 67 HasBeenSet bool 68 69 Value DirectoryString 70 71 Aliases []string 72 EnvVars []string 73 } 74 75 // For cli.Flag: 76 77 func (f *DirectoryFlag) Names() []string { return append([]string{f.Name}, f.Aliases...) } 78 func (f *DirectoryFlag) IsSet() bool { return f.HasBeenSet } 79 func (f *DirectoryFlag) String() string { return cli.FlagStringer(f) } 80 81 // Apply called by cli library, grabs variable from environment (if in env) 82 // and adds variable to flag set for parsing. 83 func (f *DirectoryFlag) Apply(set *flag.FlagSet) error { 84 for _, envVar := range f.EnvVars { 85 envVar = strings.TrimSpace(envVar) 86 if value, found := syscall.Getenv(envVar); found { 87 f.Value.Set(value) 88 f.HasBeenSet = true 89 break 90 } 91 } 92 eachName(f, func(name string) { 93 set.Var(&f.Value, name, f.Usage) 94 }) 95 return nil 96 } 97 98 // For cli.RequiredFlag: 99 100 func (f *DirectoryFlag) IsRequired() bool { return f.Required } 101 102 // For cli.VisibleFlag: 103 104 func (f *DirectoryFlag) IsVisible() bool { return !f.Hidden } 105 106 // For cli.CategorizableFlag: 107 108 func (f *DirectoryFlag) GetCategory() string { return f.Category } 109 110 // For cli.DocGenerationFlag: 111 112 func (f *DirectoryFlag) TakesValue() bool { return true } 113 func (f *DirectoryFlag) GetUsage() string { return f.Usage } 114 func (f *DirectoryFlag) GetValue() string { return f.Value.String() } 115 func (f *DirectoryFlag) GetEnvVars() []string { return f.EnvVars } 116 117 func (f *DirectoryFlag) GetDefaultText() string { 118 if f.DefaultText != "" { 119 return f.DefaultText 120 } 121 return f.GetValue() 122 } 123 124 var ( 125 _ cli.Flag = (*BigFlag)(nil) 126 _ cli.RequiredFlag = (*BigFlag)(nil) 127 _ cli.VisibleFlag = (*BigFlag)(nil) 128 _ cli.DocGenerationFlag = (*BigFlag)(nil) 129 _ cli.CategorizableFlag = (*BigFlag)(nil) 130 ) 131 132 // BigFlag is a command line flag that accepts 256 bit big integers in decimal or 133 // hexadecimal syntax. 134 type BigFlag struct { 135 Name string 136 137 Category string 138 DefaultText string 139 Usage string 140 141 Required bool 142 Hidden bool 143 HasBeenSet bool 144 145 Value *big.Int 146 defaultValue *big.Int 147 148 Aliases []string 149 EnvVars []string 150 } 151 152 // For cli.Flag: 153 154 func (f *BigFlag) Names() []string { return append([]string{f.Name}, f.Aliases...) } 155 func (f *BigFlag) IsSet() bool { return f.HasBeenSet } 156 func (f *BigFlag) String() string { return cli.FlagStringer(f) } 157 158 func (f *BigFlag) Apply(set *flag.FlagSet) error { 159 // Set default value so that environment wont be able to overwrite it 160 if f.Value != nil { 161 f.defaultValue = new(big.Int).Set(f.Value) 162 } 163 for _, envVar := range f.EnvVars { 164 envVar = strings.TrimSpace(envVar) 165 if value, found := syscall.Getenv(envVar); found { 166 if _, ok := f.Value.SetString(value, 10); !ok { 167 return fmt.Errorf("could not parse %q from environment variable %q for flag %s", value, envVar, f.Name) 168 } 169 f.HasBeenSet = true 170 break 171 } 172 } 173 eachName(f, func(name string) { 174 f.Value = new(big.Int) 175 set.Var((*bigValue)(f.Value), name, f.Usage) 176 }) 177 return nil 178 } 179 180 // For cli.RequiredFlag: 181 182 func (f *BigFlag) IsRequired() bool { return f.Required } 183 184 // For cli.VisibleFlag: 185 186 func (f *BigFlag) IsVisible() bool { return !f.Hidden } 187 188 // For cli.CategorizableFlag: 189 190 func (f *BigFlag) GetCategory() string { return f.Category } 191 192 // For cli.DocGenerationFlag: 193 194 func (f *BigFlag) TakesValue() bool { return true } 195 func (f *BigFlag) GetUsage() string { return f.Usage } 196 func (f *BigFlag) GetValue() string { return f.Value.String() } 197 func (f *BigFlag) GetEnvVars() []string { return f.EnvVars } 198 199 func (f *BigFlag) GetDefaultText() string { 200 if f.DefaultText != "" { 201 return f.DefaultText 202 } 203 return f.defaultValue.String() 204 } 205 206 // bigValue turns *big.Int into a flag.Value 207 type bigValue big.Int 208 209 func (b *bigValue) String() string { 210 if b == nil { 211 return "" 212 } 213 return (*big.Int)(b).String() 214 } 215 216 func (b *bigValue) Set(s string) error { 217 intVal, ok := math.ParseBig256(s) 218 if !ok { 219 return errors.New("invalid integer syntax") 220 } 221 *b = (bigValue)(*intVal) 222 return nil 223 } 224 225 // GlobalBig returns the value of a BigFlag from the global flag set. 226 func GlobalBig(ctx *cli.Context, name string) *big.Int { 227 val := ctx.Generic(name) 228 if val == nil { 229 return nil 230 } 231 return (*big.Int)(val.(*bigValue)) 232 } 233 234 // Expands a file path 235 // 1. replace tilde with users home dir 236 // 2. expands embedded environment variables 237 // 3. cleans the path, e.g. /a/b/../c -> /a/c 238 // Note, it has limitations, e.g. ~someuser/tmp will not be expanded 239 func expandPath(p string) string { 240 // Named pipes are not file paths on windows, ignore 241 if strings.HasPrefix(p, `\\.\pipe`) { 242 return p 243 } 244 if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") { 245 if home := HomeDir(); home != "" { 246 p = home + p[1:] 247 } 248 } 249 return filepath.Clean(os.ExpandEnv(p)) 250 } 251 252 func HomeDir() string { 253 if home := os.Getenv("HOME"); home != "" { 254 return home 255 } 256 if usr, err := user.Current(); err == nil { 257 return usr.HomeDir 258 } 259 return "" 260 } 261 262 func eachName(f cli.Flag, fn func(string)) { 263 for _, name := range f.Names() { 264 name = strings.Trim(name, " ") 265 fn(name) 266 } 267 }