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

add ability to ignore unknown flags #160

Merged
merged 5 commits into from Mar 30, 2018
Merged

Conversation

rajatjindal
Copy link

It will be nice if we can add ability to ignore unknown flags. This can be useful when writing wrappers on other commands where exposing all downstream flags is un-necessary.

@CLAassistant
Copy link

CLAassistant commented Mar 12, 2018

CLA assistant check
All committers have signed the CLA.

@rajatjindal rajatjindal changed the title [WIP] add ability to ignore unknown flags add ability to ignore unknown flags Mar 12, 2018
@rajatjindal
Copy link
Author

requesting review from @eparis

@rajatjindal
Copy link
Author

pinging @eparis again

@rajatjindal
Copy link
Author

Pinging @eparis, please let me know if once a day ping is too much

@rajatjindal
Copy link
Author

ping @spf13 @eparis

@rajatjindal
Copy link
Author

ping @eparis

please continue to ignore if you are busy, i just want to make sure i don't forget about it.

@eparis
Copy link
Collaborator

eparis commented Mar 19, 2018

How should this relate to the *OnError defines?
https://github.com/spf13/pflag/pull/160/files#diff-1fdeef6cfb1d74886a385d13094d6cbcL117
I'm specifically wondering how Missing is today an error, which means it would be handled by the *OnError defines, but after this patch we have multiple error handle things...

Can you think of a good way to rationalize this into a single error handling logic?

@rajatjindal
Copy link
Author

rajatjindal commented Mar 21, 2018

Thanks a lot for the review @eparis

I see what you are saying.

looking at this: https://github.com/spf13/pflag/blob/master/flag.go#L1087

i think with ContinueOnError, it will stop parsing flags as soon as it encounter an unknown flag, but let user decide what do to with error

with IgnoreUnknownFlags, it will ignore unknown flag error encountered during parse while continuing to parse the other known flags. (it will still return error for other conditions).

If it make sense, I can add this as an "ErrorHandling" type. Please let me know

@eparis
Copy link
Collaborator

eparis commented Mar 21, 2018

Do you think IgnoreUnknownFlags is a better API? I think it makes sense to me.

I'm not arguing that the "ErrorHandling" stuff is a good idea, it's just the thing we have. And I don't want to make a second semi-related thing if we can help it....

@rajatjindal
Copy link
Author

if we add another ErrorHandling type as 'IgnoreUnknownFlags', what should be the behavior incase of any other error.

e.g. lets say user selected ErrorHandling to be of type IgnoreUnknownFlags, and flag parsing encountered a different error, what should we do with that error (panic, exit or continue?)

@rajatjindal
Copy link
Author

sorry if felt that way, but i am asking for suggestions here :)

this library is a master piece, and i want to keep it that way (even after my ugly contributions)

@rajatjindal
Copy link
Author

so kindly let me know what you think we should do here, and I will try to update the PR to reflect that.

@rajatjindal
Copy link
Author

pinging @eparis

Copy link
Collaborator

@eparis eparis left a comment

Choose a reason for hiding this comment

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

I'd like you to think about what a better Error handling interface would look like. I agree that having 3 new OnError defines is not the right thing to go. I'll take this PR, but would love to hear you thought if some sort of feature bit map or something makes better sense for our error handling. And if it does make sense, can this be the first thing the implements that new error aPI?

@@ -896,6 +899,25 @@ func (f *FlagSet) usage() {
}
}

//--unknown (args will be empty)
//--unknown --next-flag ... (args will be --next-flag ...)
Copy link
Collaborator

Choose a reason for hiding this comment

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

What if I passed --unknown=bob --next-flag. I think this will strip --next-flag, but I don't think it should.

Copy link
Author

Choose a reason for hiding this comment

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

this function just strips value for unknown flag, the flag itself is not included in args.

for --unknown=value --next-flag ... args will be --next-flag ...

added the testcase to test this explicitly

Copy link
Collaborator

Choose a reason for hiding this comment

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

