{"action":"created","issue":{"url":"https://api.github.com/repos/kbknapp/clap-rs/issues/748","repository_url":"https://api.github.com/repos/kbknapp/clap-rs","labels_url":"https://api.github.com/repos/kbknapp/clap-rs/issues/748/labels{/name}","comments_url":"https://api.github.com/repos/kbknapp/clap-rs/issues/748/comments","events_url":"https://api.github.com/repos/kbknapp/clap-rs/issues/748/events","html_url":"https://github.com/kbknapp/clap-rs/issues/748","id":189005047,"number":748,"title":"Feature request – allow parsing options from a config file instead of command line arguments","user":{"login":"casey","id":1945,"avatar_url":"https://avatars.githubusercontent.com/u/1945?v=3","gravatar_id":"","url":"https://api.github.com/users/casey","html_url":"https://github.com/casey","followers_url":"https://api.github.com/users/casey/followers","following_url":"https://api.github.com/users/casey/following{/other_user}","gists_url":"https://api.github.com/users/casey/gists{/gist_id}","starred_url":"https://api.github.com/users/casey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/casey/subscriptions","organizations_url":"https://api.github.com/users/casey/orgs","repos_url":"https://api.github.com/users/casey/repos","events_url":"https://api.github.com/users/casey/events{/privacy}","received_events_url":"https://api.github.com/users/casey/received_events","type":"User","site_admin":false},"labels":[{"id":236425856,"url":"https://api.github.com/repos/kbknapp/clap-rs/labels/C:%20parsing","name":"C: parsing","color":"fad8c7","default":false},{"id":236422310,"url":"https://api.github.com/repos/kbknapp/clap-rs/labels/D:%20intermediate","name":"D: intermediate","color":"d4c5f9","default":false},{"id":207220970,"url":"https://api.github.com/repos/kbknapp/clap-rs/labels/E:%20optional%20dep","name":"E: optional dep","color":"fef2c0","default":false},{"id":236421102,"url":"https://api.github.com/repos/kbknapp/clap-rs/labels/P4:%20nice%20to%20have","name":"P4: nice to have","color":"bfe5bf","default":false},{"id":188562498,"url":"https://api.github.com/repos/kbknapp/clap-rs/labels/T:%20new%20feature","name":"T: new feature","color":"bfd4f2","default":false},{"id":263619952,"url":"https://api.github.com/repos/kbknapp/clap-rs/labels/W:%202.x","name":"W: 2.x","color":"bfdadc","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":5,"created_at":"2016-11-13T23:56:57Z","updated_at":"2016-11-24T05:36:20Z","closed_at":null,"body":"I wrote up a sketch of how this might look here:\r\n\r\nhttps://github.com/casey/clap-config\r\n\r\nBasically, it would be pretty cool to generate a simple config file parser from a clap argument parser. There's a longer description of some use cases in the readme, but it would be great for projects which are configurable with both the command line and a config file, and for helping projects add config file configuration in addition to command line configuration."},"comment":{"url":"https://api.github.com/repos/kbknapp/clap-rs/issues/comments/262694173","html_url":"https://github.com/kbknapp/clap-rs/issues/748#issuecomment-262694173","issue_url":"https://api.github.com/repos/kbknapp/clap-rs/issues/748","id":262694173,"user":{"login":"ssokolow","id":46915,"avatar_url":"https://avatars.githubusercontent.com/u/46915?v=3","gravatar_id":"","url":"https://api.github.com/users/ssokolow","html_url":"https://github.com/ssokolow","followers_url":"https://api.github.com/users/ssokolow/followers","following_url":"https://api.github.com/users/ssokolow/following{/other_user}","gists_url":"https://api.github.com/users/ssokolow/gists{/gist_id}","starred_url":"https://api.github.com/users/ssokolow/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ssokolow/subscriptions","organizations_url":"https://api.github.com/users/ssokolow/orgs","repos_url":"https://api.github.com/users/ssokolow/repos","events_url":"https://api.github.com/users/ssokolow/events{/privacy}","received_events_url":"https://api.github.com/users/ssokolow/received_events","type":"User","site_admin":false},"created_at":"2016-11-24T05:36:20Z","updated_at":"2016-11-24T05:36:20Z","body":"> I'm not sure I really buy this. If I have a flag --foo that takes a value N, then it seems reasonable for me to want to assign a default value to it in a config file, but retain the right to want to override it on the actual command line. Depending on how the --foo flag was defined, this might not be allowed in the form of --foo X --foo Y, so a config file might need special handling?\r\n\r\nYou misunderstand. I made only two claims and neither was that `Conflict` should be mandatory within a single source. Those two claims are:\r\n\r\n1. `Conflict` never produces a worthwhile behaviour when applied to two pieces of data from different sources.\r\n2. Regardless of how `MergeType` behaviour is handled, it is entirely internal to the parsing of each individual source.\r\n\r\nWhat I'm arguing is that:\r\n\r\n1. If we're doing fine without `MergeType` now, there's nothing about adding support for configuration files which adds it to the list of requirements.\r\n2. If we need `MergeType` urgently and implement it before config file support, no beneficial functionality can be gained by expanding that \"within a single source\" implementation to also operate between multiple sources.\r\n\r\nHence, orthogonal.\r\n\r\n**First,** let's discuss the \"never produces worthwhile behaviour\" point, starting with a few examples:\r\n\r\n1. If `~/.user_default` can't override `/etc/global_default`, then that's bad.\r\n2. If `--one-time-setting` can't override either of those, then that's bad.\r\n3. If `~/.defaults_a` and `~/.defaults_b` don't have a defined precedence order, you're forcing users to manage pointless busywork in the best case and, in the worst case, you wind up with a \"FAT table copies 1 and 2 disagree? Which one did you intend?\" situation.\r\n\r\nThis derives from two issues:\r\n\r\n1. If at all possible, you want to have a single, authoritative source for settings to limit the potential for human error.\r\n2. Multiple sources of configuration are introduced specifically to take advantage of defined-precedence overriding to allow customizing in progressively narrower scopes. (eg. site, user, project, task)\r\n\r\nOr, let's come at it from the other direction and address `Override`, `Defaults`, and `Conflict` as options.\r\n\r\n`Defaults` needs no justification. When applied to reconcile data from two different sources, it implements the behaviour configuration files serve in every case I've ever encountered.\r\n\r\n`Conflict` is the hardest to justify because:\r\n\r\n* If you're the administrator, it just cripples the utility of the config file if you can't put anything into it which you might want to override on a task-by-task basis. (And then people end up implementing *another* layer of default handing using a wrapper which passes in `--foo=false` unless you call it with `--foo=true`.)\r\n* If you're not the administrator, it means \"You can't specify --foo=true because `/etc/config_defaults` specified `foo=false`\".\r\n\r\nThe former case is counter-productive and the latter sounds like trying to kitchen-sink some kind of user permissions system into clap when that's a job for code which runs after clap is done.\r\n\r\nFinally, `Override` is just `Defaults` with the ordering swapped, so it's only justifiable in the one case where you can't swap the order: The command-line arguments, which must always be the last in the chain.\r\n\r\nThe problem is that, by their very nature, command-line arguments are also the most suitable for one-off overrides, which means that there is no justifiable reason to use `Override` to silently ignore what the user specified on the command-line because some config file somewhere disagrees.\r\n\r\nTherefore, it's much better to just make defined-precedence overriding an inherent, unavoidable feature of how conflicts between multiple sources are resolved. It's the de facto standard way to handle things and it's the only solution which addresses all of the concerns I brought up.\r\n\r\n...it's also easy for people to conceptualize. For example, in Python (since it's pseudocode-like):\r\n```python\r\nmatches = dict()\r\nmatches.update(parse_global_config())\r\nmatches.update(parse_local_config())\r\nmatches.update(parse_command_line_args())\r\n```\r\n\r\n**Therefore,** the concept of `MergeType` is only meaningful within the process of parsing a single source, because merging input from multiple sources should always `Override`.\r\n\r\nWe may indeed need to discuss the `MergeType` idea more, but the conclusion we come to has no bearing on a well-designed multi-source implementation.\r\n\r\n1. Parse command-line input\r\n2. Parse one or more config files (optionally with a source file specified in step 1 via `--config-file` or the like)\r\n3. Merge the results using a simple \"When in doubt, the last to speak wins\" algorithm.\r\n\r\nThe only potential kink I see is to at least warn users that step 3 might reset `config_file` so it's not the actual value used if the config file itself contains a `config_file` value.\r\n\r\n**The beauty of this approach** is that it's made of very small, very extensible pieces and you can get a lot of utility early on, then amend it later. Here are some example steps:\r\n\r\n1. Split the `argv` parsing out from the rest so that anyone can implement the connecting interface on top of a JSON/TOML/etc. parser. (Now, even if they have to manually hook up the config parser and manually merge things, users don't have to reinvent clap's \"apply the validation\" code in between those two steps.)\r\n2. Add a simple function for merging two parse results. (Now users don't have to manually merge entry-by-entry anymore.)\r\n3. Anything else you think is necessary.\r\n\r\nWhat I'm envisioning is that the `argv`-parsing side of the interface would take a reference it could use to query the schema-validation side to disambiguate things that would be inherent in the framing of some formats but not others. For example:\r\n\r\n* Please resolve this key name (so `argv` can resolve command-line shorthands like `-s` without complaint while config files can print a deprecation message or exit with a failure message asking the user if they meant `sidechannel_data=...` in `config.cfg`)\r\n* What type of value does this key take? (so parsers can perform any additional transformations needed, like `argv` deciding whether `--foo --bar` actually means `--foo=--bar`)"}}
{"actor":{"display_login":"ssokolow"}}