github.com/tyler-smith/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  }