-
Notifications
You must be signed in to change notification settings - Fork 2k
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
BindPFlags functionality does not seem to match documentation #375
Comments
After reviewing [this pull request](spf13/viper#396) under the Viper project, in response to my [filed issue](spf13/viper#375), I've attempted to follow the updated README in said pull request. My main problem is that Viper expects PFlags ( BindPFlags() ), but Cobra only exposes Flags via the Flags() method.
I too just ran across something similar: This seem to have been working at some point for me
When looking up:
Update I discovered this quit working when I used the same flag name in a different command. Not sure if this is in the docs somewhere, but changing out |
Any updates? |
1 similar comment
Any updates? |
Thanks @juztin for your solution. Just to clarify; if one wants to use the i.e.: // constants.go (used by both commands)
var (
serverHostPortFlag string
configFileFlag string
)
// cmd2.go
deleteCmd.PersistentFlags().StringVarP(&serverHostPortFlag, serverHostPortKey, "s", constants.DHCPDDHostPortDefault, constants.HostPortDocs) |
Ran into this as well. This did not work as I had expected: err := viper.BindPFlags(cmd.Flags())
fmt.Printf("bind error: %v\n", err)
cobraValue, err := cmd.Flags().GetString("server_socket")
fmt.Printf("Cobra value: %s, err: %v\n", cobraValue, err)
fmt.Printf("Viper value: %s\n", v.GetString("server_socket")) Result: $ go run main.go serve --server_socket=127.0.0.1:2222
bind error: <nil>
Cobra value: 127.0.0.1:2222, err: <nil>
Viper value: 127.0.0.1:1111 However, iterating over those flags and binding them individually does work: cmd.Flags().VisitAll(func (flag *pflag.Flag) {
v.BindPFlag(flag.Name, flag)
})
fmt.Printf("Viper: %s\n", v.GetString("server_socket")) $ go run main.go serve --server_socket=127.0.0.1:2222
Viper: 127.0.0.1:2222 No changes to the flags themselves in between "not working" and "working". These are persistent flags, but not of the |
Piping in late, but I just wanted to add my .02 here... I've stumbled upon the same issue as all of you. In my case, I'm not using Cobra or any kind of CLI properly speaking, but rather just launching a Web app service that I intend to configure from a And obviously, I'm assuming a certain (fixed) priority: compile-time values first, then environment, then flags, and finally In other words, I'd like to have the exact same functionality as To add to the confusion, I'm an amateur programmer, who spent way too long tinkering with PHP for her own good :) One of the 'bad habits' I picked up was to get all flags inside some sort of meta-structure — just to be aware that some variables are 'special' in some way and not 'regular' variables. Sometimes I use string maps — when I know in advance that all flags will be strings — but it's more often to have just a Storing configuration items in string maps has the advantage that tricks such as the one provided by @kalzoo would work nicely — at the cost of forcing every configuration item to be a string. Granted, I could have a map of interfaces... but one ought to wonder why I'm duplicating the very same internal configuration that Viper is using...? Wouldn't it make sense to simply use the map that Viper already uses? (sure, it's just pointers, so no memory is wasted except a few bytes of overhead, but still...) Here is what ultimately broke everything for me: To keep command-line flags with Well, here's the catch... However, when using So let's assume the following scenario: Under [configuration]
hostname = "my.host.name"
port = 3133 # integer
scheme = "HTTP://" ... and let's assume I invoke my compiled app with Viper will start by adding But when reading from the From the perspective of the programmer, we now have two branches on the tree, one that is being updated through command-line flags (fixed at run-time) and resides at the tree root; and another that gets updated via configuration files (which can be dynamically changed by writing new values on the file), under a subtree/new node. The names at the leaves are identical, but, of course, Viper has no problem with that. It's just the programmer that needs to handle that. My admittedly naïve approach was simple: I don't care what Viper thinks that its own internal structure should be. Instead, I just use my own structure instead. When reading from The theory is that I could manually check if a configuration string is present in the Alas, whatever approach I use, 'nothing works' — in other words, because configuration variables are inherently different between Why? My guess is that 'my' configuration struct is basically just pointers — pointing to content stored somewhere inside Viper's structures. When new values are loaded by Viper (via This is just too much for my meagre skills to figure out what exactly is happening backstage. The plain, simple truth is that Viper, working in these mysterious ways, is not usable for my own purposes; I might have to switch back to |
LOL, that's a giant wall of text. To answer the original issue: I think Another important thing (I guess this could be better highlighted in the docs) is that binding a FlagSet will only bind the existing flags in that set. Any flags defined later won't be bound. To your point @GwynethLlewelyn: The issue you raise has nothing to do with Yes, Viper is somewhat opinionated, but that's what makes it simple at the same time. As far as I see your problem is with INI section names being part of the config key, thus not matching with your flag names. This seems to be the logical behavior to me though. Personally, I'd suggest avoiding INI all together. Use a sane format, like JSON or YAML. Lastly, I'm not sure I understand your explanation about pointers. Everything you described seems to work like it should be even if it doesn't match your expectations. If you have a reproducible problem, please open a separate issue with sufficient details that allows us to debug it. Thank you! I'm closing this issue because as far as I can tell the problems described here are user errors. If you think you found a bug a though, feel free to open a new issue with more details. Thanks! |
Just for the record, my own issue was solved, thanks to this comment:
You're absolutely right! Four years ago or so, when I first used Viper, I was using TOML (not much saner than INI, but slightly better). Everything worked back then, so — I thought — why not go for INI this time? After all, the differences are minimal. Well, guess what: they are not minimal at all. By switching from Thanks so much for your suggestion! 🙏 (Granted, I could drop TOML — which is not perfect, by far — and go with JSON or YAML, but in my particular scenario, the |
When you bind individual flags using However, when you bind all of the flags at once using For example: viper.BindPFlag("campaign.name", campaignCmd.PersistentFlags().Lookup("name"))
viper.BindPFlag("campaign.description", campaignCmd.PersistentFlags().Lookup("description")) will expects the following configuration: campaign:
name: test
description: test using: viper.BindPFlags(campaignCmd.PersistentFlags()) would expect the following configuration: description: test
name: test |
I've followed the README's example of how to bind flags into viper, but when I try to use the BindFlags() method versus explicitly binding flags by name, there's some sort of disconnect, the values never make it into viper. Minimal test case below.
The documentation ( https://godoc.org/github.com/spf13/viper#BindPFlags ) seems to indicate that this should be all that's necessary to allow config value lookups to also reference set flags. I do not discount the possibility that I'm misunderstanding but because the README only covers explicitly binding individual flag values I can't be sure.
The confusion here is that the code compiles and runs without complaint using
BindPFlags()
but values passed via command-line don't seem to be available via viper'sGet*
methods.My application will eventually have dozens upon dozens of commands, subcommands, and flag sets with common and uncommon flags between each. I'd like to be able to bind-once and not have to update my bindings any time I move, rename, or add flags.
The text was updated successfully, but these errors were encountered: