fsprojects / Argu

A declarative CLI argument parser for F#
https://fsprojects.github.io/Argu
MIT License
453 stars 75 forks source link

Integration with IConfiguration #162

Closed absolutejam closed 3 years ago

absolutejam commented 3 years ago

Description

I currently have an established pattern of using .net core's IConfiguration to parse json, yaml, env vars, etc. to POCOs which then go through a parsing layer to convert them to F# records (eg. Nullable<in> to int option). This approach has a little more ground work but provides really neat, type-safe configuration types in the end.

I was hoping I could use Argu to contribute to my existing IConfiguration-based setup, but from what I can tell, the IConfigurationReader provided by Argu are for reading settings in to Argu. And since I already have a parsing layer and type-safe configuration, I'd like to be able to keep with that and have Argu contribute to it, not rely on Argu for the parsing (and some of my apps have no CLI access at all).

So quite simply, Is there any easy way to integrate Argu with IConfiguration in this manner? Ultimately IConfiguration is just a big dictionary so it's easy enough to build up, but I just need to get the information out of Argu first.

What I'm thinking at the moment is:

I'm looking at this purely through the public lenses - Is it possible there's an even easier way that could be contributed to Argu?

eiriktsarpalis commented 3 years ago

Argu exposes an interface for abstracting key/value reads. It looks like writing an adapter for IConfiguration should be relatively straightfoward.

absolutejam commented 3 years ago

Just to clarify, is that for pulling external k/v data into Argu, or can it be leveraged as a mechanism to also get it out?

Writing an adapter for pulling IConfiguration into Argu seems simple enough, but I want to do the inverse.

Or have I completely missed your point? (sorry!)

eiriktsarpalis commented 3 years ago

Writing an adapter for pulling IConfiguration into Argu seems simple enough, but I want to do the inverse.

I might have misunderstood what you were asking. The library was never really designed with such concerns in mind, I'm not sure how to best approach the problem.

absolutejam commented 3 years ago

I just didn't know if there was any kind of post-processing callback that could simply dump each entry into IConfiguration based on the AppSettingsName value which already exists.

I know there is a PostProcessResults method but my understanding is that you'd still need to manually implement the callback for each DU case? At bare minimum, if I could provide a way to iterate the results with a DU' -> (), I could at manually implement what I need (with exhaustiveness checking from the compiler), but I'm not really comfortable enough with expressions to be able to provide a solution with this.

I think the ideal solution would be variation of PostProcessResults that could spit out something like what GetArgumentCases() provides, along with the parsed value, but that could lead to issues with returning different types/obj.

If this was a possibility, it would mean Argu could effortlessly plug into other libraries/patterns :wink:

EDIT: At a cursory glance, it looks like I could possibly iterate over parser.ParseCommandLine([||]).GetAllResults() with a function that matches a DU case to a IConfiguration path, but it feels a bit hacky compared to the rest of the amazing, declarative API provided by Argu.

absolutejam commented 3 years ago

Just wanted to say that I've moved my configuration to use Argu as a the centralised API (wrapping IConfiguration), and I'll try out some custom configuration readers to pull from other sources.

absolutejam commented 3 years ago

So I took the plunge and moved all my config to use Argu as the single API, but I'm getting the following when I define CustomAppSettings in my subcommands:

ERROR: CustomAppSettings in GlobalParameters.Es_Source not supported in subcommands.

which is here.

Was the a reason this was added, or was it just because the functionality was not implemented?

absolutejam commented 3 years ago

Sorry, it looks like the above error was because I added CustomAppSettings to a subcommand, eg.

  | [<CliPrefix(CliPrefix.None); Unique; Last; CustomAppSettings("Foo")>] Es_Source       of ParseResults<EventStoreSourceParameters>

However, it looks like actual subcommand DU cases are not parsed for CustomAppSettings so I can't see a way of defining & consuming their equivalent IConfiguration path.

deviousasti commented 3 years ago

Same error - the ConfigurationReader doesn't seem to be inherited by the sub-command parser.

eiriktsarpalis commented 3 years ago

This is by design. IConfigurationReader is a flat key/value reader abstraction which is not compatible with the tree-like structure of subcommand syntax.