Command Line Subcommands in Fortress

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 with their own sets 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();
        HelpFormatter formatter = new HelpFormatter();

        try {
            switch (subcommand) {
                case "foo":
                    // For every subcommand, we parse its own flags and
                    // have access to trailing positional arguments
                    CommandLine cmd = parser.parse(fooOptions, subcommandArgs);
                    System.out.println("subcommand 'foo'");
                    System.out.println("  enable: " + cmd.hasOption("enable"));
                    System.out.println("  name: " + cmd.getOptionValue("name"));
                    System.out.println("  tail: " + Arrays.toString(cmd.getArgs()));
                    break;
                case "bar":
                    cmd = parser.parse(barOptions, subcommandArgs);
                    System.out.println("subcommand 'bar'");
                    System.out.println("  level: " + cmd.getOptionValue("level"));
                    System.out.println("  tail: " + Arrays.toString(cmd.getArgs()));
                    break;
                default:
                    System.out.println("expected 'foo' or 'bar' subcommands");
                    System.exit(1);
            }
        } catch (ParseException e) {
            System.out.println(e.getMessage());
            formatter.printHelp(subcommand, subcommand.equals("foo") ? fooOptions : barOptions);
            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
Unrecognized option: -enable
usage: bar
 -level <arg>   level

This example demonstrates how to create a command-line application with subcommands in Java. We’ve used the Apache Commons CLI library to parse command-line options, which provides similar functionality to Go’s flag package.

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