Skip to content

Commit

Permalink
Merge branch 'master' into ally_fix_default_val
Browse files Browse the repository at this point in the history
  • Loading branch information
rliebz committed Apr 24, 2021
2 parents c98b85d + b1a2d96 commit ab52d6f
Show file tree
Hide file tree
Showing 25 changed files with 149 additions and 135 deletions.
1 change: 1 addition & 0 deletions .github/stale.yml
Expand Up @@ -14,6 +14,7 @@ onlyLabels: []
exemptLabels:
- pinned
- security
- "help wanted"
- "kind/maintenance"

# Set to true to ignore issues in a project (defaults to false)
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/cli.yml
Expand Up @@ -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:
Expand All @@ -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
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions app.go
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion command.go
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
130 changes: 31 additions & 99 deletions context.go
Expand Up @@ -2,9 +2,7 @@ package cli

import (
"context"
"errors"
"flag"
"fmt"
"strings"
)

Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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() {
Expand Down Expand Up @@ -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)
}
}
}
8 changes: 4 additions & 4 deletions context_test.go
Expand Up @@ -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()
}
}
Expand Down Expand Up @@ -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 {
Expand Down
22 changes: 22 additions & 0 deletions errors.go
Expand Up @@ -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)
Expand Down
43 changes: 43 additions & 0 deletions flag.go
@@ -1,6 +1,7 @@
package cli

import (
"errors"
"flag"
"fmt"
"io/ioutil"
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion flag_bool.go
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion flag_duration.go
Expand Up @@ -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
Expand Down

0 comments on commit ab52d6f

Please sign in to comment.