I really think you need to know len(split) (from parseLongArg) and to use that. What if it was --unknown=value subcmd. You would strip subcmd which is really not what the user wants.

Clearly it is a heuristic to know what to strip and what not to strip for an 'unknown' but I think we want to be as careful as we can...

Copy link
Author

Choose a reason for hiding this comment

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

oh yes, thats right. i would consider this a bug :)

fixed. thank you for pointing out.

"unknown1Value",
"-d=true",
"-x",
"--unknown2=unknown2Value",
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this test need to cover the case where --unknown=value is followed by --known

Copy link
Author

Choose a reason for hiding this comment

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

added the testcase, thanks

@rajatjindal
Copy link
Author

thanks for the review @eparis

I have added the test case as suggested.

flag.go Outdated
@@ -138,6 +138,9 @@ type FlagSet struct {
// help/usage messages.
SortFlags bool

// IgnoreUnknownFlags is used to indicate to ignore unknown flags
IgnoreUnknownFlags bool
Copy link
Collaborator

Choose a reason for hiding this comment

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

Convert this into some sort of generic "set" of error handling bools which we can grow as needed and I'll merge this PR.

Copy link
Author

Choose a reason for hiding this comment

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

Will do that today, thanks

@eparis eparis merged commit 1cd4a0c into spf13:master Mar 30, 2018
@rajatjindal
Copy link
Author

thanks a lot for merging eparis

@vcastellm
Copy link

vcastellm commented Apr 4, 2018

@rajatjindal I was waiting for this PR thanks for the effort! If I understand correctly, it strips all unknown flags passed, leaving known ones.

I need to create a wrapper command in the form: cmd subcmd systemcmd --systemcmd-flag

Where systemcmd is any executable given by the user.

What happens is that I'm loosing any given --systemcmd-flag passed. What is the goal of this PR if those flags are stripped?

@rajatjindal
Copy link
Author

originally pflag will error out if it encounters any flag which was not configured by 'current cmd'. so running cmd subcmd systemcmd --systemcmd-flag, will result in 'unknown flag --systemcmd-flag'

The intention of this PR was to ignore those unknown flags during parsing (in other words strip) and keep the flags which are required by 'current cmd'.

do u have a use case where you want to consume systemcmd-flag in your 'current cmd'?

@vcastellm
Copy link

@rajatjindal I want to build a command wrapper similar to the bundle exec http://bundler.io/man/bundle-exec.1.html interface.

I need to preserve all flags passed to the command being wrapped.

Currently this is not possible to do with the previous pflag and it's still not possible with this PR.

@eparis
Copy link
Collaborator

eparis commented Apr 5, 2018

I think it is possible, but now you have go back and process os.Args yourself inside Run()

what if we added the 'ignored' flags to the args array we pass to Run()

@vcastellm
Copy link

@eparis thanks for pointing that, this should workaround the problem.

I expected to find the "ignored" flags in the args passed to Run(), I could craft a PR with that, what do you think?

@eparis
Copy link
Collaborator

eparis commented Apr 5, 2018

we'll see what @rajatjindal says about it. This API is new enough I don't mind 'breaking' it....

@rajatjindal
Copy link
Author

I think we should probably include IgnoredFlags *flag.FlagSet field in command, that can be set when ignoredflags is on

Passing by default to run func may create prob again for user on what is child commands vs ignored flags

@vcastellm
Copy link

vcastellm commented Apr 5, 2018

@rajatjindal but would that require the user to explicitly set IgnoredFlags in advance?

I would add IgnoredFlags []string

@rajatjindal
Copy link
Author

Yeah, i think so, otherwise the flag parsing will fail on it.

I think []string make sense

@rajatjindal
Copy link
Author

sorry i think i misread your comment. The user will just have to set a bool flag to ignore unknown flags, but ignored flags will be read and added to IgnoredFlags while parsing.

@eparis
Copy link
Collaborator

eparis commented Apr 5, 2018

Making sure my thought was understood. I was saying that if we ignore a flag and arg (because the dev decided to set IgnoreUnknown) we should add those things to the args here: https://github.com/spf13/cobra/blob/master/command.go#L103

Today, I think, those args are just 'non-flag' args which were not consumed by cobra. If you set 'IgnoreUnknown' your program will start getting those 'ignored' things along with the non-flag args. Now it would be your program's problem to parse and handle those 'args'. How you decide to handle those are your problem...

@vcastellm
Copy link

I'm totally with @eparis, just unsure to be saying something nonsense, but passing everything back to the user in args makes sense to me.

@rajatjindal
Copy link
Author

I think thats fine too. args it is then :)

