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