github.com/tirogen/go-ethereum@v1.10.12-0.20221226051715-250cfede41b6/internal/flags/flags.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser 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  // The go-ethereum library 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 Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package flags
    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/tirogen/go-ethereum/common/math"
    30  	"github.com/urfave/cli/v2"
    31  )
    32  
    33  // DirectoryString is 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  var (
    48  	_ cli.Flag              = (*DirectoryFlag)(nil)
    49  	_ cli.RequiredFlag      = (*DirectoryFlag)(nil)
    50  	_ cli.VisibleFlag       = (*DirectoryFlag)(nil)
    51  	_ cli.DocGenerationFlag = (*DirectoryFlag)(nil)
    52  	_ cli.CategorizableFlag = (*DirectoryFlag)(nil)
    53  )
    54  
    55  // DirectoryFlag is custom cli.Flag type which expand the received string to an absolute path.
    56  // e.g. ~/.ethereum -> /home/username/.ethereum
    57  type DirectoryFlag struct {
    58  	Name string
    59  
    60  	Category    string
    61  	DefaultText string
    62  	Usage       string
    63  
    64  	Required   bool
    65  	Hidden     bool
    66  	HasBeenSet bool
    67  
    68  	Value DirectoryString
    69  
    70  	Aliases []string
    71  }
    72  
    73  // For cli.Flag:
    74  
    75  func (f *DirectoryFlag) Names() []string { return append([]string{f.Name}, f.Aliases...) }
    76  func (f *DirectoryFlag) IsSet() bool     { return f.HasBeenSet }
    77  func (f *DirectoryFlag) String() string  { return cli.FlagStringer(f) }
    78  
    79  // Apply called by cli library, grabs variable from environment (if in env)
    80  // and adds variable to flag set for parsing.
    81  func (f *DirectoryFlag) Apply(set *flag.FlagSet) error {
    82  	eachName(f, func(name string) {
    83  		set.Var(&f.Value, f.Name, f.Usage)
    84  	})
    85  	return nil
    86  }
    87  
    88  // For cli.RequiredFlag:
    89  
    90  func (f *DirectoryFlag) IsRequired() bool { return f.Required }
    91  
    92  // For cli.VisibleFlag:
    93  
    94  func (f *DirectoryFlag) IsVisible() bool { return !f.Hidden }
    95  
    96  // For cli.CategorizableFlag:
    97  
    98  func (f *DirectoryFlag) GetCategory() string { return f.Category }
    99  
   100  // For cli.DocGenerationFlag:
   101  
   102  func (f *DirectoryFlag) TakesValue() bool     { return true }
   103  func (f *DirectoryFlag) GetUsage() string     { return f.Usage }
   104  func (f *DirectoryFlag) GetValue() string     { return f.Value.String() }
   105  func (f *DirectoryFlag) GetEnvVars() []string { return nil } // env not supported
   106  
   107  func (f *DirectoryFlag) GetDefaultText() string {
   108  	if f.DefaultText != "" {
   109  		return f.DefaultText
   110  	}
   111  	return f.GetValue()
   112  }
   113  
   114  type TextMarshaler interface {
   115  	encoding.TextMarshaler
   116  	encoding.TextUnmarshaler
   117  }
   118  
   119  // textMarshalerVal turns a TextMarshaler into a flag.Value
   120  type textMarshalerVal struct {
   121  	v TextMarshaler
   122  }
   123  
   124  func (v textMarshalerVal) String() string {
   125  	if v.v == nil {
   126  		return ""
   127  	}
   128  	text, _ := v.v.MarshalText()
   129  	return string(text)
   130  }
   131  
   132  func (v textMarshalerVal) Set(s string) error {
   133  	return v.v.UnmarshalText([]byte(s))
   134  }
   135  
   136  var (
   137  	_ cli.Flag              = (*TextMarshalerFlag)(nil)
   138  	_ cli.RequiredFlag      = (*TextMarshalerFlag)(nil)
   139  	_ cli.VisibleFlag       = (*TextMarshalerFlag)(nil)
   140  	_ cli.DocGenerationFlag = (*TextMarshalerFlag)(nil)
   141  	_ cli.CategorizableFlag = (*TextMarshalerFlag)(nil)
   142  )
   143  
   144  // TextMarshalerFlag wraps a TextMarshaler value.
   145  type TextMarshalerFlag struct {
   146  	Name string
   147  
   148  	Category    string
   149  	DefaultText string
   150  	Usage       string
   151  
   152  	Required   bool
   153  	Hidden     bool
   154  	HasBeenSet bool
   155  
   156  	Value TextMarshaler
   157  
   158  	Aliases []string
   159  }
   160  
   161  // For cli.Flag:
   162  
   163  func (f *TextMarshalerFlag) Names() []string { return append([]string{f.Name}, f.Aliases...) }
   164  func (f *TextMarshalerFlag) IsSet() bool     { return f.HasBeenSet }
   165  func (f *TextMarshalerFlag) String() string  { return cli.FlagStringer(f) }
   166  
   167  func (f *TextMarshalerFlag) Apply(set *flag.FlagSet) error {
   168  	eachName(f, func(name string) {
   169  		set.Var(textMarshalerVal{f.Value}, f.Name, f.Usage)
   170  	})
   171  	return nil
   172  }
   173  
   174  // For cli.RequiredFlag:
   175  
   176  func (f *TextMarshalerFlag) IsRequired() bool { return f.Required }
   177  
   178  // For cli.VisibleFlag:
   179  
   180  func (f *TextMarshalerFlag) IsVisible() bool { return !f.Hidden }
   181  
   182  // For cli.CategorizableFlag:
   183  
   184  func (f *TextMarshalerFlag) GetCategory() string { return f.Category }
   185  
   186  // For cli.DocGenerationFlag:
   187  
   188  func (f *TextMarshalerFlag) TakesValue() bool     { return true }
   189  func (f *TextMarshalerFlag) GetUsage() string     { return f.Usage }
   190  func (f *TextMarshalerFlag) GetEnvVars() []string { return nil } // env not supported
   191  
   192  func (f *TextMarshalerFlag) GetValue() string {
   193  	t, err := f.Value.MarshalText()
   194  	if err != nil {
   195  		return "(ERR: " + err.Error() + ")"
   196  	}
   197  	return string(t)
   198  }
   199  
   200  func (f *TextMarshalerFlag) GetDefaultText() string {
   201  	if f.DefaultText != "" {
   202  		return f.DefaultText
   203  	}
   204  	return f.GetValue()
   205  }
   206  
   207  // GlobalTextMarshaler returns the value of a TextMarshalerFlag from the global flag set.
   208  func GlobalTextMarshaler(ctx *cli.Context, name string) TextMarshaler {
   209  	val := ctx.Generic(name)
   210  	if val == nil {
   211  		return nil
   212  	}
   213  	return val.(textMarshalerVal).v
   214  }
   215  
   216  var (
   217  	_ cli.Flag              = (*BigFlag)(nil)
   218  	_ cli.RequiredFlag      = (*BigFlag)(nil)
   219  	_ cli.VisibleFlag       = (*BigFlag)(nil)
   220  	_ cli.DocGenerationFlag = (*BigFlag)(nil)
   221  	_ cli.CategorizableFlag = (*BigFlag)(nil)
   222  )
   223  
   224  // BigFlag is a command line flag that accepts 256 bit big integers in decimal or
   225  // hexadecimal syntax.
   226  type BigFlag struct {
   227  	Name string
   228  
   229  	Category    string
   230  	DefaultText string
   231  	Usage       string
   232  
   233  	Required   bool
   234  	Hidden     bool
   235  	HasBeenSet bool
   236  
   237  	Value *big.Int
   238  
   239  	Aliases []string
   240  }
   241  
   242  // For cli.Flag:
   243  
   244  func (f *BigFlag) Names() []string { return append([]string{f.Name}, f.Aliases...) }
   245  func (f *BigFlag) IsSet() bool     { return f.HasBeenSet }
   246  func (f *BigFlag) String() string  { return cli.FlagStringer(f) }
   247  
   248  func (f *BigFlag) Apply(set *flag.FlagSet) error {
   249  	eachName(f, func(name string) {
   250  		f.Value = new(big.Int)
   251  		set.Var((*bigValue)(f.Value), f.Name, f.Usage)
   252  	})
   253  
   254  	return nil
   255  }
   256  
   257  // For cli.RequiredFlag:
   258  
   259  func (f *BigFlag) IsRequired() bool { return f.Required }
   260  
   261  // For cli.VisibleFlag:
   262  
   263  func (f *BigFlag) IsVisible() bool { return !f.Hidden }
   264  
   265  // For cli.CategorizableFlag:
   266  
   267  func (f *BigFlag) GetCategory() string { return f.Category }
   268  
   269  // For cli.DocGenerationFlag:
   270  
   271  func (f *BigFlag) TakesValue() bool     { return true }
   272  func (f *BigFlag) GetUsage() string     { return f.Usage }
   273  func (f *BigFlag) GetValue() string     { return f.Value.String() }
   274  func (f *BigFlag) GetEnvVars() []string { return nil } // env not supported
   275  
   276  func (f *BigFlag) GetDefaultText() string {
   277  	if f.DefaultText != "" {
   278  		return f.DefaultText
   279  	}
   280  	return f.GetValue()
   281  }
   282  
   283  // bigValue turns *big.Int into a flag.Value
   284  type bigValue big.Int
   285  
   286  func (b *bigValue) String() string {
   287  	if b == nil {
   288  		return ""
   289  	}
   290  	return (*big.Int)(b).String()
   291  }
   292  
   293  func (b *bigValue) Set(s string) error {
   294  	intVal, ok := math.ParseBig256(s)
   295  	if !ok {
   296  		return errors.New("invalid integer syntax")
   297  	}
   298  	*b = (bigValue)(*intVal)
   299  	return nil
   300  }
   301  
   302  // GlobalBig returns the value of a BigFlag from the global flag set.
   303  func GlobalBig(ctx *cli.Context, name string) *big.Int {
   304  	val := ctx.Generic(name)
   305  	if val == nil {
   306  		return nil
   307  	}
   308  	return (*big.Int)(val.(*bigValue))
   309  }
   310  
   311  // Expands a file path
   312  // 1. replace tilde with users home dir
   313  // 2. expands embedded environment variables
   314  // 3. cleans the path, e.g. /a/b/../c -> /a/c
   315  // Note, it has limitations, e.g. ~someuser/tmp will not be expanded
   316  func expandPath(p string) string {
   317  	if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") {
   318  		if home := HomeDir(); home != "" {
   319  			p = home + p[1:]
   320  		}
   321  	}
   322  	return path.Clean(os.ExpandEnv(p))
   323  }
   324  
   325  func HomeDir() string {
   326  	if home := os.Getenv("HOME"); home != "" {
   327  		return home
   328  	}
   329  	if usr, err := user.Current(); err == nil {
   330  		return usr.HomeDir
   331  	}
   332  	return ""
   333  }
   334  
   335  func eachName(f cli.Flag, fn func(string)) {
   336  	for _, name := range f.Names() {
   337  		name = strings.Trim(name, " ")
   338  		fn(name)
   339  	}
   340  }