Argu icon indicating copy to clipboard operation
Argu copied to clipboard

Feature idea: Declarative fall-back to environment variables including automatic --help

Open bartelink opened this issue 5 years ago • 3 comments

TL;DR add a [<AltEnvVar "envvarname">] or similar attribute, facilitating ability to supply values via environment variables including integrating into usage text

CURRENT

In some layout conventions, it's established practice to have required settings generally be supplied via environment variables, but admitting overrides in a local context via commandline arguments. This yields a clean way to define all configurable settings for a given program

In this mode, Parameters like:

    type Parameters =
        | [<AltCommandLine "-b"; Unique>]   Broker of string
        | [<AltCommandLine "-t"; Unique>]   Topic of string

are processed by a helper that a) accepts the argument if supplied b) otherwise falls back to the environment variable c) provides a message as to the missing argument and related environment variable in the startup failure message if neither are supplied:

    type Arguments(a : ParseResults<Parameters>) =
        member __.Broker = a.TryGetResult Broker |> defaultWithEnvVar "KAFKA_BROKER" "Broker" |> Uri
        member __.Topic =  a.TryGetResult Topic  |> defaultWithEnvVar "KAFKA_TOPIC"  "Topic"

this however brings the burden of keeping the related usage message in sync:

        interface IArgParserTemplate with
            member a.Usage =
                match a with
                | Broker _ -> "specify Kafka Broker, in host:port format. (optional if environment variable KAFKA_BROKER specified)."
                | Topic _ ->  "specify Kafka Topic name. (optional if environment variable KAFKA_TOPIC specified)."

PROPOSAL

the suggestion is to allow the above to be expressed via:

    type Parameters =
        | [<AltEnvVar "KAFKA_BROKER"; AltCommandLine "-b"; Required>] Broker of string
        | [<AltEnvVar "KAFKA_TOPIC";  AltCommandLine "-t"; Required>] Topic of string

(note Required is now possible)

    type Arguments(a : ParseResults<Parameters>) =
        member __.Broker =     a.GetResult Broker |> Uri
        member __.Topic =      a.GetResult Topic

(note no helpers required)

        interface IArgParserTemplate with
            member a.Usage =
                match a with
                | Broker _ ->  "specify Kafka Broker, in host:port format."
                | Topic _ ->   "specify Kafka Topic name."

(note no mention of the env vars)

bartelink avatar Mar 04 '20 11:03 bartelink

Related to #63. It's trivial to provide an IConfigurationReader implementation that reads from the environment. The key can be modified using the CustomAppSettings attribute.

eiriktsarpalis avatar Mar 04 '20 12:03 eiriktsarpalis

Yes, I was aware of that, but, unless I'm mistaken ... that mechanism doesn't yet provide for the error message and help messages to reference the related env var by name? (was posting this with the intent of "someone" broadening the impl such that it enables that simplified usage but, critically, provides correct error and help messages?)

bartelink avatar Mar 04 '20 14:03 bartelink

I can't think of a good way to surface those environment variable names automagically in a way that works for everyone. For the sake of DRY you could perhaps use a literal string that is passed in both the attribute and to build the usage string.

eiriktsarpalis avatar Mar 04 '20 14:03 eiriktsarpalis