Skip to content

v1 regression: v1.22.2-and-over skips over flag-like arguments to subcommand string slice flags #1152

@cyphar

Description

@cyphar

my urfave/cli version is

v1.22.1 was the last working version, and all versions up to v1.22.4 are broken.

Checklist

  • Are you running the latest v1 release? The list of releases is here.
  • Did you check the manual for your release? The v1 manual is here
  • Did you perform a search about this problem? Here's the Github guide about searching.

Dependency Management

  • My project is using go modules.
  • My project is using vendoring.
  • My project is automatically downloading the latest version.
  • I am unsure of what my dependency management setup is.

Describe the bug

If you try to use a flag-like argument to a string slice argument that is not a valid flag, the argument gets ignored and instead the next argument is used instead (which, if it is a valid string slice argument it is swallowed as a flag value).

To reproduce

First, set up a basic Go dev environment for the test:

% mkdir -p /tmp/testcli
% cd /tmp/testcli
% go mod init example.com/testcli
go: creating new go.mod: module example.com/testcli
% go get github.com/urfave/cli@v1.22.4
go: downloading github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d

And then try to run the following program:

package main

import (
	"fmt"
	"os"

	"github.com/urfave/cli"
)

func main() {
	app := cli.NewApp()
	app.Commands = []cli.Command{
		{
			Name: "config",
			Flags: []cli.Flag{
				cli.StringSliceFlag{
					Name: "config.cmd",
				},
			},
			Action: func(ctx *cli.Context) error {
				fmt.Printf("args: %v\n", os.Args)
				fmt.Printf("leftover args: %v\n", ctx.Args())
				fmt.Printf("config.cmd: %v\n", ctx.StringSlice("config.cmd"))
				return nil
			},
		},
	}

	err := app.Run(os.Args)
	if err != nil {
		fmt.Printf("err: %v\n", err)
	}
}

Like so:

% go run main.go config --config.cmd "-c" --config.cmd "ls -la"

Observed behavior

If you use 1.22.2 or later of github.com/urfave/cli, you find:

% go run main.go config --config.cmd "-c" --config.cmd "ls -la"
args: [/tmp/go-build948656450/b001/exe/main config --config.cmd -c --config.cmd ls -la]
leftover args: [ls -la -c]
config.cmd: [--config.cmd]

What appears to be happening is that the -c argument to the --config.cmd flag is being skipped -- though it's not being treated as an unknown flag (there's no error about unknown flags) and instead is being treated as a positional argument. As as result, --config.cmd is being used as an argument (presumably because it's a known flag?) and the rest of the arguments are treated as positional arguments.

However, if you instead call the program like so you get the correct output:

% go run main.go config --config.cmd="-c" --config.cmd "ls -la"
args: [/tmp/go-build358735402/b001/exe/main config --config.cmd=-c --config.cmd ls -la]
leftover args: []
config.cmd: [-c ls -la]

Expected behavior

If you use 1.22.1 or earlier of github.com/urfave/cli, you find:

% go run main.go config --config.cmd "-c" --config.cmd "ls -la"
args: [/tmp/go-build278409428/b001/exe/main config --config.cmd -c --config.cmd ls -la]
leftover args: []
config.cmd: [-c ls -la]

Additional context

I am trying to update my version of github.com/urfave/cli in umoci and this is an issue I hit almost immediately when trying to do the update.

N.B. This issue doesn't happen unless you use subcommands. If you try to do this with the top-level app.Flags then it works as expected.

Run go version and paste its output here

go version go1.14.4 linux/amd64

Run go env and paste its output here

GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/cyphar/.cache/go-build"
GOENV="/home/cyphar/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/cyphar/.local"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/lib64/go/1.14"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/lib64/go/1.14/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/cyphar/tmp/testcli/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build827330497=/tmp/go-build -gno-record-gcc-switches"

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/v1relates to / is being considered for v1help wantedplease help if you can!kind/bugdescribes or fixes a bugstatus/confirmedconfirmed to be valid, but work has yet to start

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions