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

Binding with cobra flag results on IsSet always true #276

Closed
ggeorgiev opened this issue Nov 14, 2016 · 10 comments · Fixed by #331
Closed

Binding with cobra flag results on IsSet always true #276

ggeorgiev opened this issue Nov 14, 2016 · 10 comments · Fixed by #331
Milestone

Comments

@ggeorgiev
Copy link

When I bind a key to a cobra flag, when I ask IsSet I always get true, even if the flag was not set in the command line flags as well.

Do I miss something or this is a real issue?

@jasonish
Copy link

I just ran into this as well. My temporary solution is to not find the particular value I need to check IsSet on, and did a custom function that first checks if the flag is set, then checks if the viper.IsSet is set on it. IMO, viper.IsSet() is not doing the right thing here.

@stephenrlouie
Copy link

I saw this problem too! isSet() returns true as soon as I Bind a flag to viper.

I used viper in the past and believe its behavior has changed. It used to return false if you just bound the flag and no actual value was provided by an input (config file, command line, or env). It would return true only if one of these inputs were provided. IMO this is the appropriate behavior since a flag usually requires a value by nature of being a flag, but I wouldn't consider that "set".

My workaround is to substitute isSet for a zero value check. (I could also set the defaults when I declare the flags)

@jasonish
Copy link

I used viper in the past and believe its behavior has changed.

I believe you are correct. It looks like e3bc06f added the behaviour you would expect, then ec4eb2f broke it again.

@benoitmasson Is there a reason IsSet() behaviour changed with this commit? Or was it an unintended side affect?

@benoitmasson
Copy link
Contributor

Hi,

Sorry about that, this is clearly a side effect of my changes. And there should be a test for this specific case (or TestIsSet() should be extended to use flags).

However, the old code

       if val == nil {
               source := v.find(strings.ToLower(path[0]))
               if source != nil {
                       if reflect.TypeOf(source).Kind() == reflect.Map {
                               val = v.searchMap(cast.ToStringMap(source), path[1:])
                       }
               }
       }

cannot be restored as such, because it does not work properly with nested values (the source map may not be the one where the value is really, example in this post).

I'll have a look and see if I can do something.

@benoitmasson
Copy link
Contributor

I added some tests to TestIsSet(), but everything works as expected:

        v.ReadConfig(bytes.NewBuffer(yamlExample)) // defines "eyes"

	v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
	v.BindEnv("eyes")
	v.BindEnv("foo")
	v.BindEnv("clothing.hat")
	v.BindEnv("clothing.hats")
	os.Setenv("FOO", "bar")
	os.Setenv("CLOTHING_HAT", "bowler")

	assert.True(t, v.IsSet("eyes"))           // set in the config file
	assert.True(t, v.IsSet("foo"))            // set in the environment
	assert.True(t, v.IsSet("clothing.hat"))   // set in the environment
	assert.False(t, v.IsSet("clothing.hats")) // bound but not set
ok  	github.com/spf13/viper	0.014s

Did I get something wrong? Or could you be more precise about the issue you are facing?

@jasonish
Copy link

How about this:

func TestIsSetFailing(t *testing.T) {
	v := New()

	flagset := pflag.NewFlagSet("testisset", pflag.ExitOnError)
	flagset.Bool("foo", false, "foo")
	v.BindPFlag("foo", flagset.Lookup("foo"))
	err := flagset.Parse([]string{})
	assert.Nil(t, err)

	// Here I would expect IsSet to be false...
	assert.False(t, v.IsSet("foo"))
}

It seems to be tied to binding a flag.

@benoitmasson
Copy link
Contributor

benoitmasson commented Apr 11, 2017

Ooops, I must be tired, I read “flags” and tested “environment” :-( Thanks for the precision.

I see where this comes from now. If a flag is bound to Viper, a default value is automatically assigned to it, hence Get() always returns a value (the default one if not defined anywhere). IsSet() follows this behavior, but I agree this is not desired in this precise case.

I will look for a fix (probably inside the Get() and find() functions, I like the IsSet() one as it is) and submit a PR as soon as possible.

@ggeorgiev
Copy link
Author

@benoitmasson thank you for fixing this, it is causing me to use some workarounds that I can get rid of.

benoitmasson added a commit to benoitmasson/viper that referenced this issue Apr 11, 2017
Default value should be looked for by Get(), but not by IsSet().

This logic should remain inside find(), to make sure that shadowing
of keys is handled properly.

Fixes Issue spf13#276.
benoitmasson added a commit to benoitmasson/viper that referenced this issue Apr 17, 2017
Default value should be looked for by Get(), but not by IsSet().

This logic should remain inside find(), to make sure that shadowing
of keys is handled properly.

Fixes Issue spf13#276.
benoitmasson added a commit to benoitmasson/viper that referenced this issue Apr 17, 2017
Default value should be looked for by Get(), but not by IsSet().

This logic should remain inside find(), to make sure that shadowing
of keys is handled properly.

Fixes Issue spf13#276.
@zyuyou
Copy link

zyuyou commented May 15, 2017

#331 Still not accepted?

@jacobcase
Copy link

Any idea when #331 will get accepted?

mlaventure pushed a commit to mlaventure/viper that referenced this issue Sep 24, 2017
Default value should be looked for by Get(), but not by IsSet().

This logic should remain inside find(), to make sure that shadowing
of keys is handled properly.

Fixes Issue spf13#276.
benoitmasson added a commit to benoitmasson/viper that referenced this issue Oct 10, 2017
Default value should be looked for by Get(), but not by IsSet().

This logic should remain inside find(), to make sure that shadowing
of keys is handled properly.

Fixes Issue spf13#276.
benoitmasson added a commit to benoitmasson/viper that referenced this issue Oct 10, 2017
Default value should be looked for by Get(), but not by IsSet().

This logic should remain inside find(), to make sure that shadowing
of keys is handled properly.

Fixes Issue spf13#276.
benoitmasson added a commit to benoitmasson/viper that referenced this issue Feb 27, 2018
Default value should be looked for by Get(), but not by IsSet().

This logic should remain inside find(), to make sure that shadowing
of keys is handled properly.

Fixes Issue spf13#276.
benoitmasson added a commit to benoitmasson/viper that referenced this issue May 22, 2018
Default value should be looked for by Get(), but not by IsSet().

This logic should remain inside find(), to make sure that shadowing
of keys is handled properly.

Fixes Issue spf13#276.
josephtfrank pushed a commit to SpectraLogic/viper that referenced this issue Feb 25, 2019
The IsSet function returns true even if the value that's available comes
from the default. Rather than changing the behavior of IsSet, adding a
new IsExplicit function allows checking for non-default values without
breaking existing behavior. This is intended to address issue spf13#276 among
other things.
josephtfrank added a commit to SpectraLogic/viper that referenced this issue Feb 26, 2019
The IsSet function returns true even if the value that's available comes
from the default. Rather than changing the behavior of IsSet, adding a
new IsExplicit function allows checking for non-default values without
breaking existing behavior. This is intended to address issue spf13#276 among
other things.
josephtfrank added a commit to SpectraLogic/viper that referenced this issue Feb 26, 2019
The IsSet function returns true even if the value that's available comes
from the default. Rather than changing the behavior of IsSet, adding a
new IsExplicit function allows checking for non-default values without
breaking existing behavior. This is intended to address issue spf13#276 among
other things.
josephtfrank added a commit to SpectraLogic/viper that referenced this issue Feb 26, 2019
The IsSet function returns true even if the value that's available comes
from the default. Rather than changing the behavior of IsSet, adding a
new IsExplicit function allows checking for non-default values without
breaking existing behavior. This is intended to address issue spf13#276 among
other things.
josephtfrank added a commit to SpectraLogic/viper that referenced this issue Feb 26, 2019
The IsSet function returns true even if the value that's available comes
from the default. Rather than changing the behavior of IsSet, adding a
new IsExplicit function allows checking for non-default values without
breaking existing behavior. This is intended to address issue spf13#276 among
other things.
squaremo added a commit to fluxcd/flux that referenced this issue Oct 23, 2019
In some places we need to know whether a flag has been explicitly
set. When it was just flags, `pflag.Changed` served this purpose. But
`viper.IsSet`, which is supposed to do the same thing over flags,
config files, and environment entries, is broken:
spf13/viper#276.

Therefore: I've made my own isSet predicate, which checks the flags,
config and environment individually. Since we can't actually check the
environment separately, it has to construct a viper value that _only_
looks at the env, and check that.
squaremo added a commit to fluxcd/flux that referenced this issue Nov 21, 2019
In some places we need to know whether a flag has been explicitly
set. When it was just flags, `pflag.Changed` served this purpose. But
`viper.IsSet`, which is supposed to do the same thing over flags,
config files, and environment entries, is broken:
spf13/viper#276.

Therefore: I've made my own isSet predicate, which checks the flags,
config and environment individually. Since we can't actually check the
environment separately, it has to construct a viper value that _only_
looks at the env, and check that.
squaremo added a commit to fluxcd/flux that referenced this issue Nov 25, 2019
In some places we need to know whether a flag has been explicitly
set. When it was just flags, `pflag.Changed` served this purpose. But
`viper.IsSet`, which is supposed to do the same thing over flags,
config files, and environment entries, is broken:
spf13/viper#276.

Therefore: I've made my own isSet predicate, which checks the flags,
config and environment individually. Since we can't actually check the
environment separately, it has to construct a viper value that _only_
looks at the env, and check that.
benoitmasson added a commit to benoitmasson/viper that referenced this issue Nov 26, 2019
Default value should be looked for by Get(), but not by IsSet().

This logic should remain inside find(), to make sure that shadowing
of keys is handled properly.

Fixes Issue spf13#276.
@sagikazarmark sagikazarmark added this to the 1.6.0 milestone Nov 29, 2019
sagikazarmark pushed a commit that referenced this issue Nov 29, 2019
Default value should be looked for by Get(), but not by IsSet().

This logic should remain inside find(), to make sure that shadowing
of keys is handled properly.

Fixes Issue #276.
squaremo added a commit to fluxcd/flux that referenced this issue Dec 5, 2019
In some places we need to know whether a flag has been explicitly
set. When it was just flags, `pflag.Changed` served this purpose. But
`viper.IsSet`, which is supposed to do the same thing over flags,
config files, and environment entries, is broken:
spf13/viper#276.

Therefore: I've made my own isSet predicate, which checks the flags,
config and environment individually. Since we can't actually check the
environment separately, it has to construct a viper value that _only_
looks at the env, and check that.
squaremo added a commit to fluxcd/flux that referenced this issue Dec 9, 2019
In some places we need to know whether a flag has been explicitly
set. When it was just flags, `pflag.Changed` served this purpose. But
`viper.IsSet`, which is supposed to do the same thing over flags,
config files, and environment entries, is broken:
spf13/viper#276.

Therefore: I've made my own isSet predicate, which checks the flags,
config and environment individually. Since we can't actually check the
environment separately, it has to construct a viper value that _only_
looks at the env, and check that.
squaremo added a commit to fluxcd/flux that referenced this issue Dec 10, 2019
In some places we need to know whether a flag has been explicitly
set. When it was just flags, `pflag.Changed` served this purpose. But
`viper.IsSet`, which is supposed to do the same thing over flags,
config files, and environment entries, is broken:
spf13/viper#276.

Therefore: I've made my own isSet predicate, which checks the flags,
config and environment individually. Since we can't actually check the
environment separately, it has to construct a viper value that _only_
looks at the env, and check that.
squaremo added a commit to fluxcd/flux that referenced this issue Jan 28, 2020
In some places we need to know whether a flag has been explicitly
set. When it was just flags, `pflag.Changed` served this purpose. But
`viper.IsSet`, which is supposed to do the same thing over flags,
config files, and environment entries, is broken:
spf13/viper#276.

Therefore: I've made my own isSet predicate, which checks the flags,
config and environment individually. Since we can't actually check the
environment separately, it has to construct a viper value that _only_
looks at the env, and check that.
squaremo added a commit to fluxcd/flux that referenced this issue Jan 29, 2020
In some places we need to know whether a flag has been explicitly
set. When it was just flags, `pflag.Changed` served this purpose. But
`viper.IsSet`, which is supposed to do the same thing over flags,
config files, and environment entries, is broken:
spf13/viper#276.

Therefore: I've made my own isSet predicate, which checks the flags,
config and environment individually. Since we can't actually check the
environment separately, it has to construct a viper value that _only_
looks at the env, and check that.
squaremo added a commit to fluxcd/flux that referenced this issue Jan 29, 2020
In some places we need to know whether a flag has been explicitly
set. When it was just flags, `pflag.Changed` served this purpose. But
`viper.IsSet`, which is supposed to do the same thing over flags,
config files, and environment entries, is broken:
spf13/viper#276.

Therefore: I've made my own isSet predicate, which checks the flags,
config and environment individually. Since we can't actually check the
environment separately, it has to construct a viper value that _only_
looks at the env, and check that.
squaremo added a commit to fluxcd/flux that referenced this issue Jan 29, 2020
In some places we need to know whether a flag has been explicitly
set. When it was just flags, `pflag.Changed` served this purpose. But
`viper.IsSet`, which is supposed to do the same thing over flags,
config files, and environment entries, is broken:
spf13/viper#276.

Therefore: I've made my own isSet predicate, which checks the flags,
config and environment individually. Since we can't actually check the
environment separately, it has to construct a viper value that _only_
looks at the env, and check that.
squaremo added a commit to fluxcd/flux that referenced this issue Feb 4, 2020
In some places we need to know whether a flag has been explicitly
set. When it was just flags, `pflag.Changed` served this purpose. But
`viper.IsSet`, which is supposed to do the same thing over flags,
config files, and environment entries, is broken:
spf13/viper#276.

Therefore: I've made my own isSet predicate, which checks the flags,
config and environment individually. Since we can't actually check the
environment separately, it has to construct a viper value that _only_
looks at the env, and check that.
squaremo added a commit to fluxcd/flux that referenced this issue Feb 5, 2020
In some places we need to know whether a flag has been explicitly
set. When it was just flags, `pflag.Changed` served this purpose. But
`viper.IsSet`, which is supposed to do the same thing over flags,
config files, and environment entries, is broken:
spf13/viper#276.

Therefore: I've made my own isSet predicate, which checks the flags,
config and environment individually. Since we can't actually check the
environment separately, it has to construct a viper value that _only_
looks at the env, and check that.
squaremo added a commit to fluxcd/flux that referenced this issue Feb 6, 2020
In some places we need to know whether a flag has been explicitly
set. When it was just flags, `pflag.Changed` served this purpose. But
`viper.IsSet`, which is supposed to do the same thing over flags,
config files, and environment entries, is broken:
spf13/viper#276.

Therefore: I've made my own isSet predicate, which checks the flags,
config and environment individually. Since we can't actually check the
environment separately, it has to construct a viper value that _only_
looks at the env, and check that.
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 a pull request may close this issue.

7 participants