github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/cmd/utils/customflags.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:31</date>
    10  //</624342606838501376>
    11  
    12  
    13  package utils
    14  
    15  import (
    16  	"encoding"
    17  	"errors"
    18  	"flag"
    19  	"fmt"
    20  	"math/big"
    21  	"os"
    22  	"os/user"
    23  	"path"
    24  	"strings"
    25  
    26  	"github.com/ethereum/go-ethereum/common/math"
    27  	"gopkg.in/urfave/cli.v1"
    28  )
    29  
    30  //
    31  //参数分析。这允许我们将值扩展到绝对路径,当
    32  //
    33  type DirectoryString struct {
    34  	Value string
    35  }
    36  
    37  func (self *DirectoryString) String() string {
    38  	return self.Value
    39  }
    40  
    41  func (self *DirectoryString) Set(value string) error {
    42  	self.Value = expandPath(value)
    43  	return nil
    44  }
    45  
    46  //将接收到的字符串扩展为绝对路径的自定义cli.flag类型。
    47  //
    48  type DirectoryFlag struct {
    49  	Name  string
    50  	Value DirectoryString
    51  	Usage string
    52  }
    53  
    54  func (self DirectoryFlag) String() string {
    55  	fmtString := "%s %v\t%v"
    56  	if len(self.Value.Value) > 0 {
    57  		fmtString = "%s \"%v\"\t%v"
    58  	}
    59  	return fmt.Sprintf(fmtString, prefixedNames(self.Name), self.Value.Value, self.Usage)
    60  }
    61  
    62  func eachName(longName string, fn func(string)) {
    63  	parts := strings.Split(longName, ",")
    64  	for _, name := range parts {
    65  		name = strings.Trim(name, " ")
    66  		fn(name)
    67  	}
    68  }
    69  
    70  //由cli库调用,从环境中获取变量(如果在env中)
    71  //
    72  func (self DirectoryFlag) Apply(set *flag.FlagSet) {
    73  	eachName(self.Name, func(name string) {
    74  		set.Var(&self.Value, self.Name, self.Usage)
    75  	})
    76  }
    77  
    78  type TextMarshaler interface {
    79  	encoding.TextMarshaler
    80  	encoding.TextUnmarshaler
    81  }
    82  
    83  //textmarshal将textmarshaler转换为flag.value
    84  type textMarshalerVal struct {
    85  	v TextMarshaler
    86  }
    87  
    88  func (v textMarshalerVal) String() string {
    89  	if v.v == nil {
    90  		return ""
    91  	}
    92  	text, _ := v.v.MarshalText()
    93  	return string(text)
    94  }
    95  
    96  func (v textMarshalerVal) Set(s string) error {
    97  	return v.v.UnmarshalText([]byte(s))
    98  }
    99  
   100  //
   101  type TextMarshalerFlag struct {
   102  	Name  string
   103  	Value TextMarshaler
   104  	Usage string
   105  }
   106  
   107  func (f TextMarshalerFlag) GetName() string {
   108  	return f.Name
   109  }
   110  
   111  func (f TextMarshalerFlag) String() string {
   112  	return fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage)
   113  }
   114  
   115  func (f TextMarshalerFlag) Apply(set *flag.FlagSet) {
   116  	eachName(f.Name, func(name string) {
   117  		set.Var(textMarshalerVal{f.Value}, f.Name, f.Usage)
   118  	})
   119  }
   120  
   121  //
   122  func GlobalTextMarshaler(ctx *cli.Context, name string) TextMarshaler {
   123  	val := ctx.GlobalGeneric(name)
   124  	if val == nil {
   125  		return nil
   126  	}
   127  	return val.(textMarshalerVal).v
   128  }
   129  
   130  //
   131  //
   132  type BigFlag struct {
   133  	Name  string
   134  	Value *big.Int
   135  	Usage string
   136  }
   137  
   138  //big value将*big.int转换为flag.value
   139  type bigValue big.Int
   140  
   141  func (b *bigValue) String() string {
   142  	if b == nil {
   143  		return ""
   144  	}
   145  	return (*big.Int)(b).String()
   146  }
   147  
   148  func (b *bigValue) Set(s string) error {
   149  	int, ok := math.ParseBig256(s)
   150  	if !ok {
   151  		return errors.New("invalid integer syntax")
   152  	}
   153  	*b = (bigValue)(*int)
   154  	return nil
   155  }
   156  
   157  func (f BigFlag) GetName() string {
   158  	return f.Name
   159  }
   160  
   161  func (f BigFlag) String() string {
   162  	fmtString := "%s %v\t%v"
   163  	if f.Value != nil {
   164  		fmtString = "%s \"%v\"\t%v"
   165  	}
   166  	return fmt.Sprintf(fmtString, prefixedNames(f.Name), f.Value, f.Usage)
   167  }
   168  
   169  func (f BigFlag) Apply(set *flag.FlagSet) {
   170  	eachName(f.Name, func(name string) {
   171  		set.Var((*bigValue)(f.Value), f.Name, f.Usage)
   172  	})
   173  }
   174  
   175  //GlobalBigFlag从全局标志集返回BigFlag的值。
   176  func GlobalBig(ctx *cli.Context, name string) *big.Int {
   177  	val := ctx.GlobalGeneric(name)
   178  	if val == nil {
   179  		return nil
   180  	}
   181  	return (*big.Int)(val.(*bigValue))
   182  }
   183  
   184  func prefixFor(name string) (prefix string) {
   185  	if len(name) == 1 {
   186  		prefix = "-"
   187  	} else {
   188  		prefix = "--"
   189  	}
   190  
   191  	return
   192  }
   193  
   194  func prefixedNames(fullName string) (prefixed string) {
   195  	parts := strings.Split(fullName, ",")
   196  	for i, name := range parts {
   197  		name = strings.Trim(name, " ")
   198  		prefixed += prefixFor(name) + name
   199  		if i < len(parts)-1 {
   200  			prefixed += ", "
   201  		}
   202  	}
   203  	return
   204  }
   205  
   206  func (self DirectoryFlag) GetName() string {
   207  	return self.Name
   208  }
   209  
   210  func (self *DirectoryFlag) Set(value string) {
   211  	self.Value.Value = value
   212  }
   213  
   214  //展开文件路径
   215  //1。用用户主目录替换tilde
   216  //2。扩展嵌入的环境变量
   217  //三。清理路径,例如/a/b/。/c->/a/c
   218  //注意,它有局限性,例如~someuser/tmp将不会扩展
   219  func expandPath(p string) string {
   220  	if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") {
   221  		if home := homeDir(); home != "" {
   222  			p = home + p[1:]
   223  		}
   224  	}
   225  	return path.Clean(os.ExpandEnv(p))
   226  }
   227  
   228  func homeDir() string {
   229  	if home := os.Getenv("HOME"); home != "" {
   230  		return home
   231  	}
   232  	if usr, err := user.Current(); err == nil {
   233  		return usr.HomeDir
   234  	}
   235  	return ""
   236  }
   237