Merge pull request #1576 from urfave/extern-altsrc
Remove local altsrc and references
This commit is contained in:
commit
02bba4b62e
@ -1,6 +0,0 @@
|
||||
package altsrc
|
||||
|
||||
// defaultInputSource creates a default InputSourceContext.
|
||||
func defaultInputSource() (InputSourceContext, error) {
|
||||
return &MapInputSource{file: "", valueMap: map[interface{}]interface{}{}}, nil
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
# NOTE: this file is used by the tool defined in
|
||||
# ./cmd/urfave-cli-genflags/main.go which uses the
|
||||
# `Spec` type that maps to this file structure.
|
||||
flag_types:
|
||||
Bool:
|
||||
Duration:
|
||||
Float64:
|
||||
Generic:
|
||||
Int64:
|
||||
Int:
|
||||
IntSlice:
|
||||
Int64Slice:
|
||||
Float64Slice:
|
||||
String:
|
||||
Path:
|
||||
StringSlice:
|
||||
Uint64:
|
||||
Uint:
|
328
altsrc/flag.go
328
altsrc/flag.go
@ -1,328 +0,0 @@
|
||||
package altsrc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// FlagInputSourceExtension is an extension interface of cli.Flag that
|
||||
// allows a value to be set on the existing parsed flags.
|
||||
type FlagInputSourceExtension interface {
|
||||
cli.Flag
|
||||
ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
|
||||
}
|
||||
|
||||
// ApplyInputSourceValues iterates over all provided flags and
|
||||
// executes ApplyInputSourceValue on flags implementing the
|
||||
// FlagInputSourceExtension interface to initialize these flags
|
||||
// to an alternate input source.
|
||||
func ApplyInputSourceValues(cCtx *cli.Context, inputSourceContext InputSourceContext, flags []cli.Flag) error {
|
||||
for _, f := range flags {
|
||||
inputSourceExtendedFlag, isType := f.(FlagInputSourceExtension)
|
||||
if isType {
|
||||
err := inputSourceExtendedFlag.ApplyInputSourceValue(cCtx, inputSourceContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitInputSource is used to to setup an InputSourceContext on a cli.Command Before method. It will create a new
|
||||
// input source based on the func provided. If there is no error it will then apply the new input source to any flags
|
||||
// that are supported by the input source
|
||||
func InitInputSource(flags []cli.Flag, createInputSource func() (InputSourceContext, error)) cli.BeforeFunc {
|
||||
return func(cCtx *cli.Context) error {
|
||||
inputSource, err := createInputSource()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to create input source: inner error: \n'%v'", err.Error())
|
||||
}
|
||||
|
||||
return ApplyInputSourceValues(cCtx, inputSource, flags)
|
||||
}
|
||||
}
|
||||
|
||||
// InitInputSourceWithContext is used to to setup an InputSourceContext on a cli.Command Before method. It will create a new
|
||||
// input source based on the func provided with potentially using existing cli.Context values to initialize itself. If there is
|
||||
// no error it will then apply the new input source to any flags that are supported by the input source
|
||||
func InitInputSourceWithContext(flags []cli.Flag, createInputSource func(cCtx *cli.Context) (InputSourceContext, error)) cli.BeforeFunc {
|
||||
return func(cCtx *cli.Context) error {
|
||||
inputSource, err := createInputSource(cCtx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to create input source with context: inner error: \n'%v'", err.Error())
|
||||
}
|
||||
|
||||
return ApplyInputSourceValues(cCtx, inputSource, flags)
|
||||
}
|
||||
}
|
||||
|
||||
// ApplyInputSourceValue applies a generic value to the flagSet if required
|
||||
func (f *GenericFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
|
||||
if f.set == nil || cCtx.IsSet(f.Name) || isEnvVarSet(f.EnvVars) {
|
||||
return nil
|
||||
}
|
||||
for _, name := range f.GenericFlag.Names() {
|
||||
if !isc.isSet(name) {
|
||||
continue
|
||||
}
|
||||
value, err := isc.Generic(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if value == nil {
|
||||
continue
|
||||
}
|
||||
for _, n := range f.Names() {
|
||||
_ = f.set.Set(n, value.String())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApplyInputSourceValue applies a StringSlice value to the flagSet if required
|
||||
func (f *StringSliceFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
|
||||
if f.set == nil || cCtx.IsSet(f.Name) || isEnvVarSet(f.EnvVars) {
|
||||
return nil
|
||||
}
|
||||
for _, name := range f.StringSliceFlag.Names() {
|
||||
if !isc.isSet(name) {
|
||||
continue
|
||||
}
|
||||
value, err := isc.StringSlice(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if value == nil {
|
||||
continue
|
||||
}
|
||||
var sliceValue = *(cli.NewStringSlice(value...))
|
||||
for _, n := range f.Names() {
|
||||
underlyingFlag := f.set.Lookup(n)
|
||||
if underlyingFlag == nil {
|
||||
continue
|
||||
}
|
||||
underlyingFlag.Value = &sliceValue
|
||||
}
|
||||
if f.Destination != nil {
|
||||
f.Destination.Set(sliceValue.Serialize())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApplyInputSourceValue applies a IntSlice value if required
|
||||
func (f *IntSliceFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
|
||||
if f.set == nil || cCtx.IsSet(f.Name) || isEnvVarSet(f.EnvVars) {
|
||||
return nil
|
||||
}
|
||||
for _, name := range f.IntSliceFlag.Names() {
|
||||
if !isc.isSet(name) {
|
||||
continue
|
||||
}
|
||||
value, err := isc.IntSlice(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if value == nil {
|
||||
continue
|
||||
}
|
||||
var sliceValue = *(cli.NewIntSlice(value...))
|
||||
for _, n := range f.Names() {
|
||||
underlyingFlag := f.set.Lookup(n)
|
||||
if underlyingFlag == nil {
|
||||
continue
|
||||
}
|
||||
underlyingFlag.Value = &sliceValue
|
||||
}
|
||||
if f.Destination != nil {
|
||||
f.Destination.Set(sliceValue.Serialize())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApplyInputSourceValue applies a Int64Slice value if required
|
||||
func (f *Int64SliceFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
|
||||
if f.set == nil || cCtx.IsSet(f.Name) || isEnvVarSet(f.EnvVars) {
|
||||
return nil
|
||||
}
|
||||
for _, name := range f.Int64SliceFlag.Names() {
|
||||
if !isc.isSet(name) {
|
||||
continue
|
||||
}
|
||||
value, err := isc.Int64Slice(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if value == nil {
|
||||
continue
|
||||
}
|
||||
var sliceValue = *(cli.NewInt64Slice(value...))
|
||||
for _, n := range f.Names() {
|
||||
underlyingFlag := f.set.Lookup(n)
|
||||
if underlyingFlag == nil {
|
||||
continue
|
||||
}
|
||||
underlyingFlag.Value = &sliceValue
|
||||
}
|
||||
if f.Destination != nil {
|
||||
f.Destination.Set(sliceValue.Serialize())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApplyInputSourceValue applies a Bool value to the flagSet if required
|
||||
func (f *BoolFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
|
||||
if f.set == nil || cCtx.IsSet(f.Name) || isEnvVarSet(f.EnvVars) {
|
||||
return nil
|
||||
}
|
||||
for _, name := range f.BoolFlag.Names() {
|
||||
if !isc.isSet(name) {
|
||||
continue
|
||||
}
|
||||
value, err := isc.Bool(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, n := range f.Names() {
|
||||
_ = f.set.Set(n, strconv.FormatBool(value))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApplyInputSourceValue applies a String value to the flagSet if required
|
||||
func (f *StringFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
|
||||
if f.set == nil || cCtx.IsSet(f.Name) || isEnvVarSet(f.EnvVars) {
|
||||
return nil
|
||||
}
|
||||
for _, name := range f.StringFlag.Names() {
|
||||
if !isc.isSet(name) {
|
||||
continue
|
||||
}
|
||||
value, err := isc.String(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, n := range f.Names() {
|
||||
_ = f.set.Set(n, value)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApplyInputSourceValue applies a Path value to the flagSet if required
|
||||
func (f *PathFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
|
||||
if f.set == nil || cCtx.IsSet(f.Name) || isEnvVarSet(f.EnvVars) {
|
||||
return nil
|
||||
}
|
||||
for _, name := range f.PathFlag.Names() {
|
||||
if !isc.isSet(name) {
|
||||
continue
|
||||
}
|
||||
value, err := isc.String(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if value == "" {
|
||||
continue
|
||||
}
|
||||
for _, n := range f.Names() {
|
||||
if !filepath.IsAbs(value) && isc.Source() != "" {
|
||||
basePathAbs, err := filepath.Abs(isc.Source())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
value = filepath.Join(filepath.Dir(basePathAbs), value)
|
||||
}
|
||||
_ = f.set.Set(n, value)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApplyInputSourceValue applies a int value to the flagSet if required
|
||||
func (f *IntFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
|
||||
if f.set == nil || cCtx.IsSet(f.Name) || isEnvVarSet(f.EnvVars) {
|
||||
return nil
|
||||
}
|
||||
for _, name := range f.IntFlag.Names() {
|
||||
if !isc.isSet(name) {
|
||||
continue
|
||||
}
|
||||
value, err := isc.Int(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, n := range f.Names() {
|
||||
_ = f.set.Set(n, strconv.FormatInt(int64(value), 10))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApplyInputSourceValue applies a Duration value to the flagSet if required
|
||||
func (f *DurationFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
|
||||
if f.set == nil || cCtx.IsSet(f.Name) || isEnvVarSet(f.EnvVars) {
|
||||
return nil
|
||||
}
|
||||
for _, name := range f.DurationFlag.Names() {
|
||||
if !isc.isSet(name) {
|
||||
continue
|
||||
}
|
||||
value, err := isc.Duration(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, n := range f.Names() {
|
||||
_ = f.set.Set(n, value.String())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApplyInputSourceValue applies a Float64 value to the flagSet if required
|
||||
func (f *Float64Flag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error {
|
||||
if f.set == nil || cCtx.IsSet(f.Name) || isEnvVarSet(f.EnvVars) {
|
||||
return nil
|
||||
}
|
||||
for _, name := range f.Float64Flag.Names() {
|
||||
if !isc.isSet(name) {
|
||||
continue
|
||||
}
|
||||
value, err := isc.Float64(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
floatStr := float64ToString(value)
|
||||
for _, n := range f.Names() {
|
||||
_ = f.set.Set(n, floatStr)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isEnvVarSet(envVars []string) bool {
|
||||
for _, envVar := range envVars {
|
||||
if _, ok := syscall.Getenv(envVar); ok {
|
||||
// TODO: Can't use this for bools as
|
||||
// set means that it was true or false based on
|
||||
// Bool flag type, should work for other types
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func float64ToString(f float64) string {
|
||||
return fmt.Sprintf("%v", f)
|
||||
}
|
@ -1,277 +0,0 @@
|
||||
// WARNING: this file is generated. DO NOT EDIT
|
||||
|
||||
package altsrc
|
||||
|
||||
import (
|
||||
"flag"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// BoolFlag is the flag type that wraps cli.BoolFlag to allow
|
||||
// for other values to be specified
|
||||
type BoolFlag struct {
|
||||
*cli.BoolFlag
|
||||
set *flag.FlagSet
|
||||
}
|
||||
|
||||
// NewBoolFlag creates a new BoolFlag
|
||||
func NewBoolFlag(fl *cli.BoolFlag) *BoolFlag {
|
||||
return &BoolFlag{BoolFlag: fl, set: nil}
|
||||
}
|
||||
|
||||
// Apply saves the flagSet for later usage calls, then calls
|
||||
// the wrapped BoolFlag.Apply
|
||||
func (f *BoolFlag) Apply(set *flag.FlagSet) error {
|
||||
f.set = set
|
||||
return f.BoolFlag.Apply(set)
|
||||
}
|
||||
|
||||
// DurationFlag is the flag type that wraps cli.DurationFlag to allow
|
||||
// for other values to be specified
|
||||
type DurationFlag struct {
|
||||
*cli.DurationFlag
|
||||
set *flag.FlagSet
|
||||
}
|
||||
|
||||
// NewDurationFlag creates a new DurationFlag
|
||||
func NewDurationFlag(fl *cli.DurationFlag) *DurationFlag {
|
||||
return &DurationFlag{DurationFlag: fl, set: nil}
|
||||
}
|
||||
|
||||
// Apply saves the flagSet for later usage calls, then calls
|
||||
// the wrapped DurationFlag.Apply
|
||||
func (f *DurationFlag) Apply(set *flag.FlagSet) error {
|
||||
f.set = set
|
||||
return f.DurationFlag.Apply(set)
|
||||
}
|
||||
|
||||
// Float64Flag is the flag type that wraps cli.Float64Flag to allow
|
||||
// for other values to be specified
|
||||
type Float64Flag struct {
|
||||
*cli.Float64Flag
|
||||
set *flag.FlagSet
|
||||
}
|
||||
|
||||
// NewFloat64Flag creates a new Float64Flag
|
||||
func NewFloat64Flag(fl *cli.Float64Flag) *Float64Flag {
|
||||
return &Float64Flag{Float64Flag: fl, set: nil}
|
||||
}
|
||||
|
||||
// Apply saves the flagSet for later usage calls, then calls
|
||||
// the wrapped Float64Flag.Apply
|
||||
func (f *Float64Flag) Apply(set *flag.FlagSet) error {
|
||||
f.set = set
|
||||
return f.Float64Flag.Apply(set)
|
||||
}
|
||||
|
||||
// Float64SliceFlag is the flag type that wraps cli.Float64SliceFlag to allow
|
||||
// for other values to be specified
|
||||
type Float64SliceFlag struct {
|
||||
*cli.Float64SliceFlag
|
||||
set *flag.FlagSet
|
||||
}
|
||||
|
||||
// NewFloat64SliceFlag creates a new Float64SliceFlag
|
||||
func NewFloat64SliceFlag(fl *cli.Float64SliceFlag) *Float64SliceFlag {
|
||||
return &Float64SliceFlag{Float64SliceFlag: fl, set: nil}
|
||||
}
|
||||
|
||||
// Apply saves the flagSet for later usage calls, then calls
|
||||
// the wrapped Float64SliceFlag.Apply
|
||||
func (f *Float64SliceFlag) Apply(set *flag.FlagSet) error {
|
||||
f.set = set
|
||||
return f.Float64SliceFlag.Apply(set)
|
||||
}
|
||||
|
||||
// GenericFlag is the flag type that wraps cli.GenericFlag to allow
|
||||
// for other values to be specified
|
||||
type GenericFlag struct {
|
||||
*cli.GenericFlag
|
||||
set *flag.FlagSet
|
||||
}
|
||||
|
||||
// NewGenericFlag creates a new GenericFlag
|
||||
func NewGenericFlag(fl *cli.GenericFlag) *GenericFlag {
|
||||
return &GenericFlag{GenericFlag: fl, set: nil}
|
||||
}
|
||||
|
||||
// Apply saves the flagSet for later usage calls, then calls
|
||||
// the wrapped GenericFlag.Apply
|
||||
func (f *GenericFlag) Apply(set *flag.FlagSet) error {
|
||||
f.set = set
|
||||
return f.GenericFlag.Apply(set)
|
||||
}
|
||||
|
||||
// IntFlag is the flag type that wraps cli.IntFlag to allow
|
||||
// for other values to be specified
|
||||
type IntFlag struct {
|
||||
*cli.IntFlag
|
||||
set *flag.FlagSet
|
||||
}
|
||||
|
||||
// NewIntFlag creates a new IntFlag
|
||||
func NewIntFlag(fl *cli.IntFlag) *IntFlag {
|
||||
return &IntFlag{IntFlag: fl, set: nil}
|
||||
}
|
||||
|
||||
// Apply saves the flagSet for later usage calls, then calls
|
||||
// the wrapped IntFlag.Apply
|
||||
func (f *IntFlag) Apply(set *flag.FlagSet) error {
|
||||
f.set = set
|
||||
return f.IntFlag.Apply(set)
|
||||
}
|
||||
|
||||
// Int64Flag is the flag type that wraps cli.Int64Flag to allow
|
||||
// for other values to be specified
|
||||
type Int64Flag struct {
|
||||
*cli.Int64Flag
|
||||
set *flag.FlagSet
|
||||
}
|
||||
|
||||
// NewInt64Flag creates a new Int64Flag
|
||||
func NewInt64Flag(fl *cli.Int64Flag) *Int64Flag {
|
||||
return &Int64Flag{Int64Flag: fl, set: nil}
|
||||
}
|
||||
|
||||
// Apply saves the flagSet for later usage calls, then calls
|
||||
// the wrapped Int64Flag.Apply
|
||||
func (f *Int64Flag) Apply(set *flag.FlagSet) error {
|
||||
f.set = set
|
||||
return f.Int64Flag.Apply(set)
|
||||
}
|
||||
|
||||
// Int64SliceFlag is the flag type that wraps cli.Int64SliceFlag to allow
|
||||
// for other values to be specified
|
||||
type Int64SliceFlag struct {
|
||||
*cli.Int64SliceFlag
|
||||
set *flag.FlagSet
|
||||
}
|
||||
|
||||
// NewInt64SliceFlag creates a new Int64SliceFlag
|
||||
func NewInt64SliceFlag(fl *cli.Int64SliceFlag) *Int64SliceFlag {
|
||||
return &Int64SliceFlag{Int64SliceFlag: fl, set: nil}
|
||||
}
|
||||
|
||||
// Apply saves the flagSet for later usage calls, then calls
|
||||
// the wrapped Int64SliceFlag.Apply
|
||||
func (f *Int64SliceFlag) Apply(set *flag.FlagSet) error {
|
||||
f.set = set
|
||||
return f.Int64SliceFlag.Apply(set)
|
||||
}
|
||||
|
||||
// IntSliceFlag is the flag type that wraps cli.IntSliceFlag to allow
|
||||
// for other values to be specified
|
||||
type IntSliceFlag struct {
|
||||
*cli.IntSliceFlag
|
||||
set *flag.FlagSet
|
||||
}
|
||||
|
||||
// NewIntSliceFlag creates a new IntSliceFlag
|
||||
func NewIntSliceFlag(fl *cli.IntSliceFlag) *IntSliceFlag {
|
||||
return &IntSliceFlag{IntSliceFlag: fl, set: nil}
|
||||
}
|
||||
|
||||
// Apply saves the flagSet for later usage calls, then calls
|
||||
// the wrapped IntSliceFlag.Apply
|
||||
func (f *IntSliceFlag) Apply(set *flag.FlagSet) error {
|
||||
f.set = set
|
||||
return f.IntSliceFlag.Apply(set)
|
||||
}
|
||||
|
||||
// PathFlag is the flag type that wraps cli.PathFlag to allow
|
||||
// for other values to be specified
|
||||
type PathFlag struct {
|
||||
*cli.PathFlag
|
||||
set *flag.FlagSet
|
||||
}
|
||||
|
||||
// NewPathFlag creates a new PathFlag
|
||||
func NewPathFlag(fl *cli.PathFlag) *PathFlag {
|
||||
return &PathFlag{PathFlag: fl, set: nil}
|
||||
}
|
||||
|
||||
// Apply saves the flagSet for later usage calls, then calls
|
||||
// the wrapped PathFlag.Apply
|
||||
func (f *PathFlag) Apply(set *flag.FlagSet) error {
|
||||
f.set = set
|
||||
return f.PathFlag.Apply(set)
|
||||
}
|
||||
|
||||
// StringFlag is the flag type that wraps cli.StringFlag to allow
|
||||
// for other values to be specified
|
||||
type StringFlag struct {
|
||||
*cli.StringFlag
|
||||
set *flag.FlagSet
|
||||
}
|
||||
|
||||
// NewStringFlag creates a new StringFlag
|
||||
func NewStringFlag(fl *cli.StringFlag) *StringFlag {
|
||||
return &StringFlag{StringFlag: fl, set: nil}
|
||||
}
|
||||
|
||||
// Apply saves the flagSet for later usage calls, then calls
|
||||
// the wrapped StringFlag.Apply
|
||||
func (f *StringFlag) Apply(set *flag.FlagSet) error {
|
||||
f.set = set
|
||||
return f.StringFlag.Apply(set)
|
||||
}
|
||||
|
||||
// StringSliceFlag is the flag type that wraps cli.StringSliceFlag to allow
|
||||
// for other values to be specified
|
||||
type StringSliceFlag struct {
|
||||
*cli.StringSliceFlag
|
||||
set *flag.FlagSet
|
||||
}
|
||||
|
||||
// NewStringSliceFlag creates a new StringSliceFlag
|
||||
func NewStringSliceFlag(fl *cli.StringSliceFlag) *StringSliceFlag {
|
||||
return &StringSliceFlag{StringSliceFlag: fl, set: nil}
|
||||
}
|
||||
|
||||
// Apply saves the flagSet for later usage calls, then calls
|
||||
// the wrapped StringSliceFlag.Apply
|
||||
func (f *StringSliceFlag) Apply(set *flag.FlagSet) error {
|
||||
f.set = set
|
||||
return f.StringSliceFlag.Apply(set)
|
||||
}
|
||||
|
||||
// UintFlag is the flag type that wraps cli.UintFlag to allow
|
||||
// for other values to be specified
|
||||
type UintFlag struct {
|
||||
*cli.UintFlag
|
||||
set *flag.FlagSet
|
||||
}
|
||||
|
||||
// NewUintFlag creates a new UintFlag
|
||||
func NewUintFlag(fl *cli.UintFlag) *UintFlag {
|
||||
return &UintFlag{UintFlag: fl, set: nil}
|
||||
}
|
||||
|
||||
// Apply saves the flagSet for later usage calls, then calls
|
||||
// the wrapped UintFlag.Apply
|
||||
func (f *UintFlag) Apply(set *flag.FlagSet) error {
|
||||
f.set = set
|
||||
return f.UintFlag.Apply(set)
|
||||
}
|
||||
|
||||
// Uint64Flag is the flag type that wraps cli.Uint64Flag to allow
|
||||
// for other values to be specified
|
||||
type Uint64Flag struct {
|
||||
*cli.Uint64Flag
|
||||
set *flag.FlagSet
|
||||
}
|
||||
|
||||
// NewUint64Flag creates a new Uint64Flag
|
||||
func NewUint64Flag(fl *cli.Uint64Flag) *Uint64Flag {
|
||||
return &Uint64Flag{Uint64Flag: fl, set: nil}
|
||||
}
|
||||
|
||||
// Apply saves the flagSet for later usage calls, then calls
|
||||
// the wrapped Uint64Flag.Apply
|
||||
func (f *Uint64Flag) Apply(set *flag.FlagSet) error {
|
||||
f.set = set
|
||||
return f.Uint64Flag.Apply(set)
|
||||
}
|
||||
|
||||
// vim:ro
|
@ -1,743 +0,0 @@
|
||||
package altsrc
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
type testApplyInputSource struct {
|
||||
Flag FlagInputSourceExtension
|
||||
FlagName string
|
||||
FlagSetName string
|
||||
Expected string
|
||||
ContextValueString string
|
||||
ContextValue flag.Value
|
||||
EnvVarValue string
|
||||
EnvVarName string
|
||||
SourcePath string
|
||||
MapValue interface{}
|
||||
}
|
||||
|
||||
type racyInputSource struct {
|
||||
*MapInputSource
|
||||
}
|
||||
|
||||
func (ris *racyInputSource) isSet(name string) bool {
|
||||
if _, ok := ris.MapInputSource.valueMap[name]; ok {
|
||||
ris.MapInputSource.valueMap[name] = bogus{0}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func TestGenericApplyInputSourceValue_Alias(t *testing.T) {
|
||||
v := &Parser{"abc", "def"}
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewGenericFlag(&cli.GenericFlag{Name: "test", Aliases: []string{"test_alias"}, Value: &Parser{}}),
|
||||
FlagName: "test_alias",
|
||||
MapValue: v,
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, v, c.Generic("test_alias"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, v, c.Generic("test_alias"))
|
||||
}
|
||||
|
||||
func TestGenericApplyInputSourceValue(t *testing.T) {
|
||||
v := &Parser{"abc", "def"}
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewGenericFlag(&cli.GenericFlag{Name: "test", Value: &Parser{}}),
|
||||
FlagName: "test",
|
||||
MapValue: v,
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, v, c.Generic("test"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, v, c.Generic("test"))
|
||||
}
|
||||
|
||||
func TestGenericApplyInputSourceMethodContextSet(t *testing.T) {
|
||||
p := &Parser{"abc", "def"}
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewGenericFlag(&cli.GenericFlag{Name: "test", Value: &Parser{}}),
|
||||
FlagName: "test",
|
||||
MapValue: &Parser{"efg", "hig"},
|
||||
ContextValueString: p.String(),
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, p, c.Generic("test"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, p, c.Generic("test"))
|
||||
}
|
||||
|
||||
func TestGenericApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewGenericFlag(&cli.GenericFlag{
|
||||
Name: "test",
|
||||
Value: &Parser{},
|
||||
EnvVars: []string{"TEST"},
|
||||
}),
|
||||
FlagName: "test",
|
||||
MapValue: &Parser{"efg", "hij"},
|
||||
EnvVarName: "TEST",
|
||||
EnvVarValue: "abc,def",
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, &Parser{"abc", "def"}, c.Generic("test"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, &Parser{"abc", "def"}, c.Generic("test"))
|
||||
}
|
||||
|
||||
func TestStringSliceApplyInputSourceValue_Alias(t *testing.T) {
|
||||
dest := cli.NewStringSlice()
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewStringSliceFlag(&cli.StringSliceFlag{Name: "test", Aliases: []string{"test_alias"}, Destination: dest}),
|
||||
FlagName: "test_alias",
|
||||
MapValue: []interface{}{"hello", "world"},
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, c.StringSlice("test_alias"), []string{"hello", "world"})
|
||||
expect(t, dest.Value(), []string{"hello", "world"})
|
||||
|
||||
// reset dest
|
||||
dest = cli.NewStringSlice()
|
||||
tis = testApplyInputSource{
|
||||
Flag: NewStringSliceFlag(&cli.StringSliceFlag{Name: "test", Aliases: []string{"test_alias"}, Destination: dest}),
|
||||
FlagName: "test_alias",
|
||||
MapValue: []interface{}{"hello", "world"},
|
||||
}
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, c.StringSlice("test_alias"), []string{"hello", "world"})
|
||||
refute(t, dest.Value(), []string{"hello", "world"})
|
||||
}
|
||||
|
||||
func TestStringSliceApplyInputSourceValue(t *testing.T) {
|
||||
dest := cli.NewStringSlice()
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewStringSliceFlag(&cli.StringSliceFlag{Name: "test", Destination: dest}),
|
||||
FlagName: "test",
|
||||
MapValue: []interface{}{"hello", "world"},
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, c.StringSlice("test"), []string{"hello", "world"})
|
||||
expect(t, dest.Value(), []string{"hello", "world"})
|
||||
|
||||
// reset dest
|
||||
dest = cli.NewStringSlice()
|
||||
tis = testApplyInputSource{
|
||||
Flag: NewStringSliceFlag(&cli.StringSliceFlag{Name: "test", Destination: dest}),
|
||||
FlagName: "test",
|
||||
MapValue: []interface{}{"hello", "world"},
|
||||
}
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, c.StringSlice("test"), []string{"hello", "world"})
|
||||
refute(t, dest.Value(), []string{"hello", "world"})
|
||||
}
|
||||
|
||||
func TestStringSliceApplyInputSourceMethodContextSet(t *testing.T) {
|
||||
dest := cli.NewStringSlice()
|
||||
c := runTest(t, testApplyInputSource{
|
||||
Flag: NewStringSliceFlag(&cli.StringSliceFlag{Name: "test", Destination: dest}),
|
||||
FlagName: "test",
|
||||
MapValue: []interface{}{"hello", "world"},
|
||||
ContextValueString: "ohno",
|
||||
})
|
||||
expect(t, c.StringSlice("test"), []string{"ohno"})
|
||||
expect(t, dest.Value(), []string{"ohno"})
|
||||
}
|
||||
|
||||
func TestStringSliceApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewStringSliceFlag(&cli.StringSliceFlag{Name: "test", EnvVars: []string{"TEST"}}),
|
||||
FlagName: "test",
|
||||
MapValue: []interface{}{"hello", "world"},
|
||||
EnvVarName: "TEST",
|
||||
EnvVarValue: "oh,no",
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, c.StringSlice("test"), []string{"oh", "no"})
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, c.StringSlice("test"), []string{"oh", "no"})
|
||||
}
|
||||
|
||||
func TestIntSliceApplyInputSourceValue_Alias(t *testing.T) {
|
||||
dest := cli.NewIntSlice()
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewIntSliceFlag(&cli.IntSliceFlag{Name: "test", Aliases: []string{"test_alias"}, Destination: dest}),
|
||||
FlagName: "test_alias",
|
||||
MapValue: []interface{}{1, 2},
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, c.IntSlice("test_alias"), []int{1, 2})
|
||||
expect(t, dest.Value(), []int{1, 2})
|
||||
|
||||
dest = cli.NewIntSlice()
|
||||
tis = testApplyInputSource{
|
||||
Flag: NewIntSliceFlag(&cli.IntSliceFlag{Name: "test", Aliases: []string{"test_alias"}, Destination: dest}),
|
||||
FlagName: "test_alias",
|
||||
MapValue: []interface{}{1, 2},
|
||||
}
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, c.IntSlice("test_alias"), []int{1, 2})
|
||||
refute(t, dest.Value(), []int{1, 2})
|
||||
}
|
||||
|
||||
func TestIntSliceApplyInputSourceValue(t *testing.T) {
|
||||
dest := cli.NewIntSlice()
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewIntSliceFlag(&cli.IntSliceFlag{Name: "test", Destination: dest}),
|
||||
FlagName: "test",
|
||||
MapValue: []interface{}{1, 2},
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, c.IntSlice("test"), []int{1, 2})
|
||||
expect(t, dest.Value(), []int{1, 2})
|
||||
|
||||
// reset dest
|
||||
dest = cli.NewIntSlice()
|
||||
tis = testApplyInputSource{
|
||||
Flag: NewIntSliceFlag(&cli.IntSliceFlag{Name: "test", Destination: dest}),
|
||||
FlagName: "test",
|
||||
MapValue: []interface{}{1, 2},
|
||||
}
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, c.IntSlice("test"), []int{1, 2})
|
||||
refute(t, dest.Value(), []int{1, 2})
|
||||
}
|
||||
|
||||
func TestIntSliceApplyInputSourceMethodContextSet(t *testing.T) {
|
||||
dest := cli.NewIntSlice()
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewIntSliceFlag(&cli.IntSliceFlag{Name: "test", Destination: dest}),
|
||||
FlagName: "test",
|
||||
MapValue: []interface{}{1, 2},
|
||||
ContextValueString: "3",
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, c.IntSlice("test"), []int{3})
|
||||
expect(t, dest.Value(), []int{3})
|
||||
|
||||
// reset dest
|
||||
dest = cli.NewIntSlice()
|
||||
tis = testApplyInputSource{
|
||||
Flag: NewIntSliceFlag(&cli.IntSliceFlag{Name: "test", Destination: dest}),
|
||||
FlagName: "test",
|
||||
MapValue: []interface{}{1, 2},
|
||||
ContextValueString: "3",
|
||||
}
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, c.IntSlice("test"), []int{3})
|
||||
refute(t, dest.Value(), []int{3})
|
||||
}
|
||||
|
||||
func TestIntSliceApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewIntSliceFlag(&cli.IntSliceFlag{Name: "test", EnvVars: []string{"TEST"}}),
|
||||
FlagName: "test",
|
||||
MapValue: []interface{}{1, 2},
|
||||
EnvVarName: "TEST",
|
||||
EnvVarValue: "3,4",
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, c.IntSlice("test"), []int{3, 4})
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, c.IntSlice("test"), []int{3, 4})
|
||||
}
|
||||
|
||||
func TestInt64SliceFlagApplyInputSourceValue(t *testing.T) {
|
||||
dest := cli.NewInt64Slice()
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewInt64SliceFlag(&cli.Int64SliceFlag{Name: "test", Destination: dest}),
|
||||
FlagName: "test",
|
||||
MapValue: []interface{}{int64(1), int64(2)},
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, c.Int64Slice("test"), []int64{1, 2})
|
||||
expect(t, dest.Value(), []int64{1, 2})
|
||||
|
||||
// reset dest
|
||||
dest = cli.NewInt64Slice()
|
||||
tis = testApplyInputSource{
|
||||
Flag: NewInt64SliceFlag(&cli.Int64SliceFlag{Name: "test", Destination: dest}),
|
||||
FlagName: "test",
|
||||
MapValue: []interface{}{int64(1), int64(2)},
|
||||
}
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, c.IntSlice("test"), []int64{1, 2})
|
||||
refute(t, dest.Value(), []int64{1, 2})
|
||||
}
|
||||
|
||||
func TestBoolApplyInputSourceMethodSet(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewBoolFlag(&cli.BoolFlag{Name: "test"}),
|
||||
FlagName: "test",
|
||||
MapValue: true,
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, true, c.Bool("test"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, true, c.Bool("test"))
|
||||
}
|
||||
|
||||
func TestBoolApplyInputSourceMethodSet_Alias(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewBoolFlag(&cli.BoolFlag{Name: "test", Aliases: []string{"test_alias"}}),
|
||||
FlagName: "test_alias",
|
||||
MapValue: true,
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, true, c.Bool("test_alias"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, true, c.Bool("test_alias"))
|
||||
}
|
||||
|
||||
func TestBoolApplyInputSourceMethodContextSet(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewBoolFlag(&cli.BoolFlag{Name: "test"}),
|
||||
FlagName: "test",
|
||||
MapValue: false,
|
||||
ContextValueString: "true",
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, true, c.Bool("test"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, true, c.Bool("test"))
|
||||
}
|
||||
|
||||
func TestBoolApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewBoolFlag(&cli.BoolFlag{Name: "test", EnvVars: []string{"TEST"}}),
|
||||
FlagName: "test",
|
||||
MapValue: false,
|
||||
EnvVarName: "TEST",
|
||||
EnvVarValue: "true",
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, true, c.Bool("test"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, true, c.Bool("test"))
|
||||
}
|
||||
|
||||
func TestStringApplyInputSourceMethodSet_Alias(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewStringFlag(&cli.StringFlag{Name: "test", Aliases: []string{"test_alias"}}),
|
||||
FlagName: "test_alias",
|
||||
MapValue: "hello",
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, "hello", c.String("test_alias"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, "hello", c.String("test_alias"))
|
||||
}
|
||||
|
||||
func TestStringApplyInputSourceMethodSet(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewStringFlag(&cli.StringFlag{Name: "test"}),
|
||||
FlagName: "test",
|
||||
MapValue: "hello",
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, "hello", c.String("test"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, "hello", c.String("test"))
|
||||
}
|
||||
|
||||
func TestStringApplyInputSourceMethodContextSet(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewStringFlag(&cli.StringFlag{Name: "test"}),
|
||||
FlagName: "test",
|
||||
MapValue: "hello",
|
||||
ContextValueString: "goodbye",
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, "goodbye", c.String("test"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, "goodbye", c.String("test"))
|
||||
}
|
||||
|
||||
func TestStringApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewStringFlag(&cli.StringFlag{Name: "test", EnvVars: []string{"TEST"}}),
|
||||
FlagName: "test",
|
||||
MapValue: "hello",
|
||||
EnvVarName: "TEST",
|
||||
EnvVarValue: "goodbye",
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, "goodbye", c.String("test"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, "goodbye", c.String("test"))
|
||||
}
|
||||
|
||||
func TestPathApplyInputSourceMethodSet_Alias(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewPathFlag(&cli.PathFlag{Name: "test", Aliases: []string{"test_alias"}}),
|
||||
FlagName: "test_alias",
|
||||
MapValue: "hello",
|
||||
SourcePath: "/path/to/source/file",
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
|
||||
expected := "/path/to/source/hello"
|
||||
if runtime.GOOS == "windows" {
|
||||
var err error
|
||||
// Prepend the corresponding drive letter (or UNC path?), and change
|
||||
// to windows-style path:
|
||||
expected, err = filepath.Abs(expected)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
expect(t, expected, c.String("test_alias"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, expected, c.String("test_alias"))
|
||||
}
|
||||
|
||||
func TestPathApplyInputSourceMethodSet(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewPathFlag(&cli.PathFlag{Name: "test"}),
|
||||
FlagName: "test",
|
||||
MapValue: "hello",
|
||||
SourcePath: "/path/to/source/file",
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
|
||||
expected := "/path/to/source/hello"
|
||||
if runtime.GOOS == "windows" {
|
||||
var err error
|
||||
// Prepend the corresponding drive letter (or UNC path?), and change
|
||||
// to windows-style path:
|
||||
expected, err = filepath.Abs(expected)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
expect(t, expected, c.String("test"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, expected, c.String("test"))
|
||||
}
|
||||
|
||||
func TestPathApplyInputSourceMethodContextSet(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewPathFlag(&cli.PathFlag{Name: "test"}),
|
||||
FlagName: "test",
|
||||
MapValue: "hello",
|
||||
ContextValueString: "goodbye",
|
||||
SourcePath: "/path/to/source/file",
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, "goodbye", c.String("test"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, "goodbye", c.String("test"))
|
||||
}
|
||||
|
||||
func TestPathApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewPathFlag(&cli.PathFlag{Name: "test", EnvVars: []string{"TEST"}}),
|
||||
FlagName: "test",
|
||||
MapValue: "hello",
|
||||
EnvVarName: "TEST",
|
||||
EnvVarValue: "goodbye",
|
||||
SourcePath: "/path/to/source/file",
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, "goodbye", c.String("test"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, "goodbye", c.String("test"))
|
||||
}
|
||||
|
||||
func TestIntApplyInputSourceMethodSet_Alias(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewIntFlag(&cli.IntFlag{Name: "test", Aliases: []string{"test_alias"}}),
|
||||
FlagName: "test_alias",
|
||||
MapValue: 15,
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, 15, c.Int("test_alias"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, 15, c.Int("test_alias"))
|
||||
}
|
||||
|
||||
func TestIntApplyInputSourceMethodSet(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewIntFlag(&cli.IntFlag{Name: "test"}),
|
||||
FlagName: "test",
|
||||
MapValue: 15,
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, 15, c.Int("test"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, 15, c.Int("test"))
|
||||
}
|
||||
|
||||
func TestIntApplyInputSourceMethodSetNegativeValue(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewIntFlag(&cli.IntFlag{Name: "test"}),
|
||||
FlagName: "test",
|
||||
MapValue: -1,
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, -1, c.Int("test"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, -1, c.Int("test"))
|
||||
}
|
||||
|
||||
func TestIntApplyInputSourceMethodContextSet(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewIntFlag(&cli.IntFlag{Name: "test"}),
|
||||
FlagName: "test",
|
||||
MapValue: 15,
|
||||
ContextValueString: "7",
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, 7, c.Int("test"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, 7, c.Int("test"))
|
||||
}
|
||||
|
||||
func TestIntApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewIntFlag(&cli.IntFlag{Name: "test", EnvVars: []string{"TEST"}}),
|
||||
FlagName: "test",
|
||||
MapValue: 15,
|
||||
EnvVarName: "TEST",
|
||||
EnvVarValue: "12",
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, 12, c.Int("test"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, 12, c.Int("test"))
|
||||
}
|
||||
|
||||
func TestDurationApplyInputSourceMethodSet_Alias(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewDurationFlag(&cli.DurationFlag{Name: "test", Aliases: []string{"test_alias"}}),
|
||||
FlagName: "test_alias",
|
||||
MapValue: 30 * time.Second,
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, 30*time.Second, c.Duration("test_alias"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, 30*time.Second, c.Duration("test_alias"))
|
||||
}
|
||||
|
||||
func TestDurationApplyInputSourceMethodSet(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewDurationFlag(&cli.DurationFlag{Name: "test"}),
|
||||
FlagName: "test",
|
||||
MapValue: 30 * time.Second,
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, 30*time.Second, c.Duration("test"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, 30*time.Second, c.Duration("test"))
|
||||
}
|
||||
|
||||
func TestDurationApplyInputSourceMethodSetNegativeValue(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewDurationFlag(&cli.DurationFlag{Name: "test"}),
|
||||
FlagName: "test",
|
||||
MapValue: -30 * time.Second,
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, -30*time.Second, c.Duration("test"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, -30*time.Second, c.Duration("test"))
|
||||
}
|
||||
|
||||
func TestDurationApplyInputSourceMethodContextSet(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewDurationFlag(&cli.DurationFlag{Name: "test"}),
|
||||
FlagName: "test",
|
||||
MapValue: 30 * time.Second,
|
||||
ContextValueString: (15 * time.Second).String(),
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, 15*time.Second, c.Duration("test"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, 15*time.Second, c.Duration("test"))
|
||||
}
|
||||
|
||||
func TestDurationApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewDurationFlag(&cli.DurationFlag{Name: "test", EnvVars: []string{"TEST"}}),
|
||||
FlagName: "test",
|
||||
MapValue: 30 * time.Second,
|
||||
EnvVarName: "TEST",
|
||||
EnvVarValue: (15 * time.Second).String(),
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, 15*time.Second, c.Duration("test"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, 15*time.Second, c.Duration("test"))
|
||||
}
|
||||
|
||||
func TestFloat64ApplyInputSourceMethodSet(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewFloat64Flag(&cli.Float64Flag{Name: "test"}),
|
||||
FlagName: "test",
|
||||
MapValue: 1.3,
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, 1.3, c.Float64("test"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, 1.3, c.Float64("test"))
|
||||
}
|
||||
|
||||
func TestFloat64ApplyInputSourceMethodSetNegativeValue_Alias(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewFloat64Flag(&cli.Float64Flag{Name: "test", Aliases: []string{"test_alias"}}),
|
||||
FlagName: "test_alias",
|
||||
MapValue: -1.3,
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, -1.3, c.Float64("test_alias"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, -1.3, c.Float64("test_alias"))
|
||||
}
|
||||
|
||||
func TestFloat64ApplyInputSourceMethodSetNegativeValue(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewFloat64Flag(&cli.Float64Flag{Name: "test"}),
|
||||
FlagName: "test",
|
||||
MapValue: -1.3,
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, -1.3, c.Float64("test"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, -1.3, c.Float64("test"))
|
||||
}
|
||||
|
||||
func TestFloat64ApplyInputSourceMethodSetNegativeValueNotSet(t *testing.T) {
|
||||
c := runTest(t, testApplyInputSource{
|
||||
Flag: NewFloat64Flag(&cli.Float64Flag{Name: "test1"}),
|
||||
FlagName: "test1",
|
||||
// dont set map value
|
||||
})
|
||||
expect(t, 0.0, c.Float64("test1"))
|
||||
}
|
||||
|
||||
func TestFloat64ApplyInputSourceMethodContextSet(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewFloat64Flag(&cli.Float64Flag{Name: "test"}),
|
||||
FlagName: "test",
|
||||
MapValue: 1.3,
|
||||
ContextValueString: fmt.Sprintf("%v", 1.4),
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, 1.4, c.Float64("test"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, 1.4, c.Float64("test"))
|
||||
}
|
||||
|
||||
func TestFloat64ApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||
tis := testApplyInputSource{
|
||||
Flag: NewFloat64Flag(&cli.Float64Flag{Name: "test", EnvVars: []string{"TEST"}}),
|
||||
FlagName: "test",
|
||||
MapValue: 1.3,
|
||||
EnvVarName: "TEST",
|
||||
EnvVarValue: fmt.Sprintf("%v", 1.4),
|
||||
}
|
||||
c := runTest(t, tis)
|
||||
expect(t, 1.4, c.Float64("test"))
|
||||
|
||||
c = runRacyTest(t, tis)
|
||||
refute(t, 1.4, c.Float64("test"))
|
||||
}
|
||||
|
||||
func runTest(t *testing.T, test testApplyInputSource) *cli.Context {
|
||||
inputSource := &MapInputSource{
|
||||
file: test.SourcePath,
|
||||
valueMap: map[interface{}]interface{}{test.FlagName: test.MapValue},
|
||||
}
|
||||
set := flag.NewFlagSet(test.FlagSetName, flag.ContinueOnError)
|
||||
c := cli.NewContext(nil, set, nil)
|
||||
if test.EnvVarName != "" && test.EnvVarValue != "" {
|
||||
_ = os.Setenv(test.EnvVarName, test.EnvVarValue)
|
||||
defer os.Setenv(test.EnvVarName, "")
|
||||
}
|
||||
|
||||
_ = test.Flag.Apply(set)
|
||||
if test.ContextValue != nil {
|
||||
f := set.Lookup(test.FlagName)
|
||||
f.Value = test.ContextValue
|
||||
}
|
||||
if test.ContextValueString != "" {
|
||||
_ = set.Set(test.FlagName, test.ContextValueString)
|
||||
}
|
||||
_ = test.Flag.ApplyInputSourceValue(c, inputSource)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func runRacyTest(t *testing.T, test testApplyInputSource) *cli.Context {
|
||||
set := flag.NewFlagSet(test.FlagSetName, flag.ContinueOnError)
|
||||
c := cli.NewContext(nil, set, nil)
|
||||
_ = test.Flag.ApplyInputSourceValue(c, &racyInputSource{
|
||||
MapInputSource: &MapInputSource{
|
||||
file: test.SourcePath,
|
||||
valueMap: map[interface{}]interface{}{test.FlagName: test.MapValue},
|
||||
},
|
||||
})
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
type Parser [2]string
|
||||
|
||||
func (p *Parser) Set(value string) error {
|
||||
parts := strings.Split(value, ",")
|
||||
if len(parts) != 2 {
|
||||
return fmt.Errorf("invalid format")
|
||||
}
|
||||
|
||||
(*p)[0] = parts[0]
|
||||
(*p)[1] = parts[1]
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Parser) String() string {
|
||||
return fmt.Sprintf("%s,%s", p[0], p[1])
|
||||
}
|
||||
|
||||
type bogus [1]uint
|
@ -1,31 +0,0 @@
|
||||
package altsrc
|
||||
|
||||
import (
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
wd, _ = os.Getwd()
|
||||
)
|
||||
|
||||
func expect(t *testing.T, a interface{}, b interface{}) {
|
||||
_, fn, line, _ := runtime.Caller(1)
|
||||
fn = strings.Replace(fn, wd+"/", "", -1)
|
||||
|
||||
if !reflect.DeepEqual(a, b) {
|
||||
t.Errorf("(%s:%d) Expected %v (type %v) - Got %v (type %v)", fn, line, b, reflect.TypeOf(b), a, reflect.TypeOf(a))
|
||||
}
|
||||
}
|
||||
|
||||
func refute(t *testing.T, a interface{}, b interface{}) {
|
||||
_, fn, line, _ := runtime.Caller(1)
|
||||
fn = strings.Replace(fn, wd+"/", "", -1)
|
||||
|
||||
if reflect.DeepEqual(a, b) {
|
||||
t.Errorf("(%s:%d) Did not expect %v (type %v) - Got %v (type %v)", fn, line, b, reflect.TypeOf(b), a, reflect.TypeOf(a))
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
package altsrc
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// InputSourceContext is an interface used to allow
|
||||
// other input sources to be implemented as needed.
|
||||
//
|
||||
// Source returns an identifier for the input source. In case of file source
|
||||
// it should return path to the file.
|
||||
type InputSourceContext interface {
|
||||
Source() string
|
||||
|
||||
Int(name string) (int, error)
|
||||
Duration(name string) (time.Duration, error)
|
||||
Float64(name string) (float64, error)
|
||||
String(name string) (string, error)
|
||||
StringSlice(name string) ([]string, error)
|
||||
IntSlice(name string) ([]int, error)
|
||||
Int64Slice(name string) ([]int64, error)
|
||||
Generic(name string) (cli.Generic, error)
|
||||
Bool(name string) (bool, error)
|
||||
|
||||
isSet(name string) bool
|
||||
}
|
@ -1,329 +0,0 @@
|
||||
package altsrc
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
const (
|
||||
fileName = "current.json"
|
||||
simpleJSON = `{"test": 15, "testb": false}`
|
||||
nestedJSON = `{"top": {"test": 15}}`
|
||||
)
|
||||
|
||||
func TestCommandJSONFileTest(t *testing.T) {
|
||||
cleanup := writeTempFile(t, fileName, simpleJSON)
|
||||
defer cleanup()
|
||||
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
test := []string{"test-cmd", "--load", fileName}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("test")
|
||||
expect(t, val, 15)
|
||||
|
||||
valb := c.Bool("testb")
|
||||
expect(t, valb, false)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "test"}),
|
||||
&cli.StringFlag{Name: "load"},
|
||||
NewBoolFlag(&cli.BoolFlag{Name: "testb", Value: true}),
|
||||
},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewJSONSourceFromFlagFunc("load"))
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func TestCommandJSONFileTestGlobalEnvVarWins(t *testing.T) {
|
||||
cleanup := writeTempFile(t, fileName, simpleJSON)
|
||||
defer cleanup()
|
||||
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
_ = os.Setenv("THE_TEST", "10")
|
||||
defer os.Setenv("THE_TEST", "")
|
||||
|
||||
test := []string{"test-cmd", "--load", fileName}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("test")
|
||||
expect(t, val, 10)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "test", EnvVars: []string{"THE_TEST"}}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewJSONSourceFromFlagFunc("load"))
|
||||
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func TestCommandJSONFileTestGlobalEnvVarWinsNested(t *testing.T) {
|
||||
cleanup := writeTempFile(t, fileName, nestedJSON)
|
||||
defer cleanup()
|
||||
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
_ = os.Setenv("THE_TEST", "10")
|
||||
defer os.Setenv("THE_TEST", "")
|
||||
|
||||
test := []string{"test-cmd", "--load", fileName}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("top.test")
|
||||
expect(t, val, 10)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "top.test", EnvVars: []string{"THE_TEST"}}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewJSONSourceFromFlagFunc("load"))
|
||||
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func TestCommandJSONFileTestSpecifiedFlagWins(t *testing.T) {
|
||||
cleanup := writeTempFile(t, fileName, simpleJSON)
|
||||
defer cleanup()
|
||||
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
test := []string{"test-cmd", "--load", fileName, "--test", "7"}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("test")
|
||||
expect(t, val, 7)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "test"}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewJSONSourceFromFlagFunc("load"))
|
||||
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func TestCommandJSONFileTestSpecifiedFlagWinsNested(t *testing.T) {
|
||||
cleanup := writeTempFile(t, fileName, nestedJSON)
|
||||
defer cleanup()
|
||||
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
test := []string{"test-cmd", "--load", fileName, "--top.test", "7"}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("top.test")
|
||||
expect(t, val, 7)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "top.test"}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewJSONSourceFromFlagFunc("load"))
|
||||
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func TestCommandJSONFileTestDefaultValueFileWins(t *testing.T) {
|
||||
cleanup := writeTempFile(t, fileName, simpleJSON)
|
||||
defer cleanup()
|
||||
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
test := []string{"test-cmd", "--load", fileName}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("test")
|
||||
expect(t, val, 15)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "test", Value: 7}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewJSONSourceFromFlagFunc("load"))
|
||||
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func TestCommandJSONFileTestDefaultValueFileWinsNested(t *testing.T) {
|
||||
cleanup := writeTempFile(t, fileName, nestedJSON)
|
||||
defer cleanup()
|
||||
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
test := []string{"test-cmd", "--load", fileName}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("top.test")
|
||||
expect(t, val, 15)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "top.test", Value: 7}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewJSONSourceFromFlagFunc("load"))
|
||||
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func TestCommandJSONFileFlagHasDefaultGlobalEnvJSONSetGlobalEnvWins(t *testing.T) {
|
||||
cleanup := writeTempFile(t, fileName, simpleJSON)
|
||||
defer cleanup()
|
||||
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
_ = os.Setenv("THE_TEST", "11")
|
||||
defer os.Setenv("THE_TEST", "")
|
||||
|
||||
test := []string{"test-cmd", "--load", fileName}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("test")
|
||||
expect(t, val, 11)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "test", Value: 7, EnvVars: []string{"THE_TEST"}}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewJSONSourceFromFlagFunc("load"))
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func TestCommandJSONFileFlagHasDefaultGlobalEnvJSONSetGlobalEnvWinsNested(t *testing.T) {
|
||||
cleanup := writeTempFile(t, fileName, nestedJSON)
|
||||
defer cleanup()
|
||||
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
_ = os.Setenv("THE_TEST", "11")
|
||||
defer os.Setenv("THE_TEST", "")
|
||||
|
||||
test := []string{"test-cmd", "--load", fileName}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("top.test")
|
||||
expect(t, val, 11)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "top.test", Value: 7, EnvVars: []string{"THE_TEST"}}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewJSONSourceFromFlagFunc("load"))
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func writeTempFile(t *testing.T, name string, content string) func() {
|
||||
if err := ioutil.WriteFile(name, []byte(content), 0666); err != nil {
|
||||
t.Fatalf("cannot write %q: %v", name, err)
|
||||
}
|
||||
return func() {
|
||||
if err := os.Remove(name); err != nil {
|
||||
t.Errorf("cannot remove %q: %v", name, err)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,240 +0,0 @@
|
||||
package altsrc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// NewJSONSourceFromFlagFunc returns a func that takes a cli.Context
|
||||
// and returns an InputSourceContext suitable for retrieving config
|
||||
// variables from a file containing JSON data with the file name defined
|
||||
// by the given flag.
|
||||
func NewJSONSourceFromFlagFunc(flag string) func(c *cli.Context) (InputSourceContext, error) {
|
||||
return func(cCtx *cli.Context) (InputSourceContext, error) {
|
||||
if cCtx.IsSet(flag) {
|
||||
return NewJSONSourceFromFile(cCtx.String(flag))
|
||||
}
|
||||
|
||||
return defaultInputSource()
|
||||
}
|
||||
}
|
||||
|
||||
// NewJSONSourceFromFile returns an InputSourceContext suitable for
|
||||
// retrieving config variables from a file (or url) containing JSON
|
||||
// data.
|
||||
func NewJSONSourceFromFile(f string) (InputSourceContext, error) {
|
||||
data, err := loadDataFrom(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewJSONSource(data)
|
||||
}
|
||||
|
||||
// NewJSONSourceFromReader returns an InputSourceContext suitable for
|
||||
// retrieving config variables from an io.Reader that returns JSON data.
|
||||
func NewJSONSourceFromReader(r io.Reader) (InputSourceContext, error) {
|
||||
data, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewJSONSource(data)
|
||||
}
|
||||
|
||||
// NewJSONSource returns an InputSourceContext suitable for retrieving
|
||||
// config variables from raw JSON data.
|
||||
func NewJSONSource(data []byte) (InputSourceContext, error) {
|
||||
var deserialized map[string]interface{}
|
||||
if err := json.Unmarshal(data, &deserialized); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &jsonSource{deserialized: deserialized}, nil
|
||||
}
|
||||
|
||||
func (x *jsonSource) Source() string {
|
||||
return x.file
|
||||
}
|
||||
|
||||
func (x *jsonSource) Int(name string) (int, error) {
|
||||
i, err := x.getValue(name)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
switch v := i.(type) {
|
||||
default:
|
||||
return 0, fmt.Errorf("unexpected type %T for %q", i, name)
|
||||
case int:
|
||||
return v, nil
|
||||
case float32:
|
||||
return int(v), nil
|
||||
case float64:
|
||||
return int(v), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (x *jsonSource) Duration(name string) (time.Duration, error) {
|
||||
i, err := x.getValue(name)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
v, ok := i.(time.Duration)
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("unexpected type %T for %q", i, name)
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (x *jsonSource) Float64(name string) (float64, error) {
|
||||
i, err := x.getValue(name)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
v, ok := i.(float64)
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("unexpected type %T for %q", i, name)
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (x *jsonSource) String(name string) (string, error) {
|
||||
i, err := x.getValue(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
v, ok := i.(string)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("unexpected type %T for %q", i, name)
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (x *jsonSource) StringSlice(name string) ([]string, error) {
|
||||
i, err := x.getValue(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch v := i.(type) {
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected type %T for %q", i, name)
|
||||
case []string:
|
||||
return v, nil
|
||||
case []interface{}:
|
||||
c := []string{}
|
||||
for _, s := range v {
|
||||
if str, ok := s.(string); ok {
|
||||
c = append(c, str)
|
||||
} else {
|
||||
return c, fmt.Errorf("unexpected item type %T in %T for %q", s, c, name)
|
||||
}
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (x *jsonSource) IntSlice(name string) ([]int, error) {
|
||||
i, err := x.getValue(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch v := i.(type) {
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected type %T for %q", i, name)
|
||||
case []int:
|
||||
return v, nil
|
||||
case []interface{}:
|
||||
c := []int{}
|
||||
for _, s := range v {
|
||||
if i2, ok := s.(int); ok {
|
||||
c = append(c, i2)
|
||||
} else {
|
||||
return c, fmt.Errorf("unexpected item type %T in %T for %q", s, c, name)
|
||||
}
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (x *jsonSource) Int64Slice(name string) ([]int64, error) {
|
||||
i, err := x.getValue(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch v := i.(type) {
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected type %T for %q", i, name)
|
||||
case []int64:
|
||||
return v, nil
|
||||
case []interface{}:
|
||||
c := []int64{}
|
||||
for _, s := range v {
|
||||
if i2, ok := s.(int64); ok {
|
||||
c = append(c, i2)
|
||||
} else {
|
||||
return c, fmt.Errorf("unexpected item type %T in %T for %q", s, c, name)
|
||||
}
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (x *jsonSource) Generic(name string) (cli.Generic, error) {
|
||||
i, err := x.getValue(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v, ok := i.(cli.Generic)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected type %T for %q", i, name)
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (x *jsonSource) Bool(name string) (bool, error) {
|
||||
i, err := x.getValue(name)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
v, ok := i.(bool)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("unexpected type %T for %q", i, name)
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (x *jsonSource) isSet(name string) bool {
|
||||
_, err := x.getValue(name)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (x *jsonSource) getValue(key string) (interface{}, error) {
|
||||
return jsonGetValue(key, x.deserialized)
|
||||
}
|
||||
|
||||
func jsonGetValue(key string, m map[string]interface{}) (interface{}, error) {
|
||||
var ret interface{}
|
||||
var ok bool
|
||||
working := m
|
||||
keys := strings.Split(key, ".")
|
||||
for ix, k := range keys {
|
||||
if ret, ok = working[k]; !ok {
|
||||
return ret, fmt.Errorf("missing key %q", key)
|
||||
}
|
||||
if working, ok = ret.(map[string]interface{}); !ok {
|
||||
if ix < len(keys)-1 {
|
||||
return ret, fmt.Errorf("unexpected intermediate value at %q segment of %q: %T", k, key, ret)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
type jsonSource struct {
|
||||
file string
|
||||
deserialized map[string]interface{}
|
||||
}
|
@ -1,300 +0,0 @@
|
||||
package altsrc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// MapInputSource implements InputSourceContext to return
|
||||
// data from the map that is loaded.
|
||||
type MapInputSource struct {
|
||||
file string
|
||||
valueMap map[interface{}]interface{}
|
||||
}
|
||||
|
||||
// NewMapInputSource creates a new MapInputSource for implementing custom input sources.
|
||||
func NewMapInputSource(file string, valueMap map[interface{}]interface{}) *MapInputSource {
|
||||
return &MapInputSource{file: file, valueMap: valueMap}
|
||||
}
|
||||
|
||||
// nestedVal checks if the name has '.' delimiters.
|
||||
// If so, it tries to traverse the tree by the '.' delimited sections to find
|
||||
// a nested value for the key.
|
||||
func nestedVal(name string, tree map[interface{}]interface{}) (interface{}, bool) {
|
||||
if sections := strings.Split(name, "."); len(sections) > 1 {
|
||||
node := tree
|
||||
for _, section := range sections[:len(sections)-1] {
|
||||
child, ok := node[section]
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
switch child := child.(type) {
|
||||
case map[string]interface{}:
|
||||
node = make(map[interface{}]interface{}, len(child))
|
||||
for k, v := range child {
|
||||
node[k] = v
|
||||
}
|
||||
case map[interface{}]interface{}:
|
||||
node = child
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
if val, ok := node[sections[len(sections)-1]]; ok {
|
||||
return val, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Source returns the path of the source file
|
||||
func (fsm *MapInputSource) Source() string {
|
||||
return fsm.file
|
||||
}
|
||||
|
||||
// Int returns an int from the map if it exists otherwise returns 0
|
||||
func (fsm *MapInputSource) Int(name string) (int, error) {
|
||||
otherGenericValue, exists := fsm.valueMap[name]
|
||||
if exists {
|
||||
otherValue, isType := otherGenericValue.(int)
|
||||
if !isType {
|
||||
return 0, incorrectTypeForFlagError(name, "int", otherGenericValue)
|
||||
}
|
||||
return otherValue, nil
|
||||
}
|
||||
nestedGenericValue, exists := nestedVal(name, fsm.valueMap)
|
||||
if exists {
|
||||
otherValue, isType := nestedGenericValue.(int)
|
||||
if !isType {
|
||||
return 0, incorrectTypeForFlagError(name, "int", nestedGenericValue)
|
||||
}
|
||||
return otherValue, nil
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Duration returns a duration from the map if it exists otherwise returns 0
|
||||
func (fsm *MapInputSource) Duration(name string) (time.Duration, error) {
|
||||
otherGenericValue, exists := fsm.valueMap[name]
|
||||
if exists {
|
||||
return castDuration(name, otherGenericValue)
|
||||
}
|
||||
nestedGenericValue, exists := nestedVal(name, fsm.valueMap)
|
||||
if exists {
|
||||
return castDuration(name, nestedGenericValue)
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func castDuration(name string, value interface{}) (time.Duration, error) {
|
||||
if otherValue, isType := value.(time.Duration); isType {
|
||||
return otherValue, nil
|
||||
}
|
||||
otherStringValue, isType := value.(string)
|
||||
parsedValue, err := time.ParseDuration(otherStringValue)
|
||||
if !isType || err != nil {
|
||||
return 0, incorrectTypeForFlagError(name, "duration", value)
|
||||
}
|
||||
return parsedValue, nil
|
||||
}
|
||||
|
||||
// Float64 returns an float64 from the map if it exists otherwise returns 0
|
||||
func (fsm *MapInputSource) Float64(name string) (float64, error) {
|
||||
otherGenericValue, exists := fsm.valueMap[name]
|
||||
if exists {
|
||||
otherValue, isType := otherGenericValue.(float64)
|
||||
if !isType {
|
||||
return 0, incorrectTypeForFlagError(name, "float64", otherGenericValue)
|
||||
}
|
||||
return otherValue, nil
|
||||
}
|
||||
nestedGenericValue, exists := nestedVal(name, fsm.valueMap)
|
||||
if exists {
|
||||
otherValue, isType := nestedGenericValue.(float64)
|
||||
if !isType {
|
||||
return 0, incorrectTypeForFlagError(name, "float64", nestedGenericValue)
|
||||
}
|
||||
return otherValue, nil
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// String returns a string from the map if it exists otherwise returns an empty string
|
||||
func (fsm *MapInputSource) String(name string) (string, error) {
|
||||
otherGenericValue, exists := fsm.valueMap[name]
|
||||
if exists {
|
||||
otherValue, isType := otherGenericValue.(string)
|
||||
if !isType {
|
||||
return "", incorrectTypeForFlagError(name, "string", otherGenericValue)
|
||||
}
|
||||
return otherValue, nil
|
||||
}
|
||||
nestedGenericValue, exists := nestedVal(name, fsm.valueMap)
|
||||
if exists {
|
||||
otherValue, isType := nestedGenericValue.(string)
|
||||
if !isType {
|
||||
return "", incorrectTypeForFlagError(name, "string", nestedGenericValue)
|
||||
}
|
||||
return otherValue, nil
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// StringSlice returns an []string from the map if it exists otherwise returns nil
|
||||
func (fsm *MapInputSource) StringSlice(name string) ([]string, error) {
|
||||
otherGenericValue, exists := fsm.valueMap[name]
|
||||
if !exists {
|
||||
otherGenericValue, exists = nestedVal(name, fsm.valueMap)
|
||||
if !exists {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
otherValue, isType := otherGenericValue.([]interface{})
|
||||
if !isType {
|
||||
return nil, incorrectTypeForFlagError(name, "[]interface{}", otherGenericValue)
|
||||
}
|
||||
|
||||
var stringSlice = make([]string, 0, len(otherValue))
|
||||
for i, v := range otherValue {
|
||||
stringValue, isType := v.(string)
|
||||
|
||||
if !isType {
|
||||
return nil, incorrectTypeForFlagError(fmt.Sprintf("%s[%d]", name, i), "string", v)
|
||||
}
|
||||
|
||||
stringSlice = append(stringSlice, stringValue)
|
||||
}
|
||||
|
||||
return stringSlice, nil
|
||||
}
|
||||
|
||||
// IntSlice returns an []int from the map if it exists otherwise returns nil
|
||||
func (fsm *MapInputSource) IntSlice(name string) ([]int, error) {
|
||||
otherGenericValue, exists := fsm.valueMap[name]
|
||||
if !exists {
|
||||
otherGenericValue, exists = nestedVal(name, fsm.valueMap)
|
||||
if !exists {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
otherValue, isType := otherGenericValue.([]interface{})
|
||||
if !isType {
|
||||
return nil, incorrectTypeForFlagError(name, "[]interface{}", otherGenericValue)
|
||||
}
|
||||
|
||||
var intSlice = make([]int, 0, len(otherValue))
|
||||
for i, v := range otherValue {
|
||||
intValue, isType := v.(int)
|
||||
|
||||
if !isType {
|
||||
return nil, incorrectTypeForFlagError(fmt.Sprintf("%s[%d]", name, i), "int", v)
|
||||
}
|
||||
|
||||
intSlice = append(intSlice, intValue)
|
||||
}
|
||||
|
||||
return intSlice, nil
|
||||
}
|
||||
|
||||
// Int64Slice returns an []int64 from the map if it exists otherwise returns nil
|
||||
func (fsm *MapInputSource) Int64Slice(name string) ([]int64, error) {
|
||||
otherGenericValue, exists := fsm.valueMap[name]
|
||||
if !exists {
|
||||
otherGenericValue, exists = nestedVal(name, fsm.valueMap)
|
||||
if !exists {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
otherValue, isType := otherGenericValue.([]interface{})
|
||||
if !isType {
|
||||
return nil, incorrectTypeForFlagError(name, "[]interface{}", otherGenericValue)
|
||||
}
|
||||
|
||||
var int64Slice = make([]int64, 0, len(otherValue))
|
||||
for i, v := range otherValue {
|
||||
int64Value, isType := v.(int64)
|
||||
|
||||
if !isType {
|
||||
return nil, incorrectTypeForFlagError(fmt.Sprintf("%s[%d]", name, i), "int", v)
|
||||
}
|
||||
|
||||
int64Slice = append(int64Slice, int64Value)
|
||||
}
|
||||
|
||||
return int64Slice, nil
|
||||
}
|
||||
|
||||
// Generic returns an cli.Generic from the map if it exists otherwise returns nil
|
||||
func (fsm *MapInputSource) Generic(name string) (cli.Generic, error) {
|
||||
otherGenericValue, exists := fsm.valueMap[name]
|
||||
if exists {
|
||||
otherValue, isType := otherGenericValue.(cli.Generic)
|
||||
if !isType {
|
||||
return nil, incorrectTypeForFlagError(name, "cli.Generic", otherGenericValue)
|
||||
}
|
||||
return otherValue, nil
|
||||
}
|
||||
nestedGenericValue, exists := nestedVal(name, fsm.valueMap)
|
||||
if exists {
|
||||
otherValue, isType := nestedGenericValue.(cli.Generic)
|
||||
if !isType {
|
||||
return nil, incorrectTypeForFlagError(name, "cli.Generic", nestedGenericValue)
|
||||
}
|
||||
return otherValue, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Bool returns an bool from the map otherwise returns false
|
||||
func (fsm *MapInputSource) Bool(name string) (bool, error) {
|
||||
otherGenericValue, exists := fsm.valueMap[name]
|
||||
if exists {
|
||||
otherValue, isType := otherGenericValue.(bool)
|
||||
if !isType {
|
||||
return false, incorrectTypeForFlagError(name, "bool", otherGenericValue)
|
||||
}
|
||||
return otherValue, nil
|
||||
}
|
||||
nestedGenericValue, exists := nestedVal(name, fsm.valueMap)
|
||||
if exists {
|
||||
otherValue, isType := nestedGenericValue.(bool)
|
||||
if !isType {
|
||||
return false, incorrectTypeForFlagError(name, "bool", nestedGenericValue)
|
||||
}
|
||||
return otherValue, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (fsm *MapInputSource) isSet(name string) bool {
|
||||
if _, exists := fsm.valueMap[name]; exists {
|
||||
return exists
|
||||
}
|
||||
|
||||
_, exists := nestedVal(name, fsm.valueMap)
|
||||
return exists
|
||||
}
|
||||
|
||||
func incorrectTypeForFlagError(name, expectedTypeName string, value interface{}) error {
|
||||
valueType := reflect.TypeOf(value)
|
||||
valueTypeName := ""
|
||||
if valueType != nil {
|
||||
valueTypeName = valueType.Name()
|
||||
}
|
||||
|
||||
return fmt.Errorf("Mismatched type for flag '%s'. Expected '%s' but actual is '%s'", name, expectedTypeName, valueTypeName)
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package altsrc
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestMapDuration(t *testing.T) {
|
||||
inputSource := NewMapInputSource(
|
||||
"test",
|
||||
map[interface{}]interface{}{
|
||||
"duration_of_duration_type": time.Minute,
|
||||
"duration_of_string_type": "1m",
|
||||
"duration_of_int_type": 1000,
|
||||
})
|
||||
d, err := inputSource.Duration("duration_of_duration_type")
|
||||
expect(t, time.Minute, d)
|
||||
expect(t, nil, err)
|
||||
d, err = inputSource.Duration("duration_of_string_type")
|
||||
expect(t, time.Minute, d)
|
||||
expect(t, nil, err)
|
||||
_, err = inputSource.Duration("duration_of_int_type")
|
||||
refute(t, nil, err)
|
||||
}
|
||||
|
||||
func TestMapInputSource_Int64Slice(t *testing.T) {
|
||||
inputSource := NewMapInputSource(
|
||||
"test",
|
||||
map[interface{}]interface{}{
|
||||
"test_num": []interface{}{int64(1), int64(2), int64(3)},
|
||||
})
|
||||
d, err := inputSource.Int64Slice("test_num")
|
||||
expect(t, []int64{1, 2, 3}, d)
|
||||
expect(t, nil, err)
|
||||
}
|
@ -1,305 +0,0 @@
|
||||
package altsrc
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
func TestCommandTomFileTest(t *testing.T) {
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
_ = ioutil.WriteFile("current.toml", []byte("test = 15"), 0666)
|
||||
defer os.Remove("current.toml")
|
||||
test := []string{"test-cmd", "--load", "current.toml"}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("test")
|
||||
expect(t, val, 15)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "test"}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func TestCommandTomlFileTestGlobalEnvVarWins(t *testing.T) {
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
_ = ioutil.WriteFile("current.toml", []byte("test = 15"), 0666)
|
||||
defer os.Remove("current.toml")
|
||||
|
||||
_ = os.Setenv("THE_TEST", "10")
|
||||
defer os.Setenv("THE_TEST", "")
|
||||
test := []string{"test-cmd", "--load", "current.toml"}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("test")
|
||||
expect(t, val, 10)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "test", EnvVars: []string{"THE_TEST"}}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
|
||||
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func TestCommandTomlFileTestGlobalEnvVarWinsNested(t *testing.T) {
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
_ = ioutil.WriteFile("current.toml", []byte("[top]\ntest = 15"), 0666)
|
||||
defer os.Remove("current.toml")
|
||||
|
||||
_ = os.Setenv("THE_TEST", "10")
|
||||
defer os.Setenv("THE_TEST", "")
|
||||
test := []string{"test-cmd", "--load", "current.toml"}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("top.test")
|
||||
expect(t, val, 10)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "top.test", EnvVars: []string{"THE_TEST"}}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
|
||||
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func TestCommandTomlFileTestSpecifiedFlagWins(t *testing.T) {
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
_ = ioutil.WriteFile("current.toml", []byte("test = 15"), 0666)
|
||||
defer os.Remove("current.toml")
|
||||
|
||||
test := []string{"test-cmd", "--load", "current.toml", "--test", "7"}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("test")
|
||||
expect(t, val, 7)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "test"}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
|
||||
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func TestCommandTomlFileTestSpecifiedFlagWinsNested(t *testing.T) {
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
_ = ioutil.WriteFile("current.toml", []byte(`[top]
|
||||
test = 15`), 0666)
|
||||
defer os.Remove("current.toml")
|
||||
|
||||
test := []string{"test-cmd", "--load", "current.toml", "--top.test", "7"}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("top.test")
|
||||
expect(t, val, 7)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "top.test"}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
|
||||
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func TestCommandTomlFileTestDefaultValueFileWins(t *testing.T) {
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
_ = ioutil.WriteFile("current.toml", []byte("test = 15"), 0666)
|
||||
defer os.Remove("current.toml")
|
||||
|
||||
test := []string{"test-cmd", "--load", "current.toml"}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("test")
|
||||
expect(t, val, 15)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "test", Value: 7}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
|
||||
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func TestCommandTomlFileTestDefaultValueFileWinsNested(t *testing.T) {
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
_ = ioutil.WriteFile("current.toml", []byte("[top]\ntest = 15"), 0666)
|
||||
defer os.Remove("current.toml")
|
||||
|
||||
test := []string{"test-cmd", "--load", "current.toml"}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("top.test")
|
||||
expect(t, val, 15)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "top.test", Value: 7}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
|
||||
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func TestCommandTomlFileFlagHasDefaultGlobalEnvTomlSetGlobalEnvWins(t *testing.T) {
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
_ = ioutil.WriteFile("current.toml", []byte("test = 15"), 0666)
|
||||
defer os.Remove("current.toml")
|
||||
|
||||
_ = os.Setenv("THE_TEST", "11")
|
||||
defer os.Setenv("THE_TEST", "")
|
||||
|
||||
test := []string{"test-cmd", "--load", "current.toml"}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("test")
|
||||
expect(t, val, 11)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "test", Value: 7, EnvVars: []string{"THE_TEST"}}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func TestCommandTomlFileFlagHasDefaultGlobalEnvTomlSetGlobalEnvWinsNested(t *testing.T) {
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
_ = ioutil.WriteFile("current.toml", []byte("[top]\ntest = 15"), 0666)
|
||||
defer os.Remove("current.toml")
|
||||
|
||||
_ = os.Setenv("THE_TEST", "11")
|
||||
defer os.Setenv("THE_TEST", "")
|
||||
|
||||
test := []string{"test-cmd", "--load", "current.toml"}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("top.test")
|
||||
expect(t, val, 11)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "top.test", Value: 7, EnvVars: []string{"THE_TEST"}}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
package altsrc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
type tomlMap struct {
|
||||
Map map[interface{}]interface{}
|
||||
}
|
||||
|
||||
func unmarshalMap(i interface{}) (ret map[interface{}]interface{}, err error) {
|
||||
ret = make(map[interface{}]interface{})
|
||||
m := i.(map[string]interface{})
|
||||
for key, val := range m {
|
||||
v := reflect.ValueOf(val)
|
||||
switch v.Kind() {
|
||||
case reflect.Bool:
|
||||
ret[key] = val.(bool)
|
||||
case reflect.String:
|
||||
ret[key] = val.(string)
|
||||
case reflect.Int:
|
||||
ret[key] = val.(int)
|
||||
case reflect.Int8:
|
||||
ret[key] = int(val.(int8))
|
||||
case reflect.Int16:
|
||||
ret[key] = int(val.(int16))
|
||||
case reflect.Int32:
|
||||
ret[key] = int(val.(int32))
|
||||
case reflect.Int64:
|
||||
ret[key] = int(val.(int64))
|
||||
case reflect.Uint:
|
||||
ret[key] = int(val.(uint))
|
||||
case reflect.Uint8:
|
||||
ret[key] = int(val.(uint8))
|
||||
case reflect.Uint16:
|
||||
ret[key] = int(val.(uint16))
|
||||
case reflect.Uint32:
|
||||
ret[key] = int(val.(uint32))
|
||||
case reflect.Uint64:
|
||||
ret[key] = int(val.(uint64))
|
||||
case reflect.Float32:
|
||||
ret[key] = float64(val.(float32))
|
||||
case reflect.Float64:
|
||||
ret[key] = val.(float64)
|
||||
case reflect.Map:
|
||||
if tmp, err := unmarshalMap(val); err == nil {
|
||||
ret[key] = tmp
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
case reflect.Array, reflect.Slice:
|
||||
ret[key] = val.([]interface{})
|
||||
default:
|
||||
return nil, fmt.Errorf("Unsupported: type = %#v", v.Kind())
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (tm *tomlMap) UnmarshalTOML(i interface{}) error {
|
||||
if tmp, err := unmarshalMap(i); err == nil {
|
||||
tm.Map = tmp
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type tomlSourceContext struct {
|
||||
FilePath string
|
||||
}
|
||||
|
||||
// NewTomlSourceFromFile creates a new TOML InputSourceContext from a filepath.
|
||||
func NewTomlSourceFromFile(file string) (InputSourceContext, error) {
|
||||
tsc := &tomlSourceContext{FilePath: file}
|
||||
var results tomlMap = tomlMap{}
|
||||
if err := readCommandToml(tsc.FilePath, &results); err != nil {
|
||||
return nil, fmt.Errorf("Unable to load TOML file '%s': inner error: \n'%v'", tsc.FilePath, err.Error())
|
||||
}
|
||||
return &MapInputSource{file: file, valueMap: results.Map}, nil
|
||||
}
|
||||
|
||||
// NewTomlSourceFromFlagFunc creates a new TOML InputSourceContext from a provided flag name and source context.
|
||||
func NewTomlSourceFromFlagFunc(flagFileName string) func(cCtx *cli.Context) (InputSourceContext, error) {
|
||||
return func(cCtx *cli.Context) (InputSourceContext, error) {
|
||||
if cCtx.IsSet(flagFileName) {
|
||||
filePath := cCtx.String(flagFileName)
|
||||
return NewTomlSourceFromFile(filePath)
|
||||
}
|
||||
|
||||
return defaultInputSource()
|
||||
}
|
||||
}
|
||||
|
||||
func readCommandToml(filePath string, container interface{}) (err error) {
|
||||
b, err := loadDataFrom(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = toml.Unmarshal(b, container)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = nil
|
||||
return
|
||||
}
|
@ -1,308 +0,0 @@
|
||||
package altsrc
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
func TestCommandYamlFileTest(t *testing.T) {
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
_ = ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666)
|
||||
defer os.Remove("current.yaml")
|
||||
test := []string{"test-cmd", "--load", "current.yaml"}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("test")
|
||||
expect(t, val, 15)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "test"}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func TestCommandYamlFileTestGlobalEnvVarWins(t *testing.T) {
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
_ = ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666)
|
||||
defer os.Remove("current.yaml")
|
||||
|
||||
_ = os.Setenv("THE_TEST", "10")
|
||||
defer os.Setenv("THE_TEST", "")
|
||||
test := []string{"test-cmd", "--load", "current.yaml"}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("test")
|
||||
expect(t, val, 10)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "test", EnvVars: []string{"THE_TEST"}}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func TestCommandYamlFileTestGlobalEnvVarWinsNested(t *testing.T) {
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
_ = ioutil.WriteFile("current.yaml", []byte(`top:
|
||||
test: 15`), 0666)
|
||||
defer os.Remove("current.yaml")
|
||||
|
||||
_ = os.Setenv("THE_TEST", "10")
|
||||
defer os.Setenv("THE_TEST", "")
|
||||
test := []string{"test-cmd", "--load", "current.yaml"}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("top.test")
|
||||
expect(t, val, 10)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "top.test", EnvVars: []string{"THE_TEST"}}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func TestCommandYamlFileTestSpecifiedFlagWins(t *testing.T) {
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
_ = ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666)
|
||||
defer os.Remove("current.yaml")
|
||||
|
||||
test := []string{"test-cmd", "--load", "current.yaml", "--test", "7"}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("test")
|
||||
expect(t, val, 7)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "test"}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func TestCommandYamlFileTestSpecifiedFlagWinsNested(t *testing.T) {
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
_ = ioutil.WriteFile("current.yaml", []byte(`top:
|
||||
test: 15`), 0666)
|
||||
defer os.Remove("current.yaml")
|
||||
|
||||
test := []string{"test-cmd", "--load", "current.yaml", "--top.test", "7"}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("top.test")
|
||||
expect(t, val, 7)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "top.test"}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func TestCommandYamlFileTestDefaultValueFileWins(t *testing.T) {
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
_ = ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666)
|
||||
defer os.Remove("current.yaml")
|
||||
|
||||
test := []string{"test-cmd", "--load", "current.yaml"}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("test")
|
||||
expect(t, val, 15)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "test", Value: 7}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func TestCommandYamlFileTestDefaultValueFileWinsNested(t *testing.T) {
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
_ = ioutil.WriteFile("current.yaml", []byte(`top:
|
||||
test: 15`), 0666)
|
||||
defer os.Remove("current.yaml")
|
||||
|
||||
test := []string{"test-cmd", "--load", "current.yaml"}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("top.test")
|
||||
expect(t, val, 15)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "top.test", Value: 7}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func TestCommandYamlFileFlagHasDefaultGlobalEnvYamlSetGlobalEnvWins(t *testing.T) {
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
_ = ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666)
|
||||
defer os.Remove("current.yaml")
|
||||
|
||||
_ = os.Setenv("THE_TEST", "11")
|
||||
defer os.Setenv("THE_TEST", "")
|
||||
|
||||
test := []string{"test-cmd", "--load", "current.yaml"}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("test")
|
||||
expect(t, val, 11)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "test", Value: 7, EnvVars: []string{"THE_TEST"}}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
|
||||
func TestCommandYamlFileFlagHasDefaultGlobalEnvYamlSetGlobalEnvWinsNested(t *testing.T) {
|
||||
app := &cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
_ = ioutil.WriteFile("current.yaml", []byte(`top:
|
||||
test: 15`), 0666)
|
||||
defer os.Remove("current.yaml")
|
||||
|
||||
_ = os.Setenv("THE_TEST", "11")
|
||||
defer os.Setenv("THE_TEST", "")
|
||||
|
||||
test := []string{"test-cmd", "--load", "current.yaml"}
|
||||
_ = set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, nil)
|
||||
|
||||
command := &cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(c *cli.Context) error {
|
||||
val := c.Int("top.test")
|
||||
expect(t, val, 11)
|
||||
return nil
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NewIntFlag(&cli.IntFlag{Name: "top.test", Value: 7, EnvVars: []string{"THE_TEST"}}),
|
||||
&cli.StringFlag{Name: "load"}},
|
||||
}
|
||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||
err := command.Run(c, test...)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
package altsrc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type yamlSourceContext struct {
|
||||
FilePath string
|
||||
}
|
||||
|
||||
// NewYamlSourceFromFile creates a new Yaml InputSourceContext from a filepath.
|
||||
func NewYamlSourceFromFile(file string) (InputSourceContext, error) {
|
||||
ysc := &yamlSourceContext{FilePath: file}
|
||||
var results map[interface{}]interface{}
|
||||
err := readCommandYaml(ysc.FilePath, &results)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to load Yaml file '%s': inner error: \n'%v'", ysc.FilePath, err.Error())
|
||||
}
|
||||
|
||||
return &MapInputSource{file: file, valueMap: results}, nil
|
||||
}
|
||||
|
||||
// NewYamlSourceFromFlagFunc creates a new Yaml InputSourceContext from a provided flag name and source context.
|
||||
func NewYamlSourceFromFlagFunc(flagFileName string) func(cCtx *cli.Context) (InputSourceContext, error) {
|
||||
return func(cCtx *cli.Context) (InputSourceContext, error) {
|
||||
if filePath := cCtx.String(flagFileName); filePath != "" {
|
||||
return NewYamlSourceFromFile(filePath)
|
||||
}
|
||||
return defaultInputSource()
|
||||
}
|
||||
}
|
||||
|
||||
func readCommandYaml(filePath string, container interface{}) (err error) {
|
||||
b, err := loadDataFrom(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = yaml.Unmarshal(b, container)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = nil
|
||||
return
|
||||
}
|
||||
|
||||
func loadDataFrom(filePath string) ([]byte, error) {
|
||||
u, err := url.Parse(filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if u.Host != "" { // i have a host, now do i support the scheme?
|
||||
switch u.Scheme {
|
||||
case "http", "https":
|
||||
res, err := http.Get(filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ioutil.ReadAll(res.Body)
|
||||
default:
|
||||
return nil, fmt.Errorf("scheme of %s is unsupported", filePath)
|
||||
}
|
||||
} else if u.Path != "" { // i dont have a host, but I have a path. I am a local file.
|
||||
if _, notFoundFileErr := os.Stat(filePath); notFoundFileErr != nil {
|
||||
return nil, fmt.Errorf("Cannot read from file: '%s' because it does not exist.", filePath)
|
||||
}
|
||||
return ioutil.ReadFile(filePath)
|
||||
} else if runtime.GOOS == "windows" && strings.Contains(u.String(), "\\") {
|
||||
// on Windows systems u.Path is always empty, so we need to check the string directly.
|
||||
if _, notFoundFileErr := os.Stat(filePath); notFoundFileErr != nil {
|
||||
return nil, fmt.Errorf("Cannot read from file: '%s' because it does not exist.", filePath)
|
||||
}
|
||||
return ioutil.ReadFile(filePath)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unable to determine how to load from path %s", filePath)
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
package altsrc_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
"github.com/urfave/cli/v3/altsrc"
|
||||
)
|
||||
|
||||
func ExampleApp_Run_yamlFileLoaderDuration() {
|
||||
execServe := func(c *cli.Context) error {
|
||||
keepaliveInterval := c.Duration("keepalive-interval")
|
||||
fmt.Printf("keepalive %s\n", keepaliveInterval)
|
||||
return nil
|
||||
}
|
||||
|
||||
fileExists := func(filename string) bool {
|
||||
stat, _ := os.Stat(filename)
|
||||
return stat != nil
|
||||
}
|
||||
|
||||
// initConfigFileInputSource is like altsrc.InitInputSourceWithContext and altsrc.NewYamlSourceFromFlagFunc, but checks
|
||||
// if the config flag is exists and only loads it if it does. If the flag is set and the file exists, it fails.
|
||||
initConfigFileInputSource := func(configFlag string, flags []cli.Flag) cli.BeforeFunc {
|
||||
return func(context *cli.Context) error {
|
||||
configFile := context.String(configFlag)
|
||||
if context.IsSet(configFlag) && !fileExists(configFile) {
|
||||
return fmt.Errorf("config file %s does not exist", configFile)
|
||||
} else if !context.IsSet(configFlag) && !fileExists(configFile) {
|
||||
return nil
|
||||
}
|
||||
inputSource, err := altsrc.NewYamlSourceFromFile(configFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return altsrc.ApplyInputSourceValues(context, inputSource, flags)
|
||||
}
|
||||
}
|
||||
|
||||
flagsServe := []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "config",
|
||||
Aliases: []string{"c"},
|
||||
EnvVars: []string{"CONFIG_FILE"},
|
||||
Value: "../testdata/empty.yml",
|
||||
DefaultText: "../testdata/empty.yml",
|
||||
Usage: "config file",
|
||||
},
|
||||
altsrc.NewDurationFlag(
|
||||
&cli.DurationFlag{
|
||||
Name: "keepalive-interval",
|
||||
Aliases: []string{"k"},
|
||||
EnvVars: []string{"KEEPALIVE_INTERVAL"},
|
||||
Value: 45 * time.Second,
|
||||
Usage: "interval of keepalive messages",
|
||||
},
|
||||
),
|
||||
}
|
||||
|
||||
cmdServe := &cli.Command{
|
||||
Name: "serve",
|
||||
Usage: "Run the server",
|
||||
UsageText: "serve [OPTIONS..]",
|
||||
Action: execServe,
|
||||
Flags: flagsServe,
|
||||
Before: initConfigFileInputSource("config", flagsServe),
|
||||
}
|
||||
|
||||
c := &cli.App{
|
||||
Name: "cmd",
|
||||
HideVersion: true,
|
||||
UseShortOptionHandling: true,
|
||||
Commands: []*cli.Command{
|
||||
cmdServe,
|
||||
},
|
||||
}
|
||||
|
||||
if err := c.Run([]string{"cmd", "serve", "--config", "../testdata/empty.yml"}); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// keepalive 45s
|
||||
}
|
@ -26,4 +26,3 @@ show-cover:
|
||||
.PHONY: run
|
||||
run: build
|
||||
./urfave-cli-genflags
|
||||
./urfave-cli-genflags -f altsrc/flag-spec.yaml -o altsrc/flag_generated.go -p altsrc -a
|
||||
|
@ -2313,358 +2313,3 @@ type VisibleFlagCategory interface {
|
||||
}
|
||||
VisibleFlagCategory is a category containing flags.
|
||||
|
||||
package altsrc // import "github.com/urfave/cli/v3/altsrc"
|
||||
|
||||
|
||||
FUNCTIONS
|
||||
|
||||
func ApplyInputSourceValues(cCtx *cli.Context, inputSourceContext InputSourceContext, flags []cli.Flag) error
|
||||
ApplyInputSourceValues iterates over all provided flags and executes
|
||||
ApplyInputSourceValue on flags implementing the FlagInputSourceExtension
|
||||
interface to initialize these flags to an alternate input source.
|
||||
|
||||
func InitInputSource(flags []cli.Flag, createInputSource func() (InputSourceContext, error)) cli.BeforeFunc
|
||||
InitInputSource is used to to setup an InputSourceContext on a cli.Command
|
||||
Before method. It will create a new input source based on the func provided.
|
||||
If there is no error it will then apply the new input source to any flags
|
||||
that are supported by the input source
|
||||
|
||||
func InitInputSourceWithContext(flags []cli.Flag, createInputSource func(cCtx *cli.Context) (InputSourceContext, error)) cli.BeforeFunc
|
||||
InitInputSourceWithContext is used to to setup an InputSourceContext on
|
||||
a cli.Command Before method. It will create a new input source based on
|
||||
the func provided with potentially using existing cli.Context values to
|
||||
initialize itself. If there is no error it will then apply the new input
|
||||
source to any flags that are supported by the input source
|
||||
|
||||
func NewJSONSourceFromFlagFunc(flag string) func(c *cli.Context) (InputSourceContext, error)
|
||||
NewJSONSourceFromFlagFunc returns a func that takes a cli.Context and
|
||||
returns an InputSourceContext suitable for retrieving config variables from
|
||||
a file containing JSON data with the file name defined by the given flag.
|
||||
|
||||
func NewTomlSourceFromFlagFunc(flagFileName string) func(cCtx *cli.Context) (InputSourceContext, error)
|
||||
NewTomlSourceFromFlagFunc creates a new TOML InputSourceContext from a
|
||||
provided flag name and source context.
|
||||
|
||||
func NewYamlSourceFromFlagFunc(flagFileName string) func(cCtx *cli.Context) (InputSourceContext, error)
|
||||
NewYamlSourceFromFlagFunc creates a new Yaml InputSourceContext from a
|
||||
provided flag name and source context.
|
||||
|
||||
|
||||
TYPES
|
||||
|
||||
type BoolFlag struct {
|
||||
*cli.BoolFlag
|
||||
// Has unexported fields.
|
||||
}
|
||||
BoolFlag is the flag type that wraps cli.BoolFlag to allow for other values
|
||||
to be specified
|
||||
|
||||
func NewBoolFlag(fl *cli.BoolFlag) *BoolFlag
|
||||
NewBoolFlag creates a new BoolFlag
|
||||
|
||||
func (f *BoolFlag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
BoolFlag.Apply
|
||||
|
||||
func (f *BoolFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
|
||||
ApplyInputSourceValue applies a Bool value to the flagSet if required
|
||||
|
||||
type DurationFlag struct {
|
||||
*cli.DurationFlag
|
||||
// Has unexported fields.
|
||||
}
|
||||
DurationFlag is the flag type that wraps cli.DurationFlag to allow for other
|
||||
values to be specified
|
||||
|
||||
func NewDurationFlag(fl *cli.DurationFlag) *DurationFlag
|
||||
NewDurationFlag creates a new DurationFlag
|
||||
|
||||
func (f *DurationFlag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
DurationFlag.Apply
|
||||
|
||||
func (f *DurationFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
|
||||
ApplyInputSourceValue applies a Duration value to the flagSet if required
|
||||
|
||||
type FlagInputSourceExtension interface {
|
||||
cli.Flag
|
||||
ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
|
||||
}
|
||||
FlagInputSourceExtension is an extension interface of cli.Flag that allows a
|
||||
value to be set on the existing parsed flags.
|
||||
|
||||
type Float64Flag struct {
|
||||
*cli.Float64Flag
|
||||
// Has unexported fields.
|
||||
}
|
||||
Float64Flag is the flag type that wraps cli.Float64Flag to allow for other
|
||||
values to be specified
|
||||
|
||||
func NewFloat64Flag(fl *cli.Float64Flag) *Float64Flag
|
||||
NewFloat64Flag creates a new Float64Flag
|
||||
|
||||
func (f *Float64Flag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
Float64Flag.Apply
|
||||
|
||||
func (f *Float64Flag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
|
||||
ApplyInputSourceValue applies a Float64 value to the flagSet if required
|
||||
|
||||
type Float64SliceFlag struct {
|
||||
*cli.Float64SliceFlag
|
||||
// Has unexported fields.
|
||||
}
|
||||
Float64SliceFlag is the flag type that wraps cli.Float64SliceFlag to allow
|
||||
for other values to be specified
|
||||
|
||||
func NewFloat64SliceFlag(fl *cli.Float64SliceFlag) *Float64SliceFlag
|
||||
NewFloat64SliceFlag creates a new Float64SliceFlag
|
||||
|
||||
func (f *Float64SliceFlag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
Float64SliceFlag.Apply
|
||||
|
||||
type GenericFlag struct {
|
||||
*cli.GenericFlag
|
||||
// Has unexported fields.
|
||||
}
|
||||
GenericFlag is the flag type that wraps cli.GenericFlag to allow for other
|
||||
values to be specified
|
||||
|
||||
func NewGenericFlag(fl *cli.GenericFlag) *GenericFlag
|
||||
NewGenericFlag creates a new GenericFlag
|
||||
|
||||
func (f *GenericFlag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
GenericFlag.Apply
|
||||
|
||||
func (f *GenericFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
|
||||
ApplyInputSourceValue applies a generic value to the flagSet if required
|
||||
|
||||
type InputSourceContext interface {
|
||||
Source() string
|
||||
|
||||
Int(name string) (int, error)
|
||||
Duration(name string) (time.Duration, error)
|
||||
Float64(name string) (float64, error)
|
||||
String(name string) (string, error)
|
||||
StringSlice(name string) ([]string, error)
|
||||
IntSlice(name string) ([]int, error)
|
||||
Int64Slice(name string) ([]int64, error)
|
||||
Generic(name string) (cli.Generic, error)
|
||||
Bool(name string) (bool, error)
|
||||
|
||||
// Has unexported methods.
|
||||
}
|
||||
InputSourceContext is an interface used to allow other input sources to be
|
||||
implemented as needed.
|
||||
|
||||
Source returns an identifier for the input source. In case of file source it
|
||||
should return path to the file.
|
||||
|
||||
func NewJSONSource(data []byte) (InputSourceContext, error)
|
||||
NewJSONSource returns an InputSourceContext suitable for retrieving config
|
||||
variables from raw JSON data.
|
||||
|
||||
func NewJSONSourceFromFile(f string) (InputSourceContext, error)
|
||||
NewJSONSourceFromFile returns an InputSourceContext suitable for retrieving
|
||||
config variables from a file (or url) containing JSON data.
|
||||
|
||||
func NewJSONSourceFromReader(r io.Reader) (InputSourceContext, error)
|
||||
NewJSONSourceFromReader returns an InputSourceContext suitable for
|
||||
retrieving config variables from an io.Reader that returns JSON data.
|
||||
|
||||
func NewTomlSourceFromFile(file string) (InputSourceContext, error)
|
||||
NewTomlSourceFromFile creates a new TOML InputSourceContext from a filepath.
|
||||
|
||||
func NewYamlSourceFromFile(file string) (InputSourceContext, error)
|
||||
NewYamlSourceFromFile creates a new Yaml InputSourceContext from a filepath.
|
||||
|
||||
type Int64Flag struct {
|
||||
*cli.Int64Flag
|
||||
// Has unexported fields.
|
||||
}
|
||||
Int64Flag is the flag type that wraps cli.Int64Flag to allow for other
|
||||
values to be specified
|
||||
|
||||
func NewInt64Flag(fl *cli.Int64Flag) *Int64Flag
|
||||
NewInt64Flag creates a new Int64Flag
|
||||
|
||||
func (f *Int64Flag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
Int64Flag.Apply
|
||||
|
||||
type Int64SliceFlag struct {
|
||||
*cli.Int64SliceFlag
|
||||
// Has unexported fields.
|
||||
}
|
||||
Int64SliceFlag is the flag type that wraps cli.Int64SliceFlag to allow for
|
||||
other values to be specified
|
||||
|
||||
func NewInt64SliceFlag(fl *cli.Int64SliceFlag) *Int64SliceFlag
|
||||
NewInt64SliceFlag creates a new Int64SliceFlag
|
||||
|
||||
func (f *Int64SliceFlag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
Int64SliceFlag.Apply
|
||||
|
||||
func (f *Int64SliceFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
|
||||
ApplyInputSourceValue applies a Int64Slice value if required
|
||||
|
||||
type IntFlag struct {
|
||||
*cli.IntFlag
|
||||
// Has unexported fields.
|
||||
}
|
||||
IntFlag is the flag type that wraps cli.IntFlag to allow for other values to
|
||||
be specified
|
||||
|
||||
func NewIntFlag(fl *cli.IntFlag) *IntFlag
|
||||
NewIntFlag creates a new IntFlag
|
||||
|
||||
func (f *IntFlag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
IntFlag.Apply
|
||||
|
||||
func (f *IntFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
|
||||
ApplyInputSourceValue applies a int value to the flagSet if required
|
||||
|
||||
type IntSliceFlag struct {
|
||||
*cli.IntSliceFlag
|
||||
// Has unexported fields.
|
||||
}
|
||||
IntSliceFlag is the flag type that wraps cli.IntSliceFlag to allow for other
|
||||
values to be specified
|
||||
|
||||
func NewIntSliceFlag(fl *cli.IntSliceFlag) *IntSliceFlag
|
||||
NewIntSliceFlag creates a new IntSliceFlag
|
||||
|
||||
func (f *IntSliceFlag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
IntSliceFlag.Apply
|
||||
|
||||
func (f *IntSliceFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
|
||||
ApplyInputSourceValue applies a IntSlice value if required
|
||||
|
||||
type MapInputSource struct {
|
||||
// Has unexported fields.
|
||||
}
|
||||
MapInputSource implements InputSourceContext to return data from the map
|
||||
that is loaded.
|
||||
|
||||
func NewMapInputSource(file string, valueMap map[interface{}]interface{}) *MapInputSource
|
||||
NewMapInputSource creates a new MapInputSource for implementing custom input
|
||||
sources.
|
||||
|
||||
func (fsm *MapInputSource) Bool(name string) (bool, error)
|
||||
Bool returns an bool from the map otherwise returns false
|
||||
|
||||
func (fsm *MapInputSource) Duration(name string) (time.Duration, error)
|
||||
Duration returns a duration from the map if it exists otherwise returns 0
|
||||
|
||||
func (fsm *MapInputSource) Float64(name string) (float64, error)
|
||||
Float64 returns an float64 from the map if it exists otherwise returns 0
|
||||
|
||||
func (fsm *MapInputSource) Generic(name string) (cli.Generic, error)
|
||||
Generic returns an cli.Generic from the map if it exists otherwise returns
|
||||
nil
|
||||
|
||||
func (fsm *MapInputSource) Int(name string) (int, error)
|
||||
Int returns an int from the map if it exists otherwise returns 0
|
||||
|
||||
func (fsm *MapInputSource) Int64Slice(name string) ([]int64, error)
|
||||
Int64Slice returns an []int64 from the map if it exists otherwise returns
|
||||
nil
|
||||
|
||||
func (fsm *MapInputSource) IntSlice(name string) ([]int, error)
|
||||
IntSlice returns an []int from the map if it exists otherwise returns nil
|
||||
|
||||
func (fsm *MapInputSource) Source() string
|
||||
Source returns the path of the source file
|
||||
|
||||
func (fsm *MapInputSource) String(name string) (string, error)
|
||||
String returns a string from the map if it exists otherwise returns an empty
|
||||
string
|
||||
|
||||
func (fsm *MapInputSource) StringSlice(name string) ([]string, error)
|
||||
StringSlice returns an []string from the map if it exists otherwise returns
|
||||
nil
|
||||
|
||||
type PathFlag struct {
|
||||
*cli.PathFlag
|
||||
// Has unexported fields.
|
||||
}
|
||||
PathFlag is the flag type that wraps cli.PathFlag to allow for other values
|
||||
to be specified
|
||||
|
||||
func NewPathFlag(fl *cli.PathFlag) *PathFlag
|
||||
NewPathFlag creates a new PathFlag
|
||||
|
||||
func (f *PathFlag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
PathFlag.Apply
|
||||
|
||||
func (f *PathFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
|
||||
ApplyInputSourceValue applies a Path value to the flagSet if required
|
||||
|
||||
type StringFlag struct {
|
||||
*cli.StringFlag
|
||||
// Has unexported fields.
|
||||
}
|
||||
StringFlag is the flag type that wraps cli.StringFlag to allow for other
|
||||
values to be specified
|
||||
|
||||
func NewStringFlag(fl *cli.StringFlag) *StringFlag
|
||||
NewStringFlag creates a new StringFlag
|
||||
|
||||
func (f *StringFlag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
StringFlag.Apply
|
||||
|
||||
func (f *StringFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
|
||||
ApplyInputSourceValue applies a String value to the flagSet if required
|
||||
|
||||
type StringSliceFlag struct {
|
||||
*cli.StringSliceFlag
|
||||
// Has unexported fields.
|
||||
}
|
||||
StringSliceFlag is the flag type that wraps cli.StringSliceFlag to allow for
|
||||
other values to be specified
|
||||
|
||||
func NewStringSliceFlag(fl *cli.StringSliceFlag) *StringSliceFlag
|
||||
NewStringSliceFlag creates a new StringSliceFlag
|
||||
|
||||
func (f *StringSliceFlag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
StringSliceFlag.Apply
|
||||
|
||||
func (f *StringSliceFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
|
||||
ApplyInputSourceValue applies a StringSlice value to the flagSet if required
|
||||
|
||||
type Uint64Flag struct {
|
||||
*cli.Uint64Flag
|
||||
// Has unexported fields.
|
||||
}
|
||||
Uint64Flag is the flag type that wraps cli.Uint64Flag to allow for other
|
||||
values to be specified
|
||||
|
||||
func NewUint64Flag(fl *cli.Uint64Flag) *Uint64Flag
|
||||
NewUint64Flag creates a new Uint64Flag
|
||||
|
||||
func (f *Uint64Flag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
Uint64Flag.Apply
|
||||
|
||||
type UintFlag struct {
|
||||
*cli.UintFlag
|
||||
// Has unexported fields.
|
||||
}
|
||||
UintFlag is the flag type that wraps cli.UintFlag to allow for other values
|
||||
to be specified
|
||||
|
||||
func NewUintFlag(fl *cli.UintFlag) *UintFlag
|
||||
NewUintFlag creates a new UintFlag
|
||||
|
||||
func (f *UintFlag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
UintFlag.Apply
|
||||
|
||||
|
@ -155,7 +155,7 @@ func main() {
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "packages",
|
||||
Value: cli.NewStringSlice("cli", "altsrc", "internal/build"),
|
||||
Value: cli.NewStringSlice("cli", "internal/build"),
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -500,14 +500,9 @@ func GenerateActionFunc(cCtx *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
altsrcDocs, err := sh("go", "doc", "-all", filepath.Join(top, "altsrc"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.WriteFile(
|
||||
filepath.Join(top, "godoc-current.txt"),
|
||||
[]byte(cliDocs+altsrcDocs),
|
||||
[]byte(cliDocs),
|
||||
0644,
|
||||
); err != nil {
|
||||
return err
|
||||
|
355
testdata/godoc-v3.x.txt
vendored
355
testdata/godoc-v3.x.txt
vendored
@ -2313,358 +2313,3 @@ type VisibleFlagCategory interface {
|
||||
}
|
||||
VisibleFlagCategory is a category containing flags.
|
||||
|
||||
package altsrc // import "github.com/urfave/cli/v3/altsrc"
|
||||
|
||||
|
||||
FUNCTIONS
|
||||
|
||||
func ApplyInputSourceValues(cCtx *cli.Context, inputSourceContext InputSourceContext, flags []cli.Flag) error
|
||||
ApplyInputSourceValues iterates over all provided flags and executes
|
||||
ApplyInputSourceValue on flags implementing the FlagInputSourceExtension
|
||||
interface to initialize these flags to an alternate input source.
|
||||
|
||||
func InitInputSource(flags []cli.Flag, createInputSource func() (InputSourceContext, error)) cli.BeforeFunc
|
||||
InitInputSource is used to to setup an InputSourceContext on a cli.Command
|
||||
Before method. It will create a new input source based on the func provided.
|
||||
If there is no error it will then apply the new input source to any flags
|
||||
that are supported by the input source
|
||||
|
||||
func InitInputSourceWithContext(flags []cli.Flag, createInputSource func(cCtx *cli.Context) (InputSourceContext, error)) cli.BeforeFunc
|
||||
InitInputSourceWithContext is used to to setup an InputSourceContext on
|
||||
a cli.Command Before method. It will create a new input source based on
|
||||
the func provided with potentially using existing cli.Context values to
|
||||
initialize itself. If there is no error it will then apply the new input
|
||||
source to any flags that are supported by the input source
|
||||
|
||||
func NewJSONSourceFromFlagFunc(flag string) func(c *cli.Context) (InputSourceContext, error)
|
||||
NewJSONSourceFromFlagFunc returns a func that takes a cli.Context and
|
||||
returns an InputSourceContext suitable for retrieving config variables from
|
||||
a file containing JSON data with the file name defined by the given flag.
|
||||
|
||||
func NewTomlSourceFromFlagFunc(flagFileName string) func(cCtx *cli.Context) (InputSourceContext, error)
|
||||
NewTomlSourceFromFlagFunc creates a new TOML InputSourceContext from a
|
||||
provided flag name and source context.
|
||||
|
||||
func NewYamlSourceFromFlagFunc(flagFileName string) func(cCtx *cli.Context) (InputSourceContext, error)
|
||||
NewYamlSourceFromFlagFunc creates a new Yaml InputSourceContext from a
|
||||
provided flag name and source context.
|
||||
|
||||
|
||||
TYPES
|
||||
|
||||
type BoolFlag struct {
|
||||
*cli.BoolFlag
|
||||
// Has unexported fields.
|
||||
}
|
||||
BoolFlag is the flag type that wraps cli.BoolFlag to allow for other values
|
||||
to be specified
|
||||
|
||||
func NewBoolFlag(fl *cli.BoolFlag) *BoolFlag
|
||||
NewBoolFlag creates a new BoolFlag
|
||||
|
||||
func (f *BoolFlag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
BoolFlag.Apply
|
||||
|
||||
func (f *BoolFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
|
||||
ApplyInputSourceValue applies a Bool value to the flagSet if required
|
||||
|
||||
type DurationFlag struct {
|
||||
*cli.DurationFlag
|
||||
// Has unexported fields.
|
||||
}
|
||||
DurationFlag is the flag type that wraps cli.DurationFlag to allow for other
|
||||
values to be specified
|
||||
|
||||
func NewDurationFlag(fl *cli.DurationFlag) *DurationFlag
|
||||
NewDurationFlag creates a new DurationFlag
|
||||
|
||||
func (f *DurationFlag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
DurationFlag.Apply
|
||||
|
||||
func (f *DurationFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
|
||||
ApplyInputSourceValue applies a Duration value to the flagSet if required
|
||||
|
||||
type FlagInputSourceExtension interface {
|
||||
cli.Flag
|
||||
ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
|
||||
}
|
||||
FlagInputSourceExtension is an extension interface of cli.Flag that allows a
|
||||
value to be set on the existing parsed flags.
|
||||
|
||||
type Float64Flag struct {
|
||||
*cli.Float64Flag
|
||||
// Has unexported fields.
|
||||
}
|
||||
Float64Flag is the flag type that wraps cli.Float64Flag to allow for other
|
||||
values to be specified
|
||||
|
||||
func NewFloat64Flag(fl *cli.Float64Flag) *Float64Flag
|
||||
NewFloat64Flag creates a new Float64Flag
|
||||
|
||||
func (f *Float64Flag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
Float64Flag.Apply
|
||||
|
||||
func (f *Float64Flag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
|
||||
ApplyInputSourceValue applies a Float64 value to the flagSet if required
|
||||
|
||||
type Float64SliceFlag struct {
|
||||
*cli.Float64SliceFlag
|
||||
// Has unexported fields.
|
||||
}
|
||||
Float64SliceFlag is the flag type that wraps cli.Float64SliceFlag to allow
|
||||
for other values to be specified
|
||||
|
||||
func NewFloat64SliceFlag(fl *cli.Float64SliceFlag) *Float64SliceFlag
|
||||
NewFloat64SliceFlag creates a new Float64SliceFlag
|
||||
|
||||
func (f *Float64SliceFlag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
Float64SliceFlag.Apply
|
||||
|
||||
type GenericFlag struct {
|
||||
*cli.GenericFlag
|
||||
// Has unexported fields.
|
||||
}
|
||||
GenericFlag is the flag type that wraps cli.GenericFlag to allow for other
|
||||
values to be specified
|
||||
|
||||
func NewGenericFlag(fl *cli.GenericFlag) *GenericFlag
|
||||
NewGenericFlag creates a new GenericFlag
|
||||
|
||||
func (f *GenericFlag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
GenericFlag.Apply
|
||||
|
||||
func (f *GenericFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
|
||||
ApplyInputSourceValue applies a generic value to the flagSet if required
|
||||
|
||||
type InputSourceContext interface {
|
||||
Source() string
|
||||
|
||||
Int(name string) (int, error)
|
||||
Duration(name string) (time.Duration, error)
|
||||
Float64(name string) (float64, error)
|
||||
String(name string) (string, error)
|
||||
StringSlice(name string) ([]string, error)
|
||||
IntSlice(name string) ([]int, error)
|
||||
Int64Slice(name string) ([]int64, error)
|
||||
Generic(name string) (cli.Generic, error)
|
||||
Bool(name string) (bool, error)
|
||||
|
||||
// Has unexported methods.
|
||||
}
|
||||
InputSourceContext is an interface used to allow other input sources to be
|
||||
implemented as needed.
|
||||
|
||||
Source returns an identifier for the input source. In case of file source it
|
||||
should return path to the file.
|
||||
|
||||
func NewJSONSource(data []byte) (InputSourceContext, error)
|
||||
NewJSONSource returns an InputSourceContext suitable for retrieving config
|
||||
variables from raw JSON data.
|
||||
|
||||
func NewJSONSourceFromFile(f string) (InputSourceContext, error)
|
||||
NewJSONSourceFromFile returns an InputSourceContext suitable for retrieving
|
||||
config variables from a file (or url) containing JSON data.
|
||||
|
||||
func NewJSONSourceFromReader(r io.Reader) (InputSourceContext, error)
|
||||
NewJSONSourceFromReader returns an InputSourceContext suitable for
|
||||
retrieving config variables from an io.Reader that returns JSON data.
|
||||
|
||||
func NewTomlSourceFromFile(file string) (InputSourceContext, error)
|
||||
NewTomlSourceFromFile creates a new TOML InputSourceContext from a filepath.
|
||||
|
||||
func NewYamlSourceFromFile(file string) (InputSourceContext, error)
|
||||
NewYamlSourceFromFile creates a new Yaml InputSourceContext from a filepath.
|
||||
|
||||
type Int64Flag struct {
|
||||
*cli.Int64Flag
|
||||
// Has unexported fields.
|
||||
}
|
||||
Int64Flag is the flag type that wraps cli.Int64Flag to allow for other
|
||||
values to be specified
|
||||
|
||||
func NewInt64Flag(fl *cli.Int64Flag) *Int64Flag
|
||||
NewInt64Flag creates a new Int64Flag
|
||||
|
||||
func (f *Int64Flag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
Int64Flag.Apply
|
||||
|
||||
type Int64SliceFlag struct {
|
||||
*cli.Int64SliceFlag
|
||||
// Has unexported fields.
|
||||
}
|
||||
Int64SliceFlag is the flag type that wraps cli.Int64SliceFlag to allow for
|
||||
other values to be specified
|
||||
|
||||
func NewInt64SliceFlag(fl *cli.Int64SliceFlag) *Int64SliceFlag
|
||||
NewInt64SliceFlag creates a new Int64SliceFlag
|
||||
|
||||
func (f *Int64SliceFlag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
Int64SliceFlag.Apply
|
||||
|
||||
func (f *Int64SliceFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
|
||||
ApplyInputSourceValue applies a Int64Slice value if required
|
||||
|
||||
type IntFlag struct {
|
||||
*cli.IntFlag
|
||||
// Has unexported fields.
|
||||
}
|
||||
IntFlag is the flag type that wraps cli.IntFlag to allow for other values to
|
||||
be specified
|
||||
|
||||
func NewIntFlag(fl *cli.IntFlag) *IntFlag
|
||||
NewIntFlag creates a new IntFlag
|
||||
|
||||
func (f *IntFlag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
IntFlag.Apply
|
||||
|
||||
func (f *IntFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
|
||||
ApplyInputSourceValue applies a int value to the flagSet if required
|
||||
|
||||
type IntSliceFlag struct {
|
||||
*cli.IntSliceFlag
|
||||
// Has unexported fields.
|
||||
}
|
||||
IntSliceFlag is the flag type that wraps cli.IntSliceFlag to allow for other
|
||||
values to be specified
|
||||
|
||||
func NewIntSliceFlag(fl *cli.IntSliceFlag) *IntSliceFlag
|
||||
NewIntSliceFlag creates a new IntSliceFlag
|
||||
|
||||
func (f *IntSliceFlag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
IntSliceFlag.Apply
|
||||
|
||||
func (f *IntSliceFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
|
||||
ApplyInputSourceValue applies a IntSlice value if required
|
||||
|
||||
type MapInputSource struct {
|
||||
// Has unexported fields.
|
||||
}
|
||||
MapInputSource implements InputSourceContext to return data from the map
|
||||
that is loaded.
|
||||
|
||||
func NewMapInputSource(file string, valueMap map[interface{}]interface{}) *MapInputSource
|
||||
NewMapInputSource creates a new MapInputSource for implementing custom input
|
||||
sources.
|
||||
|
||||
func (fsm *MapInputSource) Bool(name string) (bool, error)
|
||||
Bool returns an bool from the map otherwise returns false
|
||||
|
||||
func (fsm *MapInputSource) Duration(name string) (time.Duration, error)
|
||||
Duration returns a duration from the map if it exists otherwise returns 0
|
||||
|
||||
func (fsm *MapInputSource) Float64(name string) (float64, error)
|
||||
Float64 returns an float64 from the map if it exists otherwise returns 0
|
||||
|
||||
func (fsm *MapInputSource) Generic(name string) (cli.Generic, error)
|
||||
Generic returns an cli.Generic from the map if it exists otherwise returns
|
||||
nil
|
||||
|
||||
func (fsm *MapInputSource) Int(name string) (int, error)
|
||||
Int returns an int from the map if it exists otherwise returns 0
|
||||
|
||||
func (fsm *MapInputSource) Int64Slice(name string) ([]int64, error)
|
||||
Int64Slice returns an []int64 from the map if it exists otherwise returns
|
||||
nil
|
||||
|
||||
func (fsm *MapInputSource) IntSlice(name string) ([]int, error)
|
||||
IntSlice returns an []int from the map if it exists otherwise returns nil
|
||||
|
||||
func (fsm *MapInputSource) Source() string
|
||||
Source returns the path of the source file
|
||||
|
||||
func (fsm *MapInputSource) String(name string) (string, error)
|
||||
String returns a string from the map if it exists otherwise returns an empty
|
||||
string
|
||||
|
||||
func (fsm *MapInputSource) StringSlice(name string) ([]string, error)
|
||||
StringSlice returns an []string from the map if it exists otherwise returns
|
||||
nil
|
||||
|
||||
type PathFlag struct {
|
||||
*cli.PathFlag
|
||||
// Has unexported fields.
|
||||
}
|
||||
PathFlag is the flag type that wraps cli.PathFlag to allow for other values
|
||||
to be specified
|
||||
|
||||
func NewPathFlag(fl *cli.PathFlag) *PathFlag
|
||||
NewPathFlag creates a new PathFlag
|
||||
|
||||
func (f *PathFlag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
PathFlag.Apply
|
||||
|
||||
func (f *PathFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
|
||||
ApplyInputSourceValue applies a Path value to the flagSet if required
|
||||
|
||||
type StringFlag struct {
|
||||
*cli.StringFlag
|
||||
// Has unexported fields.
|
||||
}
|
||||
StringFlag is the flag type that wraps cli.StringFlag to allow for other
|
||||
values to be specified
|
||||
|
||||
func NewStringFlag(fl *cli.StringFlag) *StringFlag
|
||||
NewStringFlag creates a new StringFlag
|
||||
|
||||
func (f *StringFlag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
StringFlag.Apply
|
||||
|
||||
func (f *StringFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
|
||||
ApplyInputSourceValue applies a String value to the flagSet if required
|
||||
|
||||
type StringSliceFlag struct {
|
||||
*cli.StringSliceFlag
|
||||
// Has unexported fields.
|
||||
}
|
||||
StringSliceFlag is the flag type that wraps cli.StringSliceFlag to allow for
|
||||
other values to be specified
|
||||
|
||||
func NewStringSliceFlag(fl *cli.StringSliceFlag) *StringSliceFlag
|
||||
NewStringSliceFlag creates a new StringSliceFlag
|
||||
|
||||
func (f *StringSliceFlag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
StringSliceFlag.Apply
|
||||
|
||||
func (f *StringSliceFlag) ApplyInputSourceValue(cCtx *cli.Context, isc InputSourceContext) error
|
||||
ApplyInputSourceValue applies a StringSlice value to the flagSet if required
|
||||
|
||||
type Uint64Flag struct {
|
||||
*cli.Uint64Flag
|
||||
// Has unexported fields.
|
||||
}
|
||||
Uint64Flag is the flag type that wraps cli.Uint64Flag to allow for other
|
||||
values to be specified
|
||||
|
||||
func NewUint64Flag(fl *cli.Uint64Flag) *Uint64Flag
|
||||
NewUint64Flag creates a new Uint64Flag
|
||||
|
||||
func (f *Uint64Flag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
Uint64Flag.Apply
|
||||
|
||||
type UintFlag struct {
|
||||
*cli.UintFlag
|
||||
// Has unexported fields.
|
||||
}
|
||||
UintFlag is the flag type that wraps cli.UintFlag to allow for other values
|
||||
to be specified
|
||||
|
||||
func NewUintFlag(fl *cli.UintFlag) *UintFlag
|
||||
NewUintFlag creates a new UintFlag
|
||||
|
||||
func (f *UintFlag) Apply(set *flag.FlagSet) error
|
||||
Apply saves the flagSet for later usage calls, then calls the wrapped
|
||||
UintFlag.Apply
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user