github.com/c2s/go-ethereum@v1.9.7/cmd/utils/customflags.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU 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 // go-ethereum 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 General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package utils 18 19 import ( 20 "encoding" 21 "errors" 22 "flag" 23 "math/big" 24 "os" 25 "os/user" 26 "path" 27 "strings" 28 29 "github.com/ethereum/go-ethereum/common/math" 30 "gopkg.in/urfave/cli.v1" 31 ) 32 33 // Custom type which is registered in the flags library which cli uses for 34 // argument parsing. This allows us to expand Value to an absolute path when 35 // the argument is parsed 36 type DirectoryString string 37 38 func (s *DirectoryString) String() string { 39 return string(*s) 40 } 41 42 func (s *DirectoryString) Set(value string) error { 43 *s = DirectoryString(expandPath(value)) 44 return nil 45 } 46 47 // Custom cli.Flag type which expand the received string to an absolute path. 48 // e.g. ~/.ethereum -> /home/username/.ethereum 49 type DirectoryFlag struct { 50 Name string 51 Value DirectoryString 52 Usage string 53 EnvVar string 54 } 55 56 func (f DirectoryFlag) String() string { 57 return cli.FlagStringer(f) 58 } 59 60 // called by cli library, grabs variable from environment (if in env) 61 // and adds variable to flag set for parsing. 62 func (f DirectoryFlag) Apply(set *flag.FlagSet) { 63 eachName(f.Name, func(name string) { 64 set.Var(&f.Value, f.Name, f.Usage) 65 }) 66 } 67 68 func (f DirectoryFlag) GetName() string { 69 return f.Name 70 } 71 72 func (f *DirectoryFlag) Set(value string) { 73 f.Value.Set(value) 74 } 75 76 func eachName(longName string, fn func(string)) { 77 parts := strings.Split(longName, ",") 78 for _, name := range parts { 79 name = strings.Trim(name, " ") 80 fn(name) 81 } 82 } 83 84 type TextMarshaler interface { 85 encoding.TextMarshaler 86 encoding.TextUnmarshaler 87 } 88 89 // textMarshalerVal turns a TextMarshaler into a flag.Value 90 type textMarshalerVal struct { 91 v TextMarshaler 92 } 93 94 func (v textMarshalerVal) String() string { 95 if v.v == nil { 96 return "" 97 } 98 text, _ := v.v.MarshalText() 99 return string(text) 100 } 101 102 func (v textMarshalerVal) Set(s string) error { 103 return v.v.UnmarshalText([]byte(s)) 104 } 105 106 // TextMarshalerFlag wraps a TextMarshaler value. 107 type TextMarshalerFlag struct { 108 Name string 109 Value TextMarshaler 110 Usage string 111 EnvVar string 112 } 113 114 func (f TextMarshalerFlag) GetName() string { 115 return f.Name 116 } 117 118 func (f TextMarshalerFlag) String() string { 119 return cli.FlagStringer(f) 120 } 121 122 func (f TextMarshalerFlag) Apply(set *flag.FlagSet) { 123 eachName(f.Name, func(name string) { 124 set.Var(textMarshalerVal{f.Value}, f.Name, f.Usage) 125 }) 126 } 127 128 // GlobalTextMarshaler returns the value of a TextMarshalerFlag from the global flag set. 129 func GlobalTextMarshaler(ctx *cli.Context, name string) TextMarshaler { 130 val := ctx.GlobalGeneric(name) 131 if val == nil { 132 return nil 133 } 134 return val.(textMarshalerVal).v 135 } 136 137 // BigFlag is a command line flag that accepts 256 bit big integers in decimal or 138 // hexadecimal syntax. 139 type BigFlag struct { 140 Name string 141 Value *big.Int 142 Usage string 143 EnvVar string 144 } 145 146 // bigValue turns *big.Int into a flag.Value 147 type bigValue big.Int 148 149 func (b *bigValue) String() string { 150 if b == nil { 151 return "" 152 } 153 return (*big.Int)(b).String() 154 } 155 156 func (b *bigValue) Set(s string) error { 157 int, ok := math.ParseBig256(s) 158 if !ok { 159 return errors.New("invalid integer syntax") 160 } 161 *b = (bigValue)(*int) 162 return nil 163 } 164 165 func (f BigFlag) GetName() string { 166 return f.Name 167 } 168 169 func (f BigFlag) String() string { 170 return cli.FlagStringer(f) 171 } 172 173 func (f BigFlag) Apply(set *flag.FlagSet) { 174 eachName(f.Name, func(name string) { 175 set.Var((*bigValue)(f.Value), f.Name, f.Usage) 176 }) 177 } 178 179 // GlobalBig returns the value of a BigFlag from the global flag set. 180 func GlobalBig(ctx *cli.Context, name string) *big.Int { 181 val := ctx.GlobalGeneric(name) 182 if val == nil { 183 return nil 184 } 185 return (*big.Int)(val.(*bigValue)) 186 } 187 188 func prefixFor(name string) (prefix string) { 189 if len(name) == 1 { 190 prefix = "-" 191 } else { 192 prefix = "--" 193 } 194 195 return 196 } 197 198 func prefixedNames(fullName string) (prefixed string) { 199 parts := strings.Split(fullName, ",") 200 for i, name := range parts { 201 name = strings.Trim(name, " ") 202 prefixed += prefixFor(name) + name 203 if i < len(parts)-1 { 204 prefixed += ", " 205 } 206 } 207 return 208 } 209 210 // Expands a file path 211 // 1. replace tilde with users home dir 212 // 2. expands embedded environment variables 213 // 3. cleans the path, e.g. /a/b/../c -> /a/c 214 // Note, it has limitations, e.g. ~someuser/tmp will not be expanded 215 func expandPath(p string) string { 216 if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") { 217 if home := homeDir(); home != "" { 218 p = home + p[1:] 219 } 220 } 221 return path.Clean(os.ExpandEnv(p)) 222 } 223 224 func homeDir() string { 225 if home := os.Getenv("HOME"); home != "" { 226 return home 227 } 228 if usr, err := user.Current(); err == nil { 229 return usr.HomeDir 230 } 231 return "" 232 }