customflags.go 5.4 KB

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