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  }