Command Line Subcommands in Scala

Here’s the translation of the Go code to Scala, with explanations in Markdown format suitable for Hugo:

Our example demonstrates how to create command-line subcommands in Scala, similar to tools like git where different subcommands (e.g., git commit, git push) have their own set of flags.

import scala.collection.mutable.Map

object CommandLineSubcommands {
  def main(args: Array[String]): Unit = {
    // We declare subcommands and their flags using Maps
    val fooCmd = Map[String, Any](
      "enable" -> false,
      "name" -> ""
    )

    val barCmd = Map[String, Any](
      "level" -> 0
    )

    // The subcommand is expected as the first argument to the program
    if (args.length < 1) {
      println("expected 'foo' or 'bar' subcommands")
      sys.exit(1)
    }

    // Check which subcommand is invoked
    args(0) match {
      // For every subcommand, we parse its own flags and
      // have access to trailing positional arguments
      case "foo" =>
        parseFlags(args.drop(1), fooCmd)
        println("subcommand 'foo'")
        println(s"  enable: ${fooCmd("enable")}")
        println(s"  name: ${fooCmd("name")}")
        println(s"  tail: ${args.drop(fooCmd.size + 1).mkString(", ")}")

      case "bar" =>
        parseFlags(args.drop(1), barCmd)
        println("subcommand 'bar'")
        println(s"  level: ${barCmd("level")}")
        println(s"  tail: ${args.drop(barCmd.size + 1).mkString(", ")}")

      case _ =>
        println("expected 'foo' or 'bar' subcommands")
        sys.exit(1)
    }
  }

  def parseFlags(args: Array[String], cmd: Map[String, Any]): Unit = {
    args.sliding(2, 1).foreach {
      case Array(flag, value) if flag.startsWith("--") =>
        val key = flag.drop(2)
        if (cmd.contains(key)) {
          cmd(key) = cmd(key) match {
            case _: Boolean => value.toBoolean
            case _: Int => value.toInt
            case _: String => value
          }
        }
      case _ => // Ignore other cases
    }
  }
}

To run the program, compile it and use scala:

$ scalac CommandLineSubcommands.scala
$ scala CommandLineSubcommands foo --enable true --name=joe a1 a2
subcommand 'foo'
  enable: true
  name: joe
  tail: a1, a2

Now try the ‘bar’ subcommand:

$ scala CommandLineSubcommands bar --level 8 a1
subcommand 'bar'
  level: 8
  tail: a1

But ‘bar’ won’t accept ‘foo’s flags:

$ scala CommandLineSubcommands bar --enable true a1
subcommand 'bar'
  level: 0
  tail: --enable, true, a1

This example showcases how to implement basic command-line subcommands in Scala. While it doesn’t have a built-in flag parsing library like Go’s flag package, we can achieve similar functionality using Scala’s powerful pattern matching and collections.

Next, we’ll look at environment variables, another common way to parameterize programs.