Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix 1.21.0 pass through regression #872

Merged
merged 36 commits into from Oct 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
4381738
wip regression test
coilysiren Aug 23, 2019
e265f50
cleanup tests
coilysiren Aug 23, 2019
6e89173
comment out tests
coilysiren Aug 23, 2019
74cd3bc
cleanup tests
coilysiren Aug 23, 2019
4fb1878
show test failures
coilysiren Aug 23, 2019
e042de5
Merge remote-tracking branch 'origin/master' into pass-through-regres…
Aug 25, 2019
15dc34e
more accurate regression reproduction
Aug 25, 2019
c542fb3
temp remove
Aug 25, 2019
b0ed044
add regression test to its own file
Aug 25, 2019
192ce00
expand name
Aug 25, 2019
2172d38
update tests
Aug 25, 2019
810b971
cleanup
Aug 25, 2019
0f9d8a9
expand test cases
Aug 25, 2019
406a1c3
update vars and args
Aug 25, 2019
2071bcf
checkpoint
Aug 26, 2019
bfeb4c8
Merge branch 'master' into pass-through-regression
Sep 8, 2019
4a4b9f4
Merge https://github.com/urfave/cli into pass-through-regression
coilysiren Sep 8, 2019
7d0751f
add argIsFlag check
Sep 12, 2019
fcfc69e
Merge remote-tracking branch 'origin/master' into pass-through-regres…
Sep 12, 2019
49dbeed
handle `=` input
Sep 12, 2019
10682fb
docs
Sep 12, 2019
09cdbbf
more docs
Sep 12, 2019
223e217
swap a test case
Sep 12, 2019
6da413a
fix go version support?
Sep 12, 2019
bfdd794
docs
Sep 12, 2019
3f6f977
Update command.go
Sep 13, 2019
72c2493
Update command.go
Sep 13, 2019
41eb645
Merge branch 'master' into pass-through-regression
Sep 15, 2019
aac6dd4
Merge branch 'master' into pass-through-regression
Oct 2, 2019
d7af485
Merge branch 'pass-through-regression' of https://github.com/urfave/c…
coilysiren Oct 2, 2019
5125980
better leading dash handling
coilysiren Oct 2, 2019
be0cc4b
add a check
coilysiren Oct 2, 2019
64d3555
trim whitespace
coilysiren Oct 2, 2019
8be7bc4
Merge branch 'master' into pass-through-regression
Oct 2, 2019
c30b1cf
Merge branch 'master' into pass-through-regression
Oct 17, 2019
0480001
Merge branch 'master' into pass-through-regression
Oct 22, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
59 changes: 59 additions & 0 deletions app_regression_test.go
@@ -0,0 +1,59 @@
package cli

import (
"testing"
)

// TestRegression tests a regression that was merged between versions 1.20.0 and 1.21.0
// The included app.Run line worked in 1.20.0, and then was broken in 1.21.0.
// Relevant PR: https://github.com/urfave/cli/pull/872
func TestVersionOneTwoOneRegression(t *testing.T) {
testData := []struct {
testCase string
appRunInput []string
skipArgReorder bool
}{
{
testCase: "with_dash_dash",
appRunInput: []string{"cli", "command", "--flagone", "flagvalue", "--", "docker", "image", "ls", "--no-trunc"},
},
{
testCase: "with_dash_dash_and_skip_reorder",
appRunInput: []string{"cli", "command", "--flagone", "flagvalue", "--", "docker", "image", "ls", "--no-trunc"},
skipArgReorder: true,
},
{
testCase: "without_dash_dash",
appRunInput: []string{"cli", "command", "--flagone", "flagvalue", "docker", "image", "ls", "--no-trunc"},
},
{
testCase: "without_dash_dash_and_skip_reorder",
appRunInput: []string{"cli", "command", "--flagone", "flagvalue", "docker", "image", "ls", "--no-trunc"},
skipArgReorder: true,
},
}
for _, test := range testData {
t.Run(test.testCase, func(t *testing.T) {
// setup
app := NewApp()
app.Commands = []Command{{
Name: "command",
SkipArgReorder: test.skipArgReorder,
Flags: []Flag{
StringFlag{
Name: "flagone",
},
},
Action: func(c *Context) error { return nil },
}}

// logic under test
err := app.Run(test.appRunInput)

// assertions
if err != nil {
t.Errorf("did not expected an error, but there was one: %s", err)
}
})
}
}
75 changes: 57 additions & 18 deletions command.go
Expand Up @@ -190,7 +190,7 @@ func (c *Command) parseFlags(args Args) (*flag.FlagSet, error) {
}

if !c.SkipArgReorder {
args = reorderArgs(args)
args = reorderArgs(c.Flags, args)
}

set, err := c.newFlagSet()
Expand Down Expand Up @@ -219,34 +219,73 @@ func (c *Command) useShortOptionHandling() bool {
return c.UseShortOptionHandling
}

// reorderArgs moves all flags before arguments as this is what flag expects
func reorderArgs(args []string) []string {
var nonflags, flags []string
// reorderArgs moves all flags (via reorderedArgs) before the rest of
// the arguments (remainingArgs) as this is what flag expects.
func reorderArgs(commandFlags []Flag, args []string) []string {
var remainingArgs, reorderedArgs []string

readFlagValue := false
nextIndexMayContainValue := false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
nextIndexMayContainValue := false
var nextIndexMayContainValue bool

This is also a possibility as it would be false by default! It's fine if you don't change it too :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm gonna opt against adding this into the PR - but only because I wanna merge this ASAP so that we can fix the regression 🔧

for i, arg := range args {

// dont reorder any args after a --
// read about -- here:
// https://unix.stackexchange.com/questions/11376/what-does-double-dash-mean-also-known-as-bare-double-dash
if arg == "--" {
nonflags = append(nonflags, args[i:]...)
remainingArgs = append(remainingArgs, args[i:]...)
break
}

if readFlagValue && !strings.HasPrefix(arg, "-") && !strings.HasPrefix(arg, "--") {
readFlagValue = false
flags = append(flags, arg)
continue
}
readFlagValue = false
// checks if this arg is a value that should be re-ordered next to its associated flag
} else if nextIndexMayContainValue && !strings.HasPrefix(arg, "-") {
nextIndexMayContainValue = false
reorderedArgs = append(reorderedArgs, arg)

if arg != "-" && strings.HasPrefix(arg, "-") {
flags = append(flags, arg)
// checks if this is an arg that should be re-ordered
} else if argIsFlag(commandFlags, arg) {
// we have determined that this is a flag that we should re-order
reorderedArgs = append(reorderedArgs, arg)
// if this arg does not contain a "=", then the next index may contain the value for this flag
nextIndexMayContainValue = !strings.Contains(arg, "=")

readFlagValue = !strings.Contains(arg, "=")
// simply append any remaining args
} else {
nonflags = append(nonflags, arg)
remainingArgs = append(remainingArgs, arg)
}
}

return append(flags, nonflags...)
return append(reorderedArgs, remainingArgs...)
}

// argIsFlag checks if an arg is one of our command flags
func argIsFlag(commandFlags []Flag, arg string) bool {
// checks if this is just a `-`, and so definitely not a flag
if arg == "-" {
return false
}
// flags always start with a -
if !strings.HasPrefix(arg, "-") {
return false
}
// this line turns `--flag` into `flag`
if strings.HasPrefix(arg, "--") {
arg = strings.Replace(arg, "-", "", 2)
}
// this line turns `-flag` into `flag`
if strings.HasPrefix(arg, "-") {
arg = strings.Replace(arg, "-", "", 1)
}
saschagrunert marked this conversation as resolved.
Show resolved Hide resolved
// this line turns `flag=value` into `flag`
arg = strings.Split(arg, "=")[0]
// look through all the flags, to see if the `arg` is one of our flags
for _, flag := range commandFlags {
for _, key := range strings.Split(flag.GetName(), ",") {
key := strings.TrimSpace(key)
if key == arg {
saschagrunert marked this conversation as resolved.
Show resolved Hide resolved
return true
}
}
}
// return false if this arg was not one of our flags
return false
}

// Names returns the names including short names and aliases.
Expand Down
2 changes: 1 addition & 1 deletion command_test.go
Expand Up @@ -18,7 +18,7 @@ func TestCommandFlagParsing(t *testing.T) {
UseShortOptionHandling bool
}{
// Test normal "not ignoring flags" flow
{[]string{"test-cmd", "blah", "blah", "-break"}, false, false, errors.New("flag provided but not defined: -break"), false},
{[]string{"test-cmd", "blah", "blah", "-break"}, false, false, nil, false},

// Test no arg reorder
{[]string{"test-cmd", "blah", "blah", "-break"}, false, true, nil, false},
Expand Down