github.com/core-coin/go-core/v2@v2.1.9/cmd/utils/customflags.go (about) 1 // Copyright 2015 by the Authors 2 // This file is part of go-core. 3 // 4 // go-core 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-core 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-core. 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 "gopkg.in/urfave/cli.v1" 30 31 "github.com/core-coin/go-core/v2/common/math" 32 ) 33 34 // 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 // Custom cli.Flag type which expand the received string to an absolute path. 49 // e.g. ~/.core -> /home/username/.core 50 type DirectoryFlag struct { 51 Name string 52 Value DirectoryString 53 Usage string 54 EnvVar string 55 } 56 57 func (f DirectoryFlag) String() string { 58 return cli.FlagStringer(f) 59 } 60 61 // called by cli library, grabs variable from environment (if in env) 62 // and adds variable to flag set for parsing. 63 func (f DirectoryFlag) Apply(set *flag.FlagSet) { 64 eachName(f.Name, func(name string) { 65 set.Var(&f.Value, f.Name, f.Usage) 66 }) 67 } 68 69 func (f DirectoryFlag) GetName() string { 70 return f.Name 71 } 72 73 func (f *DirectoryFlag) Set(value string) { 74 f.Value.Set(value) 75 } 76 77 func eachName(longName string, fn func(string)) { 78 parts := strings.Split(longName, ",") 79 for _, name := range parts { 80 name = strings.Trim(name, " ") 81 fn(name) 82 } 83 } 84 85 type TextMarshaler interface { 86 encoding.TextMarshaler 87 encoding.TextUnmarshaler 88 } 89 90 // textMarshalerVal turns a TextMarshaler into a flag.Value 91 type textMarshalerVal struct { 92 v TextMarshaler 93 } 94 95 func (v textMarshalerVal) String() string { 96 if v.v == nil { 97 return "" 98 } 99 text, _ := v.v.MarshalText() 100 return string(text) 101 } 102 103 func (v textMarshalerVal) Set(s string) error { 104 return v.v.UnmarshalText([]byte(s)) 105 } 106 107 // TextMarshalerFlag wraps a TextMarshaler value. 108 type TextMarshalerFlag struct { 109 Name string 110 Value TextMarshaler 111 Usage string 112 EnvVar string 113 } 114 115 func (f TextMarshalerFlag) GetName() string { 116 return f.Name 117 } 118 119 func (f TextMarshalerFlag) String() string { 120 return cli.FlagStringer(f) 121 } 122 123 func (f TextMarshalerFlag) Apply(set *flag.FlagSet) { 124 eachName(f.Name, func(name string) { 125 set.Var(textMarshalerVal{f.Value}, f.Name, f.Usage) 126 }) 127 } 128 129 // GlobalTextMarshaler returns the value of a TextMarshalerFlag from the global flag set. 130 func GlobalTextMarshaler(ctx *cli.Context, name string) TextMarshaler { 131 val := ctx.GlobalGeneric(name) 132 if val == nil { 133 return nil 134 } 135 return val.(textMarshalerVal).v 136 } 137 138 // BigFlag is a command line flag that accepts 256 bit big integers in decimal or 139 // hexadecimal syntax. 140 type BigFlag struct { 141 Name string 142 Value *big.Int 143 Usage string 144 EnvVar string 145 } 146 147 // bigValue turns *big.Int into a flag.Value 148 type bigValue big.Int 149 150 func (b *bigValue) String() string { 151 if b == nil { 152 return "" 153 } 154 return (*big.Int)(b).String() 155 } 156 157 func (b *bigValue) Set(s string) error { 158 int, ok := math.ParseBig256(s) 159 if !ok { 160 return errors.New("invalid integer syntax") 161 } 162 *b = (bigValue)(*int) 163 return nil 164 } 165 166 func (f BigFlag) GetName() string { 167 return f.Name 168 } 169 170 func (f BigFlag) String() string { 171 return cli.FlagStringer(f) 172 } 173 174 func (f BigFlag) Apply(set *flag.FlagSet) { 175 eachName(f.Name, func(name string) { 176 set.Var((*bigValue)(f.Value), f.Name, f.Usage) 177 }) 178 } 179 180 // GlobalBig returns the value of a BigFlag from the global flag set. 181 func GlobalBig(ctx *cli.Context, name string) *big.Int { 182 val := ctx.GlobalGeneric(name) 183 if val == nil { 184 return nil 185 } 186 return (*big.Int)(val.(*bigValue)) 187 } 188 189 // Expands a file path 190 // 1. replace tilde with users home dir 191 // 2. expands embedded environment variables 192 // 3. cleans the path, e.g. /a/b/../c -> /a/c 193 // Note, it has limitations, e.g. ~someuser/tmp will not be expanded 194 func expandPath(p string) string { 195 if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") { 196 if home := HomeDir(); home != "" { 197 p = home + p[1:] 198 } 199 } 200 return path.Clean(os.ExpandEnv(p)) 201 } 202 203 func HomeDir() string { 204 if home := os.Getenv("HOME"); home != "" { 205 return home 206 } 207 if usr, err := user.Current(); err == nil { 208 return usr.HomeDir 209 } 210 return "" 211 }