thaJeztah added a commit to thaJeztah/cli that referenced this pull request May 18, 2018
Use a tagged release of this package

Relevant changes:

- spf13/pflag#122 DurationSlice: implementation and tests
- spf13/pflag#115 Implement BytesHex type of argument
- spf13/pflag#150 Add uintSlice and boolSlice to name prettifier
- spf13/pflag#155 Add multiline wrapping support
- spf13/pflag#158 doc: clarify difference between string slice vs. array
- spf13/pflag#160 add ability to ignore unknown flags
- spf13/pflag#163 Allow Users To Show Deprecated Flags

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
thaJeztah added a commit to thaJeztah/cli that referenced this pull request May 19, 2018
Use a tagged release of Cobra

Relevant changes:

- spf13/cobra#567 Add `CalledAs` method to cobra.Command
- spf13/cobra#580 Update error message for missing required flags
- spf13/cobra#584 Add support for --version flag
- spf13/cobra#614 If user has a project in symlink, just use its destination folder and work there
- spf13/cobra#649 terminates the flags when -- is found in commandline
- spf13/cobra#662 Add support for ignoring parse errors
- spf13/cobra#686 doc: hide hidden parent flags

Also various improvements were added for generating Bash
completion scripts (currently not used by us)

Bump spf13/pflag to v1.0.1

Relevant changes:

- spf13/pflag#122 DurationSlice: implementation and tests
- spf13/pflag#115 Implement BytesHex type of argument
- spf13/pflag#150 Add uintSlice and boolSlice to name prettifier
- spf13/pflag#155 Add multiline wrapping support
- spf13/pflag#158 doc: clarify difference between string slice vs. array
- spf13/pflag#160 add ability to ignore unknown flags
- spf13/pflag#163 Allow Users To Show Deprecated Flags

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
thaJeztah added a commit to thaJeztah/docker that referenced this pull request May 19, 2018
Use a tagged release of Cobra. All relevant PR's were merged, so the fork is
no longer needed.

Relevant changes:

- spf13/cobra#552 Add a field to disable [flags] in UseLine()
- spf13/cobra#567 Add `CalledAs` method to cobra.Command
- spf13/cobra#580 Update error message for missing required flags
- spf13/cobra#584 Add support for --version flag
- spf13/cobra#614 If user has a project in symlink, just use its destination folder and work there
- spf13/cobra#649 terminates the flags when -- is found in commandline
- spf13/cobra#662 Add support for ignoring parse errors
- spf13/cobra#686 doc: hide hidden parent flags

Also various improvements were added for generating Bash
completion scripts (currently not used by us)

Fixes usage output for dockerd;

Before this update:

    dockerd --help

    Usage:	dockerd COMMAND

    A self-sufficient runtime for containers.

After this update:

    dockerd --help

    Usage:	dockerd [OPTIONS] [flags]

    A self-sufficient runtime for containers.

Bump spf13/pflag to v1.0.1

Relevant changes:

- spf13/pflag#106 allow lookup by shorthand
- spf13/pflag#113 Add SortFlags option
- spf13/pflag#138 Generate flag error output for errors returned from the parseFunc
- spf13/pflag#141 Fixing Count flag usage string
- spf13/pflag#143 add int16 flag
- spf13/pflag#122 DurationSlice: implementation and tests
- spf13/pflag#115 Implement BytesHex type of argument
- spf13/pflag#150 Add uintSlice and boolSlice to name prettifier
- spf13/pflag#155 Add multiline wrapping support
- spf13/pflag#158 doc: clarify difference between string slice vs. array
- spf13/pflag#160 add ability to ignore unknown flags
- spf13/pflag#163 Allow Users To Show Deprecated Flags

Hide [flags] in usage output

Hides the [flags] in the usage output of commands (present in newer
versions of Cobra), using the `.DisableFlagsInUseLine` option.

Before this change:

    dockerd --help

    Usage:	dockerd [OPTIONS] [flags]

    A self-sufficient runtime for containers.

After this change:

    dockerd --help

    Usage:	dockerd [OPTIONS]

    A self-sufficient runtime for containers.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Â#	modified:   vendor/github.com/spf13/pflag/string_array.go
§

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
docker-jenkins pushed a commit to docker/docker-ce that referenced this pull request May 22, 2018
Use a tagged release of Cobra

Relevant changes:

- spf13/cobra#567 Add `CalledAs` method to cobra.Command
- spf13/cobra#580 Update error message for missing required flags
- spf13/cobra#584 Add support for --version flag
- spf13/cobra#614 If user has a project in symlink, just use its destination folder and work there
- spf13/cobra#649 terminates the flags when -- is found in commandline
- spf13/cobra#662 Add support for ignoring parse errors
- spf13/cobra#686 doc: hide hidden parent flags

Also various improvements were added for generating Bash
completion scripts (currently not used by us)

Bump spf13/pflag to v1.0.1

Relevant changes:

- spf13/pflag#122 DurationSlice: implementation and tests
- spf13/pflag#115 Implement BytesHex type of argument
- spf13/pflag#150 Add uintSlice and boolSlice to name prettifier
- spf13/pflag#155 Add multiline wrapping support
- spf13/pflag#158 doc: clarify difference between string slice vs. array
- spf13/pflag#160 add ability to ignore unknown flags
- spf13/pflag#163 Allow Users To Show Deprecated Flags

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Upstream-commit: 0acb2522bd17ec6f1eb4ecb0960c792a71f08f69
Component: cli
docker-jenkins pushed a commit to docker/docker-ce that referenced this pull request May 22, 2018
Use a tagged release of Cobra. All relevant PR's were merged, so the fork is
no longer needed.

Relevant changes:

- spf13/cobra#552 Add a field to disable [flags] in UseLine()
- spf13/cobra#567 Add `CalledAs` method to cobra.Command
- spf13/cobra#580 Update error message for missing required flags
- spf13/cobra#584 Add support for --version flag
- spf13/cobra#614 If user has a project in symlink, just use its destination folder and work there
- spf13/cobra#649 terminates the flags when -- is found in commandline
- spf13/cobra#662 Add support for ignoring parse errors
- spf13/cobra#686 doc: hide hidden parent flags

Also various improvements were added for generating Bash
completion scripts (currently not used by us)

Fixes usage output for dockerd;

Before this update:

    dockerd --help

    Usage:	dockerd COMMAND

    A self-sufficient runtime for containers.

After this update:

    dockerd --help

    Usage:	dockerd [OPTIONS] [flags]

    A self-sufficient runtime for containers.

Bump spf13/pflag to v1.0.1

Relevant changes:

- spf13/pflag#106 allow lookup by shorthand
- spf13/pflag#113 Add SortFlags option
- spf13/pflag#138 Generate flag error output for errors returned from the parseFunc
- spf13/pflag#141 Fixing Count flag usage string
- spf13/pflag#143 add int16 flag
- spf13/pflag#122 DurationSlice: implementation and tests
- spf13/pflag#115 Implement BytesHex type of argument
- spf13/pflag#150 Add uintSlice and boolSlice to name prettifier
- spf13/pflag#155 Add multiline wrapping support
- spf13/pflag#158 doc: clarify difference between string slice vs. array
- spf13/pflag#160 add ability to ignore unknown flags
- spf13/pflag#163 Allow Users To Show Deprecated Flags

Hide [flags] in usage output

Hides the [flags] in the usage output of commands (present in newer
versions of Cobra), using the `.DisableFlagsInUseLine` option.

Before this change:

    dockerd --help

    Usage:	dockerd [OPTIONS] [flags]

    A self-sufficient runtime for containers.

After this change:

    dockerd --help

    Usage:	dockerd [OPTIONS]

    A self-sufficient runtime for containers.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Â#	modified:   vendor/github.com/spf13/pflag/string_array.go
§

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Upstream-commit: ed75c7727bf3e454a5faa6baf686de12152d911c
Component: engine
@lucastheisen
Copy link

@rajatjindal , the last few messages in this discussion seem to indicate that any non-consumed flags should be left in the args array passed to Run. That is not the behavior that I am observing. I am currently using

	github.com/spf13/pflag v1.0.2 // indirect

I am writing a wrapper around kubectl logs:

var logsCmd = &cobra.Command{
	Use:   "logs [app name]",
	Short: "Fetch the logs of a container",
	Args:  cobra.MinimumNArgs(1),
	FParseErrWhitelist: cobra.FParseErrWhitelist{
		UnknownFlags: true,
	},
	RunE: func(cmd *cobra.Command, args []string) error {
		result, err := util.Runner{
			BufferStdout: true,
		}.Run("kubectl", []string{
			"get",
			"pod",
			"-l",
			fmt.Sprintf("app=%s", args[0]),
			"-o",
			"jsonpath={.items[0].metadata.name}",
		}...)
		if err != nil {
			return err
		}

		log.Debugf("running logs args [%v]", args)
		_, err = util.Runner{
			PrintStdout: true,
			PrintStderr: true,
		}.Run("kubectl",
			append([]string{
				"logs",
				result.Stdout.String(),
			}, args[1:]...)...)
		return err
	},
}

But when i use go run . logs foodb -f, the -f is not getting passed in args:

...
�[37mDEBU�[0m[0001] running logs args [[foodb]]
...

It appears your test code verifies that all the expected flags are parsed, and unexpected flags ignored, but it doesn't seem to be verifying that the unexpected args are present in the remaining arg list. Also, this ignore feature never made its way into the cobra documentation, it was a bit of a pita to figure this out. Might be a good idea to add it there.

@rajatjindal
Copy link
Author

Hi

Sorry for the pain it caused

I am in middle of relocating right now, i can try to fix this in about 2 weeks or if you want to open a PR that will be great

@mtheck
Copy link

mtheck commented Oct 2, 2018

Totally agree, an ignored flag should have been kept in the argument list after flag parsing, because it is ignored. This is an important missing feature of this library which prevent developing a command wrapper (as said by @Victorcoder) that has its own "global" arguments.

However this features is implemented as a kind of error to be ignored and not flags to be ignored. So I don't think it is worthwhile breaking by changing this behavior. There should be a real "IgnoreUnknownFlags" feature.

@marcusljx
Copy link

Is there any update on the ignored flag being passed back to the remaining arg list?

@sethvargo
Copy link

FWIW, using -- works as people expect with no additional options, including this configuration.

var execCmd = &cobra.Command{
	Use:   "exec -- [subcommand]",
	Short: "Spawn a subprocess",
	Args: cobra.MinimumNArgs(1),
	Run:  execRun,
}

func execRun(_ *cobra.Command, args []string) {
	execCmd := args[0]
	execArgs := args[1:]
	# ...
}

I agree it's not the ideal UX, but it gets the job done:

$ mycli exec -- ls -alh

@duglin
Copy link

duglin commented Aug 31, 2022

Is there any update on the ignored flag being passed back to the remaining arg list?

I can't seem to find a way to access the ignore flags - was this ever addressed?

@xmapst
Copy link

xmapst commented Mar 21, 2024

Is there any update on the ignored flag being passed back to the remaining arg list?

I can't seem to find a way to access the ignore flags - was this ever addressed?

cmd = &cobra.Command{
		......
		FParseErrWhitelist: cobra.FParseErrWhitelist{
			UnknownFlags: true,
		},
	}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

10 participants