quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.5k stars 2.6k forks source link

Picocli command options exposed as ConfigSources #19128

Open rivasdiaz opened 3 years ago

rivasdiaz commented 3 years ago

Description

I would like to be able to map parameters parsed for a picocli command to config properties. The simplest case would be to have commands available as a configuration sources.

Use case:

Allow the developer to specify host, username and/or password for a database connection to be parameters, which may have (in some cases) predefined defaults.

If I use Quarkus Database support, the username and password should be defined as properties and I can't override the property once the Picocli command is parsed. I attempted to define a ConfigSource backed by a map in memory and populate from the command implementation, but by the time the Picocli command is instantiated, the Config Sources are already instantiated. I also attempted modifying a system property from the Command which doesn't work either.

Currently the solution I found was defining a new property, for example username, then define in my application.properties the following property quarkus.datasource.username=${username}. The user can then pass -Dusername=<username> to the application. This approach works, but doesn't show up listed by --help and is not the most common form which could be using --username or -u.

Implementation ideas

Ideally a Quarkus application using the Picocli extension would define config sources for each defined command, probably opting-in with an annotation. This annotation may also define a prefix for the introduced properties.

An example:

org/example/mycli/MyCliCommand.java


@io.quarkus.picocli.ConfigSource(prefix = "org.example.mycli")
@picocli.CommandLine.Command(name = "mycli", mixinStandardHelpOptions = true)
public class MyCliCommand implements Runnable {
@picocli.CommandLine.Option(names = {"--logging-level"}, description = "Logging level", defaultValue = "WARNING")
String logginglevel; // exposed as the property: org.example.mycli.logginglevel

@picocli.CommandLine.Option(names = {"-e", "--env"}, description = "Target environment", defaultValue = "dev")
String env; // exposed as the property: org.example.mycli.env

// ... other parameters

public void run() { /* do something */ }

}


> application.properties
```properties
quarkus.log.category."io.quarkus".level=WARNING
quarkus.log.category."org.example.mycli".level=${org.example.mycli.logginglevel}
quarkus.datasource.jdbc.url=jdbc:postgresql://${org.example.mycli.env}.db.example.org/mydb

Finally, by using advanced support in picocli, a developer could validate or transform the user specified parameters. For example instead of defining the logginglevel, the option could be verbose, and with the help of a converter, transform the input to the values INFO or WARNING. This way the user of the cli could specify --verbose instead of --logging-level=INFO.

quarkus-bot[bot] commented 3 years ago

/cc @ebullient, @gsmet, @maxandersen

ebullient commented 2 years ago

I've been thinking about this, too.

I'm thinking we have a few options:

rivasdiaz commented 2 years ago

I definitely see uses for application.properties and .env files on a CLI app.

I can add to my main application.properties all settings I don't need user input for, and that file will end either inside an uberjar or processed while building a native binary. For .env files, although I haven't used them with quarkus, at work we have a couple of python cli tools which store some properties (that are global for the user) in .env files and I have found that functionality useful.

That said, I expect having support for a ConfigSource (or similar mechanism that lets me configure quarkus components) on top of command line options to be way more valuable for CLI apps than a ConfigSource for application.properties so if the later were blocking the former, personally I would be happy with a special configuration support on CLI apps even at the cost of disabling all other modes.

ebullient commented 2 years ago

To be clear: application.properties would still be read/used at build time. I am specifically talking about implicit/assumed runtime processing of application.properties or .env files (as that applies to running a command line application from an arbitrary location)