...

Source file src/github.com/urfave/cli/v2/flag_int_slice.go

Documentation: github.com/urfave/cli/v2

     1  package cli
     2  
     3  import (
     4  	"encoding/json"
     5  	"flag"
     6  	"fmt"
     7  	"strconv"
     8  	"strings"
     9  )
    10  
    11  // IntSlice wraps []int to satisfy flag.Value
    12  type IntSlice struct {
    13  	slice      []int
    14  	separator  separatorSpec
    15  	hasBeenSet bool
    16  }
    17  
    18  // NewIntSlice makes an *IntSlice with default values
    19  func NewIntSlice(defaults ...int) *IntSlice {
    20  	return &IntSlice{slice: append([]int{}, defaults...)}
    21  }
    22  
    23  // clone allocate a copy of self object
    24  func (i *IntSlice) clone() *IntSlice {
    25  	n := &IntSlice{
    26  		slice:      make([]int, len(i.slice)),
    27  		hasBeenSet: i.hasBeenSet,
    28  	}
    29  	copy(n.slice, i.slice)
    30  	return n
    31  }
    32  
    33  // TODO: Consistently have specific Set function for Int64 and Float64 ?
    34  // SetInt directly adds an integer to the list of values
    35  func (i *IntSlice) SetInt(value int) {
    36  	if !i.hasBeenSet {
    37  		i.slice = []int{}
    38  		i.hasBeenSet = true
    39  	}
    40  
    41  	i.slice = append(i.slice, value)
    42  }
    43  
    44  func (i *IntSlice) WithSeparatorSpec(spec separatorSpec) {
    45  	i.separator = spec
    46  }
    47  
    48  // Set parses the value into an integer and appends it to the list of values
    49  func (i *IntSlice) Set(value string) error {
    50  	if !i.hasBeenSet {
    51  		i.slice = []int{}
    52  		i.hasBeenSet = true
    53  	}
    54  
    55  	if strings.HasPrefix(value, slPfx) {
    56  		// Deserializing assumes overwrite
    57  		_ = json.Unmarshal([]byte(strings.Replace(value, slPfx, "", 1)), &i.slice)
    58  		i.hasBeenSet = true
    59  		return nil
    60  	}
    61  
    62  	for _, s := range i.separator.flagSplitMultiValues(value) {
    63  		tmp, err := strconv.ParseInt(strings.TrimSpace(s), 0, 64)
    64  		if err != nil {
    65  			return err
    66  		}
    67  
    68  		i.slice = append(i.slice, int(tmp))
    69  	}
    70  
    71  	return nil
    72  }
    73  
    74  // String returns a readable representation of this value (for usage defaults)
    75  func (i *IntSlice) String() string {
    76  	v := i.slice
    77  	if v == nil {
    78  		// treat nil the same as zero length non-nil
    79  		v = make([]int, 0)
    80  	}
    81  	return fmt.Sprintf("%#v", v)
    82  }
    83  
    84  // Serialize allows IntSlice to fulfill Serializer
    85  func (i *IntSlice) Serialize() string {
    86  	jsonBytes, _ := json.Marshal(i.slice)
    87  	return fmt.Sprintf("%s%s", slPfx, string(jsonBytes))
    88  }
    89  
    90  // Value returns the slice of ints set by this flag
    91  func (i *IntSlice) Value() []int {
    92  	return i.slice
    93  }
    94  
    95  // Get returns the slice of ints set by this flag
    96  func (i *IntSlice) Get() interface{} {
    97  	return *i
    98  }
    99  
   100  // String returns a readable representation of this value
   101  // (for usage defaults)
   102  func (f *IntSliceFlag) String() string {
   103  	return FlagStringer(f)
   104  }
   105  
   106  // TakesValue returns true of the flag takes a value, otherwise false
   107  func (f *IntSliceFlag) TakesValue() bool {
   108  	return true
   109  }
   110  
   111  // GetUsage returns the usage string for the flag
   112  func (f *IntSliceFlag) GetUsage() string {
   113  	return f.Usage
   114  }
   115  
   116  // GetCategory returns the category for the flag
   117  func (f *IntSliceFlag) GetCategory() string {
   118  	return f.Category
   119  }
   120  
   121  // GetValue returns the flags value as string representation and an empty
   122  // string if the flag takes no value at all.
   123  func (f *IntSliceFlag) GetValue() string {
   124  	var defaultVals []string
   125  	if f.Value != nil && len(f.Value.Value()) > 0 {
   126  		for _, i := range f.Value.Value() {
   127  			defaultVals = append(defaultVals, strconv.Itoa(i))
   128  		}
   129  	}
   130  	return strings.Join(defaultVals, ", ")
   131  }
   132  
   133  // GetDefaultText returns the default text for this flag
   134  func (f *IntSliceFlag) GetDefaultText() string {
   135  	if f.DefaultText != "" {
   136  		return f.DefaultText
   137  	}
   138  	return f.GetValue()
   139  }
   140  
   141  // GetEnvVars returns the env vars for this flag
   142  func (f *IntSliceFlag) GetEnvVars() []string {
   143  	return f.EnvVars
   144  }
   145  
   146  // IsSliceFlag implements DocGenerationSliceFlag.
   147  func (f *IntSliceFlag) IsSliceFlag() bool {
   148  	return true
   149  }
   150  
   151  // Apply populates the flag given the flag set and environment
   152  func (f *IntSliceFlag) Apply(set *flag.FlagSet) error {
   153  	// apply any default
   154  	if f.Destination != nil && f.Value != nil {
   155  		f.Destination.slice = make([]int, len(f.Value.slice))
   156  		copy(f.Destination.slice, f.Value.slice)
   157  	}
   158  
   159  	// resolve setValue (what we will assign to the set)
   160  	var setValue *IntSlice
   161  	switch {
   162  	case f.Destination != nil:
   163  		setValue = f.Destination
   164  	case f.Value != nil:
   165  		setValue = f.Value.clone()
   166  	default:
   167  		setValue = new(IntSlice)
   168  		setValue.WithSeparatorSpec(f.separator)
   169  	}
   170  
   171  	if val, source, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok && val != "" {
   172  		for _, s := range f.separator.flagSplitMultiValues(val) {
   173  			if err := setValue.Set(strings.TrimSpace(s)); err != nil {
   174  				return fmt.Errorf("could not parse %q as int slice value from %s for flag %s: %s", val, source, f.Name, err)
   175  			}
   176  		}
   177  
   178  		// Set this to false so that we reset the slice if we then set values from
   179  		// flags that have already been set by the environment.
   180  		setValue.hasBeenSet = false
   181  		f.HasBeenSet = true
   182  	}
   183  
   184  	for _, name := range f.Names() {
   185  		set.Var(setValue, name, f.Usage)
   186  	}
   187  
   188  	return nil
   189  }
   190  
   191  func (f *IntSliceFlag) WithSeparatorSpec(spec separatorSpec) {
   192  	f.separator = spec
   193  }
   194  
   195  // Get returns the flag’s value in the given Context.
   196  func (f *IntSliceFlag) Get(ctx *Context) []int {
   197  	return ctx.IntSlice(f.Name)
   198  }
   199  
   200  // RunAction executes flag action if set
   201  func (f *IntSliceFlag) RunAction(c *Context) error {
   202  	if f.Action != nil {
   203  		return f.Action(c, c.IntSlice(f.Name))
   204  	}
   205  
   206  	return nil
   207  }
   208  
   209  // IntSlice looks up the value of a local IntSliceFlag, returns
   210  // nil if not found
   211  func (cCtx *Context) IntSlice(name string) []int {
   212  	if fs := cCtx.lookupFlagSet(name); fs != nil {
   213  		return lookupIntSlice(name, fs)
   214  	}
   215  	return nil
   216  }
   217  
   218  func lookupIntSlice(name string, set *flag.FlagSet) []int {
   219  	f := set.Lookup(name)
   220  	if f != nil {
   221  		if slice, ok := unwrapFlagValue(f.Value).(*IntSlice); ok {
   222  			return slice.Value()
   223  		}
   224  	}
   225  	return nil
   226  }
   227  

View as plain text