...

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

View as plain text