Compare commits

...

7 Commits

Author SHA1 Message Date
689dfd65e8
Merge pull request #1579 from urfave/drop-compiled
Remove App.Compiled
2022-11-09 20:39:19 -05:00
a05e4d0982
Remove App.Compiled
Closes #753
2022-11-08 19:13:31 -05:00
02bba4b62e
Merge pull request #1576 from urfave/extern-altsrc
Remove local altsrc and references
2022-11-08 19:04:52 -05:00
12f4cba9a5
Merge branch 'main' into extern-altsrc 2022-11-08 17:59:18 -05:00
dbdd5cbc35
Merge pull request #1575 from urfave/gha-v3-mode
Update GitHub Actions events for v3 mode
2022-11-08 17:59:05 -05:00
9361cba851
Remove local altsrc and references
in favor of separate repo at https://github.com/urfave/cli-altsrc
2022-11-08 16:27:46 -05:00
5133e28f43
Update GitHub Actions events for v3 mode 2022-11-08 15:46:42 -05:00
22 changed files with 2 additions and 3979 deletions

View File

@ -3,14 +3,11 @@ on:
push:
branches:
- main
- v3-dev-main
tags:
- v2.*
- v3.*
pull_request:
branches:
- main
- v3-dev-main
permissions:
contents: read
jobs:

View File

@ -1,6 +0,0 @@
package altsrc
// defaultInputSource creates a default InputSourceContext.
func defaultInputSource() (InputSourceContext, error) {
return &MapInputSource{file: "", valueMap: map[interface{}]interface{}{}}, nil
}

View File

@ -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:

View File

@ -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)
}

View File

@ -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

View File

@ -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

View File

@ -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))
}
}

View File

@ -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
}

View File

@ -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)
}
}
}

View File

@ -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{}
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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
}

18
app.go
View File

@ -9,7 +9,6 @@ import (
"path/filepath"
"sort"
"strings"
"time"
)
const suggestDidYouMeanTemplate = "Did you mean %q?"
@ -81,8 +80,6 @@ type App struct {
OnUsageError OnUsageErrorFunc
// Execute this function when an invalid flag is accessed from the context
InvalidFlagAccessHandler InvalidFlagAccessFunc
// Compilation date
Compiled time.Time
// List of all authors who contributed
Authors []*Author
// Copyright of the binary if any
@ -128,16 +125,6 @@ type SuggestFlagFunc func(flags []Flag, provided string, hideHelp bool) string
type SuggestCommandFunc func(commands []*Command, provided string) string
// Tries to find out when this binary was compiled.
// Returns the current time if it fails to find it.
func compileTime() time.Time {
info, err := os.Stat(os.Args[0])
if err != nil {
return time.Now()
}
return info.ModTime()
}
// NewApp creates a new cli Application with some reasonable defaults for Name,
// Usage, Version and Action.
func NewApp() *App {
@ -147,7 +134,6 @@ func NewApp() *App {
UsageText: "",
BashComplete: DefaultAppComplete,
Action: helpCommand.Action,
Compiled: compileTime(),
Reader: os.Stdin,
Writer: os.Stdout,
ErrWriter: os.Stderr,
@ -188,10 +174,6 @@ func (a *App) Setup() {
a.Action = helpCommand.Action
}
if a.Compiled == (time.Time{}) {
a.Compiled = compileTime()
}
if a.Reader == nil {
a.Reader = os.Stdin
}

View File

@ -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

View File

@ -292,8 +292,6 @@ type App struct {
OnUsageError OnUsageErrorFunc
// Execute this function when an invalid flag is accessed from the context
InvalidFlagAccessHandler InvalidFlagAccessFunc
// Compilation date
Compiled time.Time
// List of all authors who contributed
Authors []*Author
// Copyright of the binary if any
@ -2313,358 +2311,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

View File

@ -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

View File

@ -292,8 +292,6 @@ type App struct {
OnUsageError OnUsageErrorFunc
// Execute this function when an invalid flag is accessed from the context
InvalidFlagAccessHandler InvalidFlagAccessFunc
// Compilation date
Compiled time.Time
// List of all authors who contributed
Authors []*Author
// Copyright of the binary if any
@ -2313,358 +2311,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