Merge branch 'master' into ally_fix_default_val

main
Robert Liebowitz 3 years ago
commit ab52d6f3a9

1
.github/stale.yml vendored

@ -14,6 +14,7 @@ onlyLabels: []
exemptLabels:
- pinned
- security
- "help wanted"
- "kind/maintenance"
# Set to true to ignore issues in a project (defaults to false)

@ -15,7 +15,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
go: [1.13, 1.14, 1.15]
go: [1.14, 1.15, 1.16]
name: ${{ matrix.os }} @ Go ${{ matrix.go }}
runs-on: ${{ matrix.os }}
steps:
@ -38,7 +38,7 @@ jobs:
ref: ${{ github.ref }}
- name: GOFMT Check
if: matrix.go == 1.15 && matrix.os == 'ubuntu-latest'
if: matrix.go == 1.16 && matrix.os == 'ubuntu-latest'
run: test -z $(gofmt -l .)
- name: vet
@ -51,19 +51,19 @@ jobs:
run: go run internal/build/build.go check-binary-size
- name: Upload coverage to Codecov
if: success() && matrix.go == 1.14 && matrix.os == 'ubuntu-latest'
if: success() && matrix.go == 1.16 && matrix.os == 'ubuntu-latest'
uses: codecov/codecov-action@v1
with:
token: 0a8cc73b-bb7c-480b-8626-38a461643761
fail_ci_if_error: true
test-docs:
name: test-docs
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.15
- name: Set up Go
uses: actions/setup-go@v1
with:
# Currently fails on 1.16
go-version: 1.15
- name: Use Node.js 12.x

@ -278,7 +278,7 @@ func (a *App) RunContext(ctx context.Context, arguments []string) (err error) {
return nil
}
cerr := checkRequiredFlags(a.Flags, context)
cerr := context.checkRequiredFlags(a.Flags)
if cerr != nil {
_ = ShowAppHelp(context)
return cerr
@ -397,7 +397,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
}
}
cerr := checkRequiredFlags(a.Flags, context)
cerr := context.checkRequiredFlags(a.Flags)
if cerr != nil {
_ = ShowSubcommandHelp(context)
return cerr

@ -127,7 +127,7 @@ func (c *Command) Run(ctx *Context) (err error) {
return nil
}
cerr := checkRequiredFlags(c.Flags, context)
cerr := context.checkRequiredFlags(c.Flags)
if cerr != nil {
_ = ShowCommandHelp(context, c.Name)
return cerr
@ -227,6 +227,7 @@ func (c *Command) startApp(ctx *Context) error {
}
app.Usage = c.Usage
app.UsageText = c.UsageText
app.Description = c.Description
app.ArgsUsage = c.ArgsUsage

@ -2,9 +2,7 @@ package cli
import (
"context"
"errors"
"flag"
"fmt"
"strings"
)
@ -53,20 +51,18 @@ func (c *Context) Set(name, value string) error {
// IsSet determines if the flag was actually set
func (c *Context) IsSet(name string) bool {
if fs := lookupFlagSet(name, c); fs != nil {
if fs := lookupFlagSet(name, c); fs != nil {
isSet := false
fs.Visit(func(f *flag.Flag) {
if f.Name == name {
isSet = true
}
})
if isSet {
return true
if fs := c.lookupFlagSet(name); fs != nil {
isSet := false
fs.Visit(func(f *flag.Flag) {
if f.Name == name {
isSet = true
}
})
if isSet {
return true
}
f := lookupFlag(name, c)
f := c.lookupFlag(name)
if f == nil {
return false
}
@ -108,7 +104,7 @@ func (c *Context) Lineage() []*Context {
// Value returns the value of the flag corresponding to `name`
func (c *Context) Value(name string) interface{} {
if fs := lookupFlagSet(name, c); fs != nil {
if fs := c.lookupFlagSet(name); fs != nil {
return fs.Lookup(name).Value.(flag.Getter).Get()
}
return nil
@ -125,7 +121,7 @@ func (c *Context) NArg() int {
return c.Args().Len()
}
func lookupFlag(name string, ctx *Context) Flag {
func (ctx *Context) lookupFlag(name string) Flag {
for _, c := range ctx.Lineage() {
if c.Command == nil {
continue
@ -153,7 +149,7 @@ func lookupFlag(name string, ctx *Context) Flag {
return nil
}
func lookupFlagSet(name string, ctx *Context) *flag.FlagSet {
func (ctx *Context) lookupFlagSet(name string) *flag.FlagSet {
for _, c := range ctx.Lineage() {
if f := c.flagSet.Lookup(name); f != nil {
return c.flagSet
@ -163,89 +159,7 @@ func lookupFlagSet(name string, ctx *Context) *flag.FlagSet {
return nil
}
func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) {
switch ff.Value.(type) {
case Serializer:
_ = set.Set(name, ff.Value.(Serializer).Serialize())
default:
_ = set.Set(name, ff.Value.String())
}
}
func normalizeFlags(flags []Flag, set *flag.FlagSet) error {
visited := make(map[string]bool)
set.Visit(func(f *flag.Flag) {
visited[f.Name] = true
})
for _, f := range flags {
parts := f.Names()
if len(parts) == 1 {
continue
}
var ff *flag.Flag
for _, name := range parts {
name = strings.Trim(name, " ")
if visited[name] {
if ff != nil {
return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name)
}
ff = set.Lookup(name)
}
}
if ff == nil {
continue
}
for _, name := range parts {
name = strings.Trim(name, " ")
if !visited[name] {
copyFlag(name, ff, set)
}
}
}
return nil
}
func makeFlagNameVisitor(names *[]string) func(*flag.Flag) {
return func(f *flag.Flag) {
nameParts := strings.Split(f.Name, ",")
name := strings.TrimSpace(nameParts[0])
for _, part := range nameParts {
part = strings.TrimSpace(part)
if len(part) > len(name) {
name = part
}
}
if name != "" {
*names = append(*names, name)
}
}
}
type requiredFlagsErr interface {
error
getMissingFlags() []string
}
type errRequiredFlags struct {
missingFlags []string
}
func (e *errRequiredFlags) Error() string {
numberOfMissingFlags := len(e.missingFlags)
if numberOfMissingFlags == 1 {
return fmt.Sprintf("Required flag %q not set", e.missingFlags[0])
}
joinedMissingFlags := strings.Join(e.missingFlags, ", ")
return fmt.Sprintf("Required flags %q not set", joinedMissingFlags)
}
func (e *errRequiredFlags) getMissingFlags() []string {
return e.missingFlags
}
func checkRequiredFlags(flags []Flag, context *Context) requiredFlagsErr {
func (context *Context) checkRequiredFlags(flags []Flag) requiredFlagsErr {
var missingFlags []string
for _, f := range flags {
if rf, ok := f.(RequiredFlag); ok && rf.IsRequired() {
@ -274,3 +188,21 @@ func checkRequiredFlags(flags []Flag, context *Context) requiredFlagsErr {
return nil
}
func makeFlagNameVisitor(names *[]string) func(*flag.Flag) {
return func(f *flag.Flag) {
nameParts := strings.Split(f.Name, ",")
name := strings.TrimSpace(nameParts[0])
for _, part := range nameParts {
part = strings.TrimSpace(part)
if len(part) > len(name) {
name = part
}
}
if name != "" {
*names = append(*names, name)
}
}
}

@ -316,13 +316,13 @@ func TestContext_lookupFlagSet(t *testing.T) {
_ = set.Parse([]string{"--local-flag"})
_ = parentSet.Parse([]string{"--top-flag"})
fs := lookupFlagSet("top-flag", ctx)
fs := ctx.lookupFlagSet("top-flag")
expect(t, fs, parentCtx.flagSet)
fs = lookupFlagSet("local-flag", ctx)
fs = ctx.lookupFlagSet("local-flag")
expect(t, fs, ctx.flagSet)
if fs := lookupFlagSet("frob", ctx); fs != nil {
if fs := ctx.lookupFlagSet("frob"); fs != nil {
t.Fail()
}
}
@ -576,7 +576,7 @@ func TestCheckRequiredFlags(t *testing.T) {
ctx.Command.Flags = test.flags
// logic under test
err := checkRequiredFlags(test.flags, ctx)
err := ctx.checkRequiredFlags(test.flags)
// assertions
if test.expectedAnError && err == nil {

@ -47,6 +47,28 @@ func (m *multiError) Errors() []error {
return errs
}
type requiredFlagsErr interface {
error
getMissingFlags() []string
}
type errRequiredFlags struct {
missingFlags []string
}
func (e *errRequiredFlags) Error() string {
numberOfMissingFlags := len(e.missingFlags)
if numberOfMissingFlags == 1 {
return fmt.Sprintf("Required flag %q not set", e.missingFlags[0])
}
joinedMissingFlags := strings.Join(e.missingFlags, ", ")
return fmt.Sprintf("Required flags %q not set", joinedMissingFlags)
}
func (e *errRequiredFlags) getMissingFlags() []string {
return e.missingFlags
}
// ErrorFormatter is the interface that will suitably format the error output
type ErrorFormatter interface {
Format(s fmt.State, verb rune)

@ -1,6 +1,7 @@
package cli
import (
"errors"
"flag"
"fmt"
"io/ioutil"
@ -130,6 +131,48 @@ func flagSet(name string, flags []Flag) (*flag.FlagSet, error) {
return set, nil
}
func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) {
switch ff.Value.(type) {
case Serializer:
_ = set.Set(name, ff.Value.(Serializer).Serialize())
default:
_ = set.Set(name, ff.Value.String())
}
}
func normalizeFlags(flags []Flag, set *flag.FlagSet) error {
visited := make(map[string]bool)
set.Visit(func(f *flag.Flag) {
visited[f.Name] = true
})
for _, f := range flags {
parts := f.Names()
if len(parts) == 1 {
continue
}
var ff *flag.Flag
for _, name := range parts {
name = strings.Trim(name, " ")
if visited[name] {
if ff != nil {
return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name)
}
ff = set.Lookup(name)
}
}
if ff == nil {
continue
}
for _, name := range parts {
name = strings.Trim(name, " ")
if !visited[name] {
copyFlag(name, ff, set)
}
}
}
return nil
}
func visibleFlags(fl []Flag) []Flag {
var visible []Flag
for _, f := range fl {

@ -87,7 +87,7 @@ func (f *BoolFlag) Apply(set *flag.FlagSet) error {
// Bool looks up the value of a local BoolFlag, returns
// false if not found
func (c *Context) Bool(name string) bool {
if fs := lookupFlagSet(name, c); fs != nil {
if fs := c.lookupFlagSet(name); fs != nil {
return lookupBool(name, fs)
}
return false

@ -86,7 +86,7 @@ func (f *DurationFlag) Apply(set *flag.FlagSet) error {
// Duration looks up the value of a local DurationFlag, returns
// 0 if not found
func (c *Context) Duration(name string) time.Duration {
if fs := lookupFlagSet(name, c); fs != nil {
if fs := c.lookupFlagSet(name); fs != nil {
return lookupDuration(name, fs)
}
return 0

@ -87,7 +87,7 @@ func (f *Float64Flag) Apply(set *flag.FlagSet) error {
// Float64 looks up the value of a local Float64Flag, returns
// 0 if not found
func (c *Context) Float64(name string) float64 {
if fs := lookupFlagSet(name, c); fs != nil {
if fs := c.lookupFlagSet(name); fs != nil {
return lookupFloat64(name, fs)
}
return 0

@ -157,7 +157,7 @@ func (f *Float64SliceFlag) Apply(set *flag.FlagSet) error {
// Float64Slice looks up the value of a local Float64SliceFlag, returns
// nil if not found
func (c *Context) Float64Slice(name string) []float64 {
if fs := lookupFlagSet(name, c); fs != nil {
if fs := c.lookupFlagSet(name); fs != nil {
return lookupFloat64Slice(name, fs)
}
return nil

@ -89,7 +89,7 @@ func (f GenericFlag) Apply(set *flag.FlagSet) error {
// Generic looks up the value of a local GenericFlag, returns
// nil if not found
func (c *Context) Generic(name string) interface{} {
if fs := lookupFlagSet(name, c); fs != nil {
if fs := c.lookupFlagSet(name); fs != nil {
return lookupGeneric(name, fs)
}
return nil

@ -87,7 +87,7 @@ func (f *IntFlag) Apply(set *flag.FlagSet) error {
// Int looks up the value of a local IntFlag, returns
// 0 if not found
func (c *Context) Int(name string) int {
if fs := lookupFlagSet(name, c); fs != nil {
if fs := c.lookupFlagSet(name); fs != nil {
return lookupInt(name, fs)
}
return 0

@ -86,7 +86,7 @@ func (f *Int64Flag) Apply(set *flag.FlagSet) error {
// Int64 looks up the value of a local Int64Flag, returns
// 0 if not found
func (c *Context) Int64(name string) int64 {
if fs := lookupFlagSet(name, c); fs != nil {
if fs := c.lookupFlagSet(name); fs != nil {
return lookupInt64(name, fs)
}
return 0

@ -156,7 +156,7 @@ func (f *Int64SliceFlag) Apply(set *flag.FlagSet) error {
// Int64Slice looks up the value of a local Int64SliceFlag, returns
// nil if not found
func (c *Context) Int64Slice(name string) []int64 {
if fs := lookupFlagSet(name, c); fs != nil {
if fs := c.lookupFlagSet(name); fs != nil {
return lookupInt64Slice(name, fs)
}
return nil

@ -167,7 +167,7 @@ func (f *IntSliceFlag) Apply(set *flag.FlagSet) error {
// IntSlice looks up the value of a local IntSliceFlag, returns
// nil if not found
func (c *Context) IntSlice(name string) []int {
if fs := lookupFlagSet(name, c); fs != nil {
if fs := c.lookupFlagSet(name); fs != nil {
return lookupIntSlice(name, fs)
}
return nil

@ -75,7 +75,7 @@ func (f *PathFlag) Apply(set *flag.FlagSet) error {
// Path looks up the value of a local PathFlag, returns
// "" if not found
func (c *Context) Path(name string) string {
if fs := lookupFlagSet(name, c); fs != nil {
if fs := c.lookupFlagSet(name); fs != nil {
return lookupPath(name, fs)
}

@ -76,7 +76,7 @@ func (f *StringFlag) Apply(set *flag.FlagSet) error {
// String looks up the value of a local StringFlag, returns
// "" if not found
func (c *Context) String(name string) string {
if fs := lookupFlagSet(name, c); fs != nil {
if fs := c.lookupFlagSet(name); fs != nil {
return lookupString(name, fs)
}
return ""

@ -171,7 +171,7 @@ func (f *StringSliceFlag) Apply(set *flag.FlagSet) error {
// StringSlice looks up the value of a local StringSliceFlag, returns
// nil if not found
func (c *Context) StringSlice(name string) []string {
if fs := lookupFlagSet(name, c); fs != nil {
if fs := c.lookupFlagSet(name); fs != nil {
return lookupStringSlice(name, fs)
}
return nil

@ -2038,3 +2038,15 @@ func TestFlagDefaultValue(t *testing.T) {
}
}
}
func TestTimestampFlagApply_WithDestination(t *testing.T) {
var destination Timestamp
expectedResult, _ := time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
fl := TimestampFlag{Name: "time", Aliases: []string{"t"}, Layout: time.RFC3339, Destination: &destination}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
err := set.Parse([]string{"--time", "2006-01-02T15:04:05Z"})
expect(t, err, nil)
expect(t, *fl.Destination.timestamp, expectedResult)
}

@ -71,6 +71,7 @@ type TimestampFlag struct {
Value *Timestamp
DefaultText string
HasBeenSet bool
Destination *Timestamp
}
// IsSet returns whether or not the flag has been set through env or file
@ -123,6 +124,10 @@ func (f *TimestampFlag) Apply(set *flag.FlagSet) error {
}
f.Value.SetLayout(f.Layout)
if f.Destination != nil {
f.Destination.SetLayout(f.Layout)
}
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
if err := f.Value.Set(val); err != nil {
return fmt.Errorf("could not parse %q as timestamp value for flag %s: %s", val, f.Name, err)
@ -131,6 +136,11 @@ func (f *TimestampFlag) Apply(set *flag.FlagSet) error {
}
for _, name := range f.Names() {
if f.Destination != nil {
set.Var(f.Destination, name, f.Usage)
continue
}
set.Var(f.Value, name, f.Usage)
}
return nil
@ -138,7 +148,7 @@ func (f *TimestampFlag) Apply(set *flag.FlagSet) error {
// Timestamp gets the timestamp from a flag name
func (c *Context) Timestamp(name string) *time.Time {
if fs := lookupFlagSet(name, c); fs != nil {
if fs := c.lookupFlagSet(name); fs != nil {
return lookupTimestamp(name, fs)
}
return nil

@ -86,7 +86,7 @@ func (f *UintFlag) GetValue() string {
// Uint looks up the value of a local UintFlag, returns
// 0 if not found
func (c *Context) Uint(name string) uint {
if fs := lookupFlagSet(name, c); fs != nil {
if fs := c.lookupFlagSet(name); fs != nil {
return lookupUint(name, fs)
}
return 0

@ -86,7 +86,7 @@ func (f *Uint64Flag) GetValue() string {
// Uint64 looks up the value of a local Uint64Flag, returns
// 0 if not found
func (c *Context) Uint64(name string) uint64 {
if fs := lookupFlagSet(name, c); fs != nil {
if fs := c.lookupFlagSet(name); fs != nil {
return lookupUint64(name, fs)
}
return 0

@ -3,24 +3,17 @@ package cli
import (
"os"
"reflect"
"runtime"
"strings"
"testing"
)
var (
wd, _ = os.Getwd()
)
func init() {
_ = os.Setenv("CLI_TEMPLATE_REPANIC", "1")
}
func expect(t *testing.T, a interface{}, b interface{}) {
_, fn, line, _ := runtime.Caller(1)
fn = strings.Replace(fn, wd+"/", "", -1)
t.Helper()
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))
t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
}
}

Loading…
Cancel
Save