diff --git a/README-CHANGES.xml b/README-CHANGES.xml index 5b46439..e550185 100644 --- a/README-CHANGES.xml +++ b/README-CHANGES.xml @@ -95,15 +95,20 @@ - + - + + + + + + diff --git a/com.io7m.jpra.compiler.frontend/pom.xml b/com.io7m.jpra.compiler.frontend/pom.xml index 683d879..7a83860 100644 --- a/com.io7m.jpra.compiler.frontend/pom.xml +++ b/com.io7m.jpra.compiler.frontend/pom.xml @@ -45,8 +45,8 @@ - io.airlift - airline + com.beust + jcommander org.slf4j @@ -78,7 +78,7 @@ false - true + false jpra-c true diff --git a/com.io7m.jpra.compiler.frontend/src/main/java/com/io7m/jpra/compiler/frontend/Main.java b/com.io7m.jpra.compiler.frontend/src/main/java/com/io7m/jpra/compiler/frontend/Main.java index ae988d0..9f34852 100644 --- a/com.io7m.jpra.compiler.frontend/src/main/java/com/io7m/jpra/compiler/frontend/Main.java +++ b/com.io7m.jpra.compiler.frontend/src/main/java/com/io7m/jpra/compiler/frontend/Main.java @@ -18,6 +18,10 @@ import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; +import com.beust.jcommander.JCommander; +import com.beust.jcommander.Parameter; +import com.beust.jcommander.ParameterException; +import com.beust.jcommander.Parameters; import com.io7m.jpra.compiler.core.JPRAProblemFormatter; import com.io7m.jpra.compiler.core.JPRAProblemFormatterType; import com.io7m.jpra.compiler.core.checker.JPRACheckerStandardCapabilities; @@ -35,22 +39,16 @@ import com.io7m.jpra.model.names.TypeName; import com.io7m.jpra.model.types.TypeUserDefinedType; import com.io7m.junreachable.UnreachableCodeException; -import io.airlift.airline.Arguments; -import io.airlift.airline.Cli; -import io.airlift.airline.Command; -import io.airlift.airline.Help; -import io.airlift.airline.Option; -import io.airlift.airline.ParseArgumentsMissingException; -import io.airlift.airline.ParseArgumentsUnexpectedException; -import io.airlift.airline.ParseOptionMissingException; import org.slf4j.LoggerFactory; import java.io.IOException; import java.nio.file.Paths; -import java.util.Collections; +import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Queue; import java.util.stream.Collectors; @@ -66,9 +64,28 @@ public final class Main LOG = (Logger) LoggerFactory.getLogger(Main.class); } - private Main() + private final String[] args; + private final HashMap commands; + private final JCommander commander; + private int exit_code; + + private Main( + final String[] in_args) { - throw new UnreachableCodeException(); + this.args = + Objects.requireNonNull(in_args, "Command line arguments"); + + final CommandCheck check = new CommandCheck(); + final CommandGenerateJava generate = new CommandGenerateJava(); + + this.commands = new HashMap<>(8); + this.commands.put("check", check); + this.commands.put("generate", generate); + + this.commander = new JCommander(); + this.commander.setProgramName("jpra-c"); + this.commander.addCommand("check", check); + this.commander.addCommand("generate", generate); } /** @@ -77,29 +94,52 @@ private Main() * @param args Command line arguments */ - public static void main(final String[] args) + public static void main( + final String[] args) { - final Cli.CliBuilder builder = Cli.builder("jpra"); - builder.withDescription("Packed record access compiler"); - builder.withDefaultCommand(Help.class); - builder.withCommand(Help.class); - builder.withCommand(CommandCheck.class); - builder.withCommand(CommandGenerateJava.class); - final Cli parser = builder.build(); + final Main cm = new Main(args); + cm.run(); + System.exit(cm.exitCode()); + } + private int exitCode() + { + return this.exit_code; + } + + private void run() + { try { - parser.parse(args).run(); - } catch (final ParseArgumentsMissingException - | ParseOptionMissingException - | ParseArgumentsUnexpectedException e) { - LOG.error("parse error: {}", e.getMessage()); - Help.help(parser.getMetadata(), Collections.emptyList()); + this.commander.parse(this.args); + + final String cmd = this.commander.getParsedCommand(); + if (cmd == null) { + final StringBuilder sb = new StringBuilder(128); + this.commander.usage(sb); + LOG.info("Arguments required.\n{}", sb.toString()); + this.exit_code = 1; + return; + } + + final CommandType command = this.commands.get(cmd); + final CommandType.Status status = command.run(); + this.exit_code = status.exitCode(); + } catch (final ParameterException e) { + final StringBuilder sb = new StringBuilder(128); + this.commander.usage(sb); + LOG.error("{}\n{}", e.getMessage(), sb.toString()); + this.exit_code = 1; + } catch (final Exception e) { + LOG.error("{}", e.getMessage(), e); + this.exit_code = 1; } } - abstract static class CommandType implements Runnable + abstract static class CommandType { - @Option(name = "--debug", description = "Enable debug logging") + @Parameter( + names = "--debug", + description = "Enable debug logging") private boolean debug; CommandType() @@ -107,6 +147,8 @@ abstract static class CommandType implements Runnable } + protected abstract Status run(); + protected final void setup() { final Logger root = (Logger) LoggerFactory.getLogger( @@ -115,23 +157,42 @@ protected final void setup() root.setLevel(Level.TRACE); } } + + enum Status + { + SUCCESS, + FAILURE; + + int exitCode() + { + switch (this) { + case SUCCESS: + return 0; + case FAILURE: + return 1; + } + throw new UnreachableCodeException(); + } + } } /** * A check command. */ - @Command(name = "check", description = "Check a list of packages") + @Parameters(commandDescription = "Check a list of packages") public static final class CommandCheck extends CommandType { - @Option( - arity = 1, + @Parameter( description = "Source directory", - name = "--source-directory", - required = true) private String source_directory; - @Arguments( - description = "Packages to be checked", - required = true) private List packages; + names = "--source-directory", + required = true) + private String source_directory; + + @Parameter( + description = "Packages to be checked (may be specified multiple times)", + names = "--package") + private List packages = new ArrayList<>(); /** * Construct a command. @@ -143,7 +204,7 @@ public CommandCheck() } @Override - public void run() + public Status run() { this.setup(); @@ -179,9 +240,9 @@ public void run() } if (error) { - System.exit(1); + return Status.FAILURE; } - System.exit(0); + return Status.SUCCESS; } } @@ -189,22 +250,27 @@ public void run() * A {@code generate-java} command. */ - @Command(name = "generate-java", description = "Generate Java code") + @Parameters(commandDescription = "Generate Java code") public static final class CommandGenerateJava extends CommandType { - @Option( + @Parameter( arity = 1, description = "Source directory", - name = "--source-directory", - required = true) private String source_directory; - @Option( + names = "--source-directory", + required = true) + private String source_directory; + + @Parameter( arity = 1, description = "Target directory", - name = "--target-directory", - required = true) private String target_directory; - @Arguments( - description = "Packages to be exported", - required = true) private List packages; + names = "--target-directory", + required = true) + private String target_directory; + + @Parameter( + description = "Packages to be exported (may be specified multiple times)", + names = "--package") + private List packages = new ArrayList<>(); /** * Construct a command. @@ -216,7 +282,7 @@ public CommandGenerateJava() } @Override - public void run() + public Status run() { this.setup(); @@ -276,9 +342,9 @@ public void run() System.err.flush(); if (error) { - System.exit(1); + return Status.FAILURE; } - System.exit(0); + return Status.SUCCESS; } } } diff --git a/com.io7m.jpra.documentation/src/main/resources/com/io7m/jpra/documentation/p-tools.xml b/com.io7m.jpra.documentation/src/main/resources/com/io7m/jpra/documentation/p-tools.xml index c262213..ba4130b 100644 --- a/com.io7m.jpra.documentation/src/main/resources/com/io7m/jpra/documentation/p-tools.xml +++ b/com.io7m.jpra.documentation/src/main/resources/com/io7m/jpra/documentation/p-tools.xml @@ -10,14 +10,34 @@ Options [] +Usage: jpra [command] [command options] + Commands: + check Check a list of packages + Usage: check [options] + Options: + --debug + Enable debug logging + Default: false + --package + Packages to be checked (may be specified multiple times) + Default: [] + * --source-directory + Source directory -The most commonly used jpra commands are: - check Check a list of packages - generate-java Generate Java code - help Display help information + generate Generate Java code + Usage: generate [options] + Options: + --debug + Enable debug logging + Default: false + --package + Packages to be exported (may be specified multiple times) + Default: [] + * --source-directory + Source directory + * --target-directory + Target directory -See 'jpra help ' for more information on a specific command. ]]> @@ -35,7 +55,7 @@ See 'jpra help ' for more information on a specific command. Checking sources @@ -59,7 +79,7 @@ $ java -jar jpra.jar check --source-directory p com.io7m.example Checking sources diff --git a/pom.xml b/pom.xml index f7dc592..31a479d 100644 --- a/pom.xml +++ b/pom.xml @@ -179,7 +179,7 @@ org.slf4j slf4j-api - 1.8.0-beta0 + 1.7.25 ch.qos.logback @@ -197,9 +197,9 @@ 3.7 - io.airlift - airline - 0.8 + com.beust + jcommander + 1.72 org.immutables