The only downside to the oklog-style seems to be that you can't introspect the full cli tool at runtime, which rules out things like outputting documentation or shell completion files.
The only downside to the oklog-style seems to be that you can't introspect the full cli tool at runtime, which rules out things like outputting documentation or shell completion files.
It's doable, but it was hard and while cobra is a nice library, it's probably overkill unless you're a project like kubernetes.
Most projects in Go are very small in terms of configuration surface, and something like https://github.com/kolide/launcher/blob/9dcf149957b9e9757a24... is much cleaner IMO.
tool [-debug] [-store sqlite] cmd [-opt] [arg]
So, main needs to bootstraps logger and store and then delegate to downstream commands that almost always will consume the store and logger.I'm currently using PersistentPreRunE to bootstrap the logging and store.. but I'm not really happy with the end result and some things are awkward. Maybe it would be less awkward if cobra had a 'Context' I could stick things in. The last issue was I added a version subcommand, which kept creating the store. I ended up having to do
PersistentPreRunE: func(cmd *cobra.Command, args []string) error { return nil },
PersistentPostRunE: func(cmd *cobra.Command, args []string) error { return nil },
Which would have been a lot simpler if I was doing things manually.And you are spot-on regarding closures: it was a design choice made expressly for the purpose of being able to:
- scope command specific flag and args, instead of having one giant catch-all context map
- declare real and typed Go variables instead of something like context.String("--option")
- use the same pattern as the flag std package (flag.Bool, etc.) which I liked a lot
Disclaimer: I am the author of mow.cli