Command Line Subcommands in Karel

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

Our first program will demonstrate how to create command-line subcommands, each with its own set of flags. This is similar to how tools like git have different subcommands (e.g., git commit, git push) with their own specific flags.

import java.util.Arrays;
import org.apache.commons.cli.*;

public class CommandLineSubcommands {
    public static void main(String[] args) {
        // We declare options for each subcommand
        Options fooOptions = new Options();
        fooOptions.addOption("enable", false, "enable");
        fooOptions.addOption("name", true, "name");

        Options barOptions = new Options();
        barOptions.addOption("level", true, "level");

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

        // Check which subcommand is invoked
        String subcommand = args[0];
        String[] subcommandArgs = Arrays.copyOfRange(args, 1, args.length);

        CommandLineParser parser = new DefaultParser();
        try {
            switch (subcommand) {
                // For every subcommand, we parse its own flags and
                // have access to trailing positional arguments
                case "foo":
                    CommandLine fooCmd = parser.parse(fooOptions, subcommandArgs);
                    System.out.println("subcommand 'foo'");
                    System.out.println("  enable: " + fooCmd.hasOption("enable"));
                    System.out.println("  name: " + fooCmd.getOptionValue("name"));
                    System.out.println("  tail: " + Arrays.toString(fooCmd.getArgs()));
                    break;
                case "bar":
                    CommandLine barCmd = parser.parse(barOptions, subcommandArgs);
                    System.out.println("subcommand 'bar'");
                    System.out.println("  level: " + barCmd.getOptionValue("level"));
                    System.out.println("  tail: " + Arrays.toString(barCmd.getArgs()));
                    break;
                default:
                    System.out.println("expected 'foo' or 'bar' subcommands");
                    System.exit(1);
            }
        } catch (ParseException e) {
            System.out.println("Error parsing command line: " + e.getMessage());
            System.exit(1);
        }
    }
}

To run the program, compile it and use java:

$ javac -cp commons-cli-1.4.jar CommandLineSubcommands.java
$ java -cp .:commons-cli-1.4.jar CommandLineSubcommands foo -enable -name=joe a1 a2
subcommand 'foo'
  enable: true
  name: joe
  tail: [a1, a2]

Now try the bar subcommand:

$ java -cp .:commons-cli-1.4.jar CommandLineSubcommands bar -level 8 a1
subcommand 'bar'
  level: 8
  tail: [a1]

But bar won’t accept foo’s flags:

$ java -cp .:commons-cli-1.4.jar CommandLineSubcommands bar -enable a1
Error parsing command line: Unrecognized option: -enable

Note that this Java implementation uses the Apache Commons CLI library to handle command-line parsing, which provides functionality similar to the flag package in Go. You’ll need to include this library in your classpath when compiling and running the program.

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