Main Methods

We can now combine the previous derivations together to make a main method.

This main method has 2 modes

  1. fully configured from the command line and environment variables
  2. configured from a config file plus overrides

The config file may be JSON or YAML and will be parsed by deriving the associated circe Decoder instances, you can bring your own ones of these.

import com.monovore.decline._
import net.andimiller.recline.annotations._
import net.andimiller.recline.generic._
import io.circe.generic.auto._
case class GraphiteConfig(
  hostname: String,
  port: Int
)
case class Configuration(
  port: Int, 
  @cli.autokebab
  adminPort: Int,
  graphite: Option[GraphiteConfig]
)
val main = deriveCommand[Configuration]("my program", "an example program")
// main: Command[Configuration] = com.monovore.decline.Command@5a9c66d4

main.parse(List("--help"))
// res0: Either[Help, Configuration] = Left(Usage:
//     my program [--port <integer>] [--admin-port <integer>] [[--graphite-hostname <string>] [--graphite-port <integer>] | [--graphite-hostname <string>] [--graphite-port <integer>]] <config>
//     my program [--port <integer>] [--admin-port <integer>] [[--graphite-hostname <string>] [--graphite-port <integer>]]
// 
// an example program
// 
// Options and flags:
//     --help
//         Display this help text.
//     --port <integer>
// 
//     --admin-port <integer>
// 
//     --graphite-hostname <string>
// 
//     --graphite-port <integer>
// 
// 
// Environment Variables:
//     PORT=<integer>
//     
//     ADMIN_PORT=<integer>
//     GRAPHITE_HOSTNAME=<string>
//     GRAPHITE_PORT=<integer>)

So we’ve derived our main method, we can run it with a config file:

main.parse(List("./docs/src/main/resources/example.yml"))
// res1: Either[Help, Configuration] = Right(Configuration(8080,8080,Some(GraphiteConfig(localhost,2003))))

We can run it with a config file and override parts of it from the CLI or env variables:

main.parse(List("./docs/src/main/resources/example.yml", "--port", "1234"), env = Map("ADMIN_PORT" -> "9876"))
// res2: Either[Help, Configuration] = Right(Configuration(1234,9876,Some(GraphiteConfig(localhost,2003))))

We could configure the whole thing via flags:

main.parse(List(
  "--port", "123",
  "--admin-port", "456"
))
// res3: Either[Help, Configuration] = Right(Configuration(123,456,None))