...

Source file src/github.com/urfave/cli/v2/altsrc/flag.go

Documentation: github.com/urfave/cli/v2/altsrc

     1  package altsrc
     2  
     3  import (
     4  	"fmt"
     5  	"path/filepath"
     6  	"strconv"
     7  	"syscall"
     8  
     9  	"github.com/urfave/cli/v2"
    10  )
    11  
    12  // FlagInputSourceExtension is an extension interface of cli.Flag that
    13  // allows a value to be set on the existing parsed flags.
    14  type FlagInputSourceExtension interface {
    15  	cli.Flag
    16  	ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
    17  }
    18  
    19  // ApplyInputSourceValues iterates over all provided flags and
    20  // executes ApplyInputSourceValue on flags implementing the
    21  // FlagInputSourceExtension interface to initialize these flags
    22  // to an alternate input source.
    23  func ApplyInputSourceValues(cCtx *cli.Context, inputSourceContext InputSourceContext, flags []cli.Flag) error {
    24  	for _, f := range flags {
    25  		inputSourceExtendedFlag, isType := f.(FlagInputSourceExtension)
    26  		if isType {
    27  			err := inputSourceExtendedFlag.ApplyInputSourceValue(cCtx, inputSourceContext)
    28  			if err != nil {
    29  				return err
    30  			}
    31  		}
    32  	}
    33  
    34  	return nil
    35  }
    36  
    37  // InitInputSource is used to to setup an InputSourceContext on a cli.Command Before method. It will create a new
    38  // input source based on the func provided. If there is no error it will then apply the new input source to any flags
    39  // that are supported by the input source
    40  func InitInputSource(flags []cli.Flag, createInputSource func() (InputSourceContext, error)) cli.BeforeFunc {
    41  	return func(cCtx *cli.Context) error {
    42  		inputSource, err := createInputSource()
    43  		if err != nil {
    44  			return fmt.Errorf("Unable to create input source: inner error: \n'%v'", err.Error())
    45  		}
    46  
    47  		return ApplyInputSourceValues(cCtx, inputSource, flags)
    48  	}
    49  }
    50  
    51  // InitInputSourceWithContext is used to to setup an InputSourceContext on a cli.Command Before method. It will create a new
    52  // input source based on the func provided with potentially using existing cli.Context values to initialize itself. If there is
    53  // no error it will then apply the new input source to any flags that are supported by the input source
    54  func InitInputSourceWithContext(flags []cli.Flag, createInputSource func(cCtx *cli.Context) (InputSourceContext, error)) cli.BeforeFunc {
    55  	return func(cCtx *cli.Context) error {
    56  		inputSource, err := createInputSource(cCtx)
    57  		if err != nil {
    58  			return fmt.Errorf("Unable to create input source with context: inner error: \n'%v'", err.Error())
    59  		}
    60  
    61  		return ApplyInputSourceValues(cCtx, inputSource, flags)
    62  	}
    63  }
    64  
    65  // ApplyInputSourceValue applies a generic value to the flagSet if required
    66  func (f *GenericFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
    67  	if f.set == nil || cCtx.IsSet(f.Name) || isEnvVarSet(f.EnvVars) {
    68  		return nil
    69  	}
    70  	for _, name := range f.GenericFlag.Names() {
    71  		if !isc.isSet(name) {
    72  			continue
    73  		}
    74  		value, err := isc.Generic(name)
    75  		if err != nil {
    76  			return err
    77  		}
    78  		if value == nil {
    79  			continue
    80  		}
    81  		for _, n := range f.Names() {
    82  			if err := f.set.Set(n, value.String()); err != nil {
    83  				return err
    84  			}
    85  		}
    86  	}
    87  
    88  	return nil
    89  }
    90  
    91  // ApplyInputSourceValue applies a StringSlice value to the flagSet if required
    92  func (f *StringSliceFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
    93  	if f.set == nil || cCtx.IsSet(f.Name) || isEnvVarSet(f.EnvVars) {
    94  		return nil
    95  	}
    96  	for _, name := range f.StringSliceFlag.Names() {
    97  		if !isc.isSet(name) {
    98  			continue
    99  		}
   100  		value, err := isc.StringSlice(name)
   101  		if err != nil {
   102  			return err
   103  		}
   104  		if value == nil {
   105  			continue
   106  		}
   107  		var sliceValue = *(cli.NewStringSlice(value...))
   108  		for _, n := range f.Names() {
   109  			underlyingFlag := f.set.Lookup(n)
   110  			if underlyingFlag == nil {
   111  				continue
   112  			}
   113  			underlyingFlag.Value = &sliceValue
   114  			if err := f.set.Set(n, sliceValue.Serialize()); err != nil {
   115  				return err
   116  			}
   117  		}
   118  		if f.Destination != nil {
   119  			_ = f.Destination.Set(sliceValue.Serialize())
   120  		}
   121  	}
   122  	return nil
   123  }
   124  
   125  // ApplyInputSourceValue applies a IntSlice value if required
   126  func (f *IntSliceFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
   127  	if f.set == nil || cCtx.IsSet(f.Name) || isEnvVarSet(f.EnvVars) {
   128  		return nil
   129  	}
   130  	for _, name := range f.IntSliceFlag.Names() {
   131  		if !isc.isSet(name) {
   132  			continue
   133  		}
   134  		value, err := isc.IntSlice(name)
   135  		if err != nil {
   136  			return err
   137  		}
   138  		if value == nil {
   139  			continue
   140  		}
   141  		var sliceValue = *(cli.NewIntSlice(value...))
   142  		for _, n := range f.Names() {
   143  			underlyingFlag := f.set.Lookup(n)
   144  			if underlyingFlag == nil {
   145  				continue
   146  			}
   147  			underlyingFlag.Value = &sliceValue
   148  		}
   149  		if f.Destination != nil {
   150  			if err := f.Destination.Set(sliceValue.Serialize()); err != nil {
   151  				return err
   152  			}
   153  		}
   154  	}
   155  	return nil
   156  }
   157  
   158  // ApplyInputSourceValue applies a Int64Slice value if required
   159  func (f *Int64SliceFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
   160  	if f.set == nil || cCtx.IsSet(f.Name) || isEnvVarSet(f.EnvVars) {
   161  		return nil
   162  	}
   163  	for _, name := range f.Int64SliceFlag.Names() {
   164  		if !isc.isSet(name) {
   165  			continue
   166  		}
   167  		value, err := isc.Int64Slice(name)
   168  		if err != nil {
   169  			return err
   170  		}
   171  		if value == nil {
   172  			continue
   173  		}
   174  		var sliceValue = *(cli.NewInt64Slice(value...))
   175  		for _, n := range f.Names() {
   176  			underlyingFlag := f.set.Lookup(n)
   177  			if underlyingFlag == nil {
   178  				continue
   179  			}
   180  			underlyingFlag.Value = &sliceValue
   181  		}
   182  		if f.Destination != nil {
   183  			if err := f.Destination.Set(sliceValue.Serialize()); err != nil {
   184  				return err
   185  			}
   186  		}
   187  	}
   188  	return nil
   189  }
   190  
   191  // ApplyInputSourceValue applies a Float64Slice value if required
   192  func (f *Float64SliceFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
   193  	if f.set == nil || cCtx.IsSet(f.Name) || isEnvVarSet(f.EnvVars) {
   194  		return nil
   195  	}
   196  	for _, name := range f.Float64SliceFlag.Names() {
   197  		if !isc.isSet(name) {
   198  			continue
   199  		}
   200  		value, err := isc.Float64Slice(name)
   201  		if err != nil {
   202  			return err
   203  		}
   204  		if value == nil {
   205  			continue
   206  		}
   207  		var sliceValue = *(cli.NewFloat64Slice(value...))
   208  		for _, n := range f.Names() {
   209  			underlyingFlag := f.set.Lookup(n)
   210  			if underlyingFlag == nil {
   211  				continue
   212  			}
   213  			underlyingFlag.Value = &sliceValue
   214  		}
   215  		if f.Destination != nil {
   216  			if err := f.Destination.Set(sliceValue.Serialize()); err != nil {
   217  				return err
   218  			}
   219  		}
   220  	}
   221  	return nil
   222  }
   223  
   224  // ApplyInputSourceValue applies a Bool value to the flagSet if required
   225  func (f *BoolFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
   226  	if f.set == nil || cCtx.IsSet(f.Name) || isEnvVarSet(f.EnvVars) {
   227  		return nil
   228  	}
   229  	for _, name := range f.BoolFlag.Names() {
   230  		if !isc.isSet(name) {
   231  			continue
   232  		}
   233  		value, err := isc.Bool(name)
   234  		if err != nil {
   235  			return err
   236  		}
   237  		for _, n := range f.Names() {
   238  			if err := f.set.Set(n, strconv.FormatBool(value)); err != nil {
   239  				return err
   240  			}
   241  		}
   242  	}
   243  	return nil
   244  }
   245  
   246  // ApplyInputSourceValue applies a String value to the flagSet if required
   247  func (f *StringFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
   248  	if f.set == nil || cCtx.IsSet(f.Name) || isEnvVarSet(f.EnvVars) {
   249  		return nil
   250  	}
   251  	for _, name := range f.StringFlag.Names() {
   252  		if !isc.isSet(name) {
   253  			continue
   254  		}
   255  		value, err := isc.String(name)
   256  		if err != nil {
   257  			return err
   258  		}
   259  		for _, n := range f.Names() {
   260  			if err := f.set.Set(n, value); err != nil {
   261  				return err
   262  			}
   263  		}
   264  	}
   265  	return nil
   266  }
   267  
   268  // ApplyInputSourceValue applies a Path value to the flagSet if required
   269  func (f *PathFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
   270  	if f.set == nil || cCtx.IsSet(f.Name) || isEnvVarSet(f.EnvVars) {
   271  		return nil
   272  	}
   273  	for _, name := range f.PathFlag.Names() {
   274  		if !isc.isSet(name) {
   275  			continue
   276  		}
   277  		value, err := isc.String(name)
   278  		if err != nil {
   279  			return err
   280  		}
   281  		if value == "" {
   282  			continue
   283  		}
   284  		for _, n := range f.Names() {
   285  			if !filepath.IsAbs(value) && isc.Source() != "" {
   286  				basePathAbs, err := filepath.Abs(isc.Source())
   287  				if err != nil {
   288  					return err
   289  				}
   290  				value = filepath.Join(filepath.Dir(basePathAbs), value)
   291  			}
   292  			if err := f.set.Set(n, value); err != nil {
   293  				return err
   294  			}
   295  		}
   296  	}
   297  	return nil
   298  }
   299  
   300  // ApplyInputSourceValue applies a int value to the flagSet if required
   301  func (f *IntFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
   302  	if f.set == nil || cCtx.IsSet(f.Name) || isEnvVarSet(f.EnvVars) {
   303  		return nil
   304  	}
   305  	for _, name := range f.IntFlag.Names() {
   306  		if !isc.isSet(name) {
   307  			continue
   308  		}
   309  		value, err := isc.Int(name)
   310  		if err != nil {
   311  			return err
   312  		}
   313  		for _, n := range f.Names() {
   314  			if err := f.set.Set(n, strconv.FormatInt(int64(value), 10)); err != nil {
   315  				return err
   316  			}
   317  		}
   318  	}
   319  	return nil
   320  }
   321  
   322  func (f *Int64Flag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
   323  	if f.set == nil || cCtx.IsSet(f.Name) || isEnvVarSet(f.EnvVars) {
   324  		return nil
   325  	}
   326  	for _, name := range f.Int64Flag.Names() {
   327  		if !isc.isSet(name) {
   328  			continue
   329  		}
   330  		value, err := isc.Int64(name)
   331  		if err != nil {
   332  			return err
   333  		}
   334  		for _, n := range f.Names() {
   335  			if err := f.set.Set(n, strconv.FormatInt(value, 10)); err != nil {
   336  				return err
   337  			}
   338  		}
   339  	}
   340  	return nil
   341  }
   342  
   343  func (f *UintFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
   344  	if f.set == nil || cCtx.IsSet(f.Name) || isEnvVarSet(f.EnvVars) {
   345  		return nil
   346  	}
   347  	for _, name := range f.UintFlag.Names() {
   348  		if !isc.isSet(name) {
   349  			continue
   350  		}
   351  		value, err := isc.Uint(name)
   352  		if err != nil {
   353  			return err
   354  		}
   355  		for _, n := range f.Names() {
   356  			if err := f.set.Set(n, strconv.FormatUint(uint64(value), 10)); err != nil {
   357  				return err
   358  			}
   359  		}
   360  	}
   361  	return nil
   362  }
   363  
   364  func (f *Uint64Flag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
   365  	if f.set == nil || cCtx.IsSet(f.Name) || isEnvVarSet(f.EnvVars) {
   366  		return nil
   367  	}
   368  	for _, name := range f.Uint64Flag.Names() {
   369  		if !isc.isSet(name) {
   370  			continue
   371  		}
   372  		value, err := isc.Uint64(name)
   373  		if err != nil {
   374  			return err
   375  		}
   376  		for _, n := range f.Names() {
   377  			if err := f.set.Set(n, strconv.FormatUint(value, 10)); err != nil {
   378  				return err
   379  			}
   380  		}
   381  	}
   382  	return nil
   383  }
   384  
   385  // ApplyInputSourceValue applies a Duration value to the flagSet if required
   386  func (f *DurationFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
   387  	if f.set == nil || cCtx.IsSet(f.Name) || isEnvVarSet(f.EnvVars) {
   388  		return nil
   389  	}
   390  	for _, name := range f.DurationFlag.Names() {
   391  		if !isc.isSet(name) {
   392  			continue
   393  		}
   394  		value, err := isc.Duration(name)
   395  		if err != nil {
   396  			return err
   397  		}
   398  		for _, n := range f.Names() {
   399  			if err := f.set.Set(n, value.String()); err != nil {
   400  				return err
   401  			}
   402  		}
   403  	}
   404  	return nil
   405  }
   406  
   407  // ApplyInputSourceValue applies a Float64 value to the flagSet if required
   408  func (f *Float64Flag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
   409  	if f.set == nil || cCtx.IsSet(f.Name) || isEnvVarSet(f.EnvVars) {
   410  		return nil
   411  	}
   412  	for _, name := range f.Float64Flag.Names() {
   413  		if !isc.isSet(name) {
   414  			continue
   415  		}
   416  		value, err := isc.Float64(name)
   417  		if err != nil {
   418  			return err
   419  		}
   420  		floatStr := float64ToString(value)
   421  		for _, n := range f.Names() {
   422  			if err := f.set.Set(n, floatStr); err != nil {
   423  				return err
   424  			}
   425  		}
   426  	}
   427  	return nil
   428  }
   429  
   430  func isEnvVarSet(envVars []string) bool {
   431  	for _, envVar := range envVars {
   432  		if _, ok := syscall.Getenv(envVar); ok {
   433  			// TODO: Can't use this for bools as
   434  			// set means that it was true or false based on
   435  			// Bool flag type, should work for other types
   436  			return true
   437  		}
   438  	}
   439  
   440  	return false
   441  }
   442  
   443  func float64ToString(f float64) string {
   444  	return fmt.Sprintf("%v", f)
   445  }
   446  

View as plain text