github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/cli/context.go (about)

     1  package cli
     2  
     3  import (
     4  	"errors"
     5  	"flag"
     6  	"strconv"
     7  	"strings"
     8  	"time"
     9  )
    10  
    11  // Context is a type that is passed through to
    12  // each Handler action in a cli application. Context
    13  // can be used to retrieve context-specific Args and
    14  // parsed command-line options.
    15  type Context struct {
    16  	App            *App
    17  	Command        Command
    18  	flagSet        *flag.FlagSet
    19  	setFlags       map[string]bool
    20  	globalSetFlags map[string]bool
    21  	parentContext  *Context
    22  }
    23  
    24  // Creates a new context. For use in when invoking an App or Command action.
    25  func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context {
    26  	return &Context{App: app, flagSet: set, parentContext: parentCtx}
    27  }
    28  
    29  // Looks up the value of a local int flag, returns 0 if no int flag exists
    30  func (c *Context) Int(name string) int {
    31  	return lookupInt(name, c.flagSet)
    32  }
    33  
    34  // Looks up the value of a local time.Duration flag, returns 0 if no time.Duration flag exists
    35  func (c *Context) Duration(name string) time.Duration {
    36  	return lookupDuration(name, c.flagSet)
    37  }
    38  
    39  // Looks up the value of a local float64 flag, returns 0 if no float64 flag exists
    40  func (c *Context) Float64(name string) float64 {
    41  	return lookupFloat64(name, c.flagSet)
    42  }
    43  
    44  // Looks up the value of a local bool flag, returns false if no bool flag exists
    45  func (c *Context) Bool(name string) bool {
    46  	return lookupBool(name, c.flagSet)
    47  }
    48  
    49  // Looks up the value of a local boolT flag, returns false if no bool flag exists
    50  func (c *Context) BoolT(name string) bool {
    51  	return lookupBoolT(name, c.flagSet)
    52  }
    53  
    54  // Looks up the value of a local string flag, returns "" if no string flag exists
    55  func (c *Context) String(name string) string {
    56  	return lookupString(name, c.flagSet)
    57  }
    58  
    59  // Looks up the value of a local string slice flag, returns nil if no string slice flag exists
    60  func (c *Context) StringSlice(name string) []string {
    61  	return lookupStringSlice(name, c.flagSet)
    62  }
    63  
    64  // Looks up the value of a local int slice flag, returns nil if no int slice flag exists
    65  func (c *Context) IntSlice(name string) []int {
    66  	return lookupIntSlice(name, c.flagSet)
    67  }
    68  
    69  // Looks up the value of a local generic flag, returns nil if no generic flag exists
    70  func (c *Context) Generic(name string) interface{} {
    71  	return lookupGeneric(name, c.flagSet)
    72  }
    73  
    74  // Looks up the value of a global int flag, returns 0 if no int flag exists
    75  func (c *Context) GlobalInt(name string) int {
    76  	if fs := lookupGlobalFlagSet(name, c); fs != nil {
    77  		return lookupInt(name, fs)
    78  	}
    79  	return 0
    80  }
    81  
    82  // Looks up the value of a global time.Duration flag, returns 0 if no time.Duration flag exists
    83  func (c *Context) GlobalDuration(name string) time.Duration {
    84  	if fs := lookupGlobalFlagSet(name, c); fs != nil {
    85  		return lookupDuration(name, fs)
    86  	}
    87  	return 0
    88  }
    89  
    90  // Looks up the value of a global bool flag, returns false if no bool flag exists
    91  func (c *Context) GlobalBool(name string) bool {
    92  	if fs := lookupGlobalFlagSet(name, c); fs != nil {
    93  		return lookupBool(name, fs)
    94  	}
    95  	return false
    96  }
    97  
    98  // Looks up the value of a global string flag, returns "" if no string flag exists
    99  func (c *Context) GlobalString(name string) string {
   100  	if fs := lookupGlobalFlagSet(name, c); fs != nil {
   101  		return lookupString(name, fs)
   102  	}
   103  	return ""
   104  }
   105  
   106  // Looks up the value of a global string slice flag, returns nil if no string slice flag exists
   107  func (c *Context) GlobalStringSlice(name string) []string {
   108  	if fs := lookupGlobalFlagSet(name, c); fs != nil {
   109  		return lookupStringSlice(name, fs)
   110  	}
   111  	return nil
   112  }
   113  
   114  // Looks up the value of a global int slice flag, returns nil if no int slice flag exists
   115  func (c *Context) GlobalIntSlice(name string) []int {
   116  	if fs := lookupGlobalFlagSet(name, c); fs != nil {
   117  		return lookupIntSlice(name, fs)
   118  	}
   119  	return nil
   120  }
   121  
   122  // Looks up the value of a global generic flag, returns nil if no generic flag exists
   123  func (c *Context) GlobalGeneric(name string) interface{} {
   124  	if fs := lookupGlobalFlagSet(name, c); fs != nil {
   125  		return lookupGeneric(name, fs)
   126  	}
   127  	return nil
   128  }
   129  
   130  // Returns the number of flags set
   131  func (c *Context) NumFlags() int {
   132  	return c.flagSet.NFlag()
   133  }
   134  
   135  // Determines if the flag was actually set
   136  func (c *Context) IsSet(name string) bool {
   137  	if c.setFlags == nil {
   138  		c.setFlags = make(map[string]bool)
   139  		c.flagSet.Visit(func(f *flag.Flag) {
   140  			c.setFlags[f.Name] = true
   141  		})
   142  	}
   143  	return c.setFlags[name] == true
   144  }
   145  
   146  // Determines if the global flag was actually set
   147  func (c *Context) GlobalIsSet(name string) bool {
   148  	if c.globalSetFlags == nil {
   149  		c.globalSetFlags = make(map[string]bool)
   150  		ctx := c
   151  		if ctx.parentContext != nil {
   152  			ctx = ctx.parentContext
   153  		}
   154  		for ; ctx != nil && c.globalSetFlags[name] == false; ctx = ctx.parentContext {
   155  			ctx.flagSet.Visit(func(f *flag.Flag) {
   156  				c.globalSetFlags[f.Name] = true
   157  			})
   158  		}
   159  	}
   160  	return c.globalSetFlags[name]
   161  }
   162  
   163  // Returns a slice of flag names used in this context.
   164  func (c *Context) FlagNames() (names []string) {
   165  	for _, flag := range c.Command.Flags {
   166  		name := strings.Split(flag.GetName(), ",")[0]
   167  		if name == "help" {
   168  			continue
   169  		}
   170  		names = append(names, name)
   171  	}
   172  	return
   173  }
   174  
   175  // Returns a slice of global flag names used by the app.
   176  func (c *Context) GlobalFlagNames() (names []string) {
   177  	for _, flag := range c.App.Flags {
   178  		name := strings.Split(flag.GetName(), ",")[0]
   179  		if name == "help" || name == "version" {
   180  			continue
   181  		}
   182  		names = append(names, name)
   183  	}
   184  	return
   185  }
   186  
   187  // Returns the parent context, if any
   188  func (c *Context) Parent() *Context {
   189  	return c.parentContext
   190  }
   191  
   192  type Args []string
   193  
   194  // Returns the command line arguments associated with the context.
   195  func (c *Context) Args() Args {
   196  	args := Args(c.flagSet.Args())
   197  	return args
   198  }
   199  
   200  // Returns the number of the command line arguments.
   201  func (c *Context) NArg() int {
   202  	return len(c.Args())
   203  }
   204  
   205  // Returns the nth argument, or else a blank string
   206  func (a Args) Get(n int) string {
   207  	if len(a) > n {
   208  		return a[n]
   209  	}
   210  	return ""
   211  }
   212  
   213  // Returns the first argument, or else a blank string
   214  func (a Args) First() string {
   215  	return a.Get(0)
   216  }
   217  
   218  // Return the rest of the arguments (not the first one)
   219  // or else an empty string slice
   220  func (a Args) Tail() []string {
   221  	if len(a) >= 2 {
   222  		return []string(a)[1:]
   223  	}
   224  	return []string{}
   225  }
   226  
   227  // Checks if there are any arguments present
   228  func (a Args) Present() bool {
   229  	return len(a) != 0
   230  }
   231  
   232  // Swaps arguments at the given indexes
   233  func (a Args) Swap(from, to int) error {
   234  	if from >= len(a) || to >= len(a) {
   235  		return errors.New("index out of range")
   236  	}
   237  	a[from], a[to] = a[to], a[from]
   238  	return nil
   239  }
   240  
   241  func lookupGlobalFlagSet(name string, ctx *Context) *flag.FlagSet {
   242  	if ctx.parentContext != nil {
   243  		ctx = ctx.parentContext
   244  	}
   245  	for ; ctx != nil; ctx = ctx.parentContext {
   246  		if f := ctx.flagSet.Lookup(name); f != nil {
   247  			return ctx.flagSet
   248  		}
   249  	}
   250  	return nil
   251  }
   252  
   253  func lookupInt(name string, set *flag.FlagSet) int {
   254  	f := set.Lookup(name)
   255  	if f != nil {
   256  		val, err := strconv.Atoi(f.Value.String())
   257  		if err != nil {
   258  			return 0
   259  		}
   260  		return val
   261  	}
   262  
   263  	return 0
   264  }
   265  
   266  func lookupDuration(name string, set *flag.FlagSet) time.Duration {
   267  	f := set.Lookup(name)
   268  	if f != nil {
   269  		val, err := time.ParseDuration(f.Value.String())
   270  		if err == nil {
   271  			return val
   272  		}
   273  	}
   274  
   275  	return 0
   276  }
   277  
   278  func lookupFloat64(name string, set *flag.FlagSet) float64 {
   279  	f := set.Lookup(name)
   280  	if f != nil {
   281  		val, err := strconv.ParseFloat(f.Value.String(), 64)
   282  		if err != nil {
   283  			return 0
   284  		}
   285  		return val
   286  	}
   287  
   288  	return 0
   289  }
   290  
   291  func lookupString(name string, set *flag.FlagSet) string {
   292  	f := set.Lookup(name)
   293  	if f != nil {
   294  		return f.Value.String()
   295  	}
   296  
   297  	return ""
   298  }
   299  
   300  func lookupStringSlice(name string, set *flag.FlagSet) []string {
   301  	f := set.Lookup(name)
   302  	if f != nil {
   303  		return (f.Value.(*StringSlice)).Value()
   304  
   305  	}
   306  
   307  	return nil
   308  }
   309  
   310  func lookupIntSlice(name string, set *flag.FlagSet) []int {
   311  	f := set.Lookup(name)
   312  	if f != nil {
   313  		return (f.Value.(*IntSlice)).Value()
   314  
   315  	}
   316  
   317  	return nil
   318  }
   319  
   320  func lookupGeneric(name string, set *flag.FlagSet) interface{} {
   321  	f := set.Lookup(name)
   322  	if f != nil {
   323  		return f.Value
   324  	}
   325  	return nil
   326  }
   327  
   328  func lookupBool(name string, set *flag.FlagSet) bool {
   329  	f := set.Lookup(name)
   330  	if f != nil {
   331  		val, err := strconv.ParseBool(f.Value.String())
   332  		if err != nil {
   333  			return false
   334  		}
   335  		return val
   336  	}
   337  
   338  	return false
   339  }
   340  
   341  func lookupBoolT(name string, set *flag.FlagSet) bool {
   342  	f := set.Lookup(name)
   343  	if f != nil {
   344  		val, err := strconv.ParseBool(f.Value.String())
   345  		if err != nil {
   346  			return true
   347  		}
   348  		return val
   349  	}
   350  
   351  	return false
   352  }
   353  
   354  func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) {
   355  	switch ff.Value.(type) {
   356  	case *StringSlice:
   357  	default:
   358  		set.Set(name, ff.Value.String())
   359  	}
   360  }
   361  
   362  func normalizeFlags(flags []Flag, set *flag.FlagSet) error {
   363  	visited := make(map[string]bool)
   364  	set.Visit(func(f *flag.Flag) {
   365  		visited[f.Name] = true
   366  	})
   367  	for _, f := range flags {
   368  		parts := strings.Split(f.GetName(), ",")
   369  		if len(parts) == 1 {
   370  			continue
   371  		}
   372  		var ff *flag.Flag
   373  		for _, name := range parts {
   374  			name = strings.Trim(name, " ")
   375  			if visited[name] {
   376  				if ff != nil {
   377  					return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name)
   378  				}
   379  				ff = set.Lookup(name)
   380  			}
   381  		}
   382  		if ff == nil {
   383  			continue
   384  		}
   385  		for _, name := range parts {
   386  			name = strings.Trim(name, " ")
   387  			if !visited[name] {
   388  				copyFlag(name, ff, set)
   389  			}
   390  		}
   391  	}
   392  	return nil
   393  }