diff --git a/CHANGE_LOG.md b/CHANGE_LOG.md index a404a5e..7dfd7fc 100644 --- a/CHANGE_LOG.md +++ b/CHANGE_LOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Changed - Updated dependencies to latest bugfix release (gson, okhttp, commons-codec, slf4j, alloy) +- (GH-16) Switched from args4j CLI parsing to picocli, as args4j no longer seems actively maintained ## [0.2.1] ### Changed diff --git a/build.gradle b/build.gradle index 0cd2e08..2998239 100644 --- a/build.gradle +++ b/build.gradle @@ -50,10 +50,10 @@ repositories { mavenCentral() } dependencies { compileOnly 'com.google.code.findbugs:jsr305' - compile 'args4j:args4j' compile 'com.google.code.gson:gson' compile 'com.squareup.okhttp3:okhttp' compile 'commons-codec:commons-codec' + compile 'info.picocli:picocli' compile 'org.slf4j:slf4j-api' compile 'org.starchartlabs.alloy:alloy-core' diff --git a/dependencies.properties b/dependencies.properties index aa0ae5d..149acd6 100644 --- a/dependencies.properties +++ b/dependencies.properties @@ -2,8 +2,6 @@ # Entries are ordered alphabetically by group, then artifact # Entries are in groups/blocks based on matching group IDs -args4j:args4j=2.33 - com.google.code.findbugs:jsr305=3.0.2 com.google.code.gson:gson=2.8.6 @@ -13,6 +11,8 @@ com.squareup.okhttp3:okhttp=3.14.4 commons-codec:commons-codec=1.13 +info.picocli:picocli=4.1.4 + org.slf4j:slf4j-api=1.7.29 org.slf4j:slf4j-simple=1.7.29 diff --git a/gradle.properties b/gradle.properties index 839263d..4403beb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ # General library settings group=org.starchartlabs.lure -version=0.2.2-SNAPSHOT +version=0.3.0-SNAPSHOT org.gradle.console=plain org.gradle.warning.mode=all diff --git a/src/main/java/org/starchartlabs/lure/CommandLineInterface.java b/src/main/java/org/starchartlabs/lure/CommandLineInterface.java index 5195638..bd1f0e6 100644 --- a/src/main/java/org/starchartlabs/lure/CommandLineInterface.java +++ b/src/main/java/org/starchartlabs/lure/CommandLineInterface.java @@ -15,23 +15,9 @@ */ package org.starchartlabs.lure; -import java.io.StringWriter; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; -import java.util.stream.Collectors; +import org.starchartlabs.lure.command.LureCommand; -import org.kohsuke.args4j.Argument; -import org.kohsuke.args4j.CmdLineException; -import org.kohsuke.args4j.CmdLineParser; -import org.kohsuke.args4j.spi.SubCommand; -import org.kohsuke.args4j.spi.SubCommandHandler; -import org.kohsuke.args4j.spi.SubCommands; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.starchartlabs.lure.command.PostbinCommand; -import org.starchartlabs.lure.command.PushCommand; +import picocli.CommandLine; /** * Main entry point for command line calls to the application @@ -41,70 +27,8 @@ */ public class CommandLineInterface { - /** Logger reference to output information to the application log files */ - private final Logger logger = LoggerFactory.getLogger(getClass()); - - @Argument(handler = SubCommandHandler.class) - @SubCommands({ - @SubCommand(name = PushCommand.COMMAND_NAME, impl = PushCommand.class), - @SubCommand(name = PostbinCommand.COMMAND_NAME, impl = PostbinCommand.class), - }) - private Runnable command; - - public static void main(String[] args) { - new CommandLineInterface().run(args); - } - - public void run(String[] args) { - CmdLineParser parser = new CmdLineParser(this); - - try { - // parse the arguments. - parser.parseArgument(args); - - if (command != null) { - command.run(); - } else { - logger.error("Invalid command line arguments"); - printUsage(parser); - } - } catch (CmdLineException e) { - logger.error("Invalid command line arguments", e); - printUsage(parser); - } - } - - private void printUsage(CmdLineParser parser) { - Objects.requireNonNull(parser); - - StringWriter usageWriter = new StringWriter(); - - // Print sub-command usages - Map subCommands = new HashMap<>(); - subCommands.put(PushCommand.COMMAND_NAME, new PushCommand()); - subCommands.put(PostbinCommand.COMMAND_NAME, new PostbinCommand()); - - String subCommandsList = subCommands.keySet().stream() - .collect(Collectors.joining(" | ")); - - usageWriter - .append("java " + getClass().getSimpleName() + " (" + subCommandsList + ") [options...] arguments..."); - usageWriter.append('\n'); - usageWriter.append('\n'); - - parser.printUsage(usageWriter, null); - - for (Entry subCommand : subCommands.entrySet()) { - usageWriter.append(subCommand.getKey()); - usageWriter.append('\n'); - - CmdLineParser subParser = new CmdLineParser(subCommand.getValue()); - subParser.printUsage(usageWriter, null); - usageWriter.append('\n'); - } - - String usage = usageWriter.toString(); - logger.error("\n{}", usage); + public static void main(String[] args) throws Exception { + new CommandLine(new LureCommand()).execute(args); } } diff --git a/src/main/java/org/starchartlabs/lure/command/LureCommand.java b/src/main/java/org/starchartlabs/lure/command/LureCommand.java new file mode 100644 index 0000000..d14b4be --- /dev/null +++ b/src/main/java/org/starchartlabs/lure/command/LureCommand.java @@ -0,0 +1,36 @@ +/* + * Copyright 2020 StarChart-Labs Contributors (https://github.com/StarChart-Labs) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.starchartlabs.lure.command; + +import picocli.CommandLine.Command; + +/** + * Represents the lure command-set as a whole. This structure is used by the picocli library, as it assumes output may + * be things structured like "git", where there is a first command indicating the program, and second indicating the + * operation + * + * @author romeara + * @since 0.3.0 + */ +@Command(mixinStandardHelpOptions = true, subcommands = { PostbinCommand.class, PushCommand.class }) +public class LureCommand implements Runnable { + + @Override + public void run() { + // This command has no behavior of its own, and serves to structure sub-commands + } + +} diff --git a/src/main/java/org/starchartlabs/lure/command/PostbinCommand.java b/src/main/java/org/starchartlabs/lure/command/PostbinCommand.java index bf74bf0..48839b1 100644 --- a/src/main/java/org/starchartlabs/lure/command/PostbinCommand.java +++ b/src/main/java/org/starchartlabs/lure/command/PostbinCommand.java @@ -25,7 +25,6 @@ import javax.annotation.Nullable; -import org.kohsuke.args4j.Option; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.starchartlabs.lure.model.postbin.PostbinCreateResponse; @@ -39,6 +38,9 @@ import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.ResponseBody; +import picocli.CommandLine.Command; +import picocli.CommandLine.Option; +import picocli.CommandLine.ParentCommand; /** * Command line sub-command that will pull requests from PostBin and push it to a web URL following patterns defined for @@ -47,6 +49,9 @@ * @author romeara * @since 0.2.0 */ +@Command( + description = "Pipes a payloads from postb.in to an indicated web URL, mimicking the GitHub webook call pattern", + name = PostbinCommand.COMMAND_NAME, mixinStandardHelpOptions = true) public class PostbinCommand implements Runnable { public static final String COMMAND_NAME = "postbin"; @@ -63,20 +68,23 @@ public class PostbinCommand implements Runnable { private final OkHttpClient httpClient = new OkHttpClient(); - @Option(name = "-t", aliases = { "--target-url" }, required = true, - usage = "Specifies the server URL to POST the event to. Required") + @ParentCommand + private LureCommand lureCommand; + + @Option(names = { "-t", "--target-url" }, required = true, + description = "Specifies the server URL to POST the event to. Required") private String targetUrl; - @Option(name = "-b", aliases = { "--bin-id" }, required = false, - usage = "Specifies the Postbin bin ID to poll. If unspecified, a new bin is created") + @Option(names = { "-b", "--bin-id" }, required = false, + description = "Specifies the Postbin bin ID to poll. If unspecified, a new bin is created") private String binId; - @Option(name = "-p", aliases = { "--poll-frequency" }, required = false, - usage = "Specifies the frequency in seconds to poll Postbin for new requests at, must be greater than 0. Defaults to 10 seconds") + @Option(names = { "-p", "--poll-frequency" }, required = false, + description = "Specifies the frequency in seconds to poll Postbin for new requests at, must be greater than 0. Defaults to 10 seconds") private int pollFrequencySeconds = 10; - @Option(name = "-r", aliases = { "--postbin-root-url" }, required = false, - usage = "Specifies the root URL of Postbin to use. Defaults to https://postb.in/api") + @Option(names = { "-r", "--postbin-root-url" }, required = false, + description = "Specifies the root URL of Postbin to use. Defaults to https://postb.in/api") private String rootUrl = "https://postb.in/api"; @Override diff --git a/src/main/java/org/starchartlabs/lure/command/PushCommand.java b/src/main/java/org/starchartlabs/lure/command/PushCommand.java index 89c82a8..e1bdcaf 100644 --- a/src/main/java/org/starchartlabs/lure/command/PushCommand.java +++ b/src/main/java/org/starchartlabs/lure/command/PushCommand.java @@ -28,7 +28,6 @@ import org.apache.commons.codec.digest.HmacAlgorithms; import org.apache.commons.codec.digest.HmacUtils; -import org.kohsuke.args4j.Option; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,6 +37,9 @@ import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; +import picocli.CommandLine.Command; +import picocli.CommandLine.Option; +import picocli.CommandLine.ParentCommand; /** * Command line sub-command that will push raw data to a web URL following patterns defined for GitHub webhook calls @@ -45,6 +47,9 @@ * @author romeara * @since 0.1.0 */ +@Command( + description = "Pushes a provided payload to an indicated web URL, mimicking the GitHub webook call pattern", + name = PushCommand.COMMAND_NAME, mixinStandardHelpOptions = true) public class PushCommand implements Runnable { public static final String COMMAND_NAME = "push"; @@ -63,21 +68,24 @@ public class PushCommand implements Runnable { /** Logger reference to output information to the application log files */ private final Logger logger = LoggerFactory.getLogger(getClass()); - @Option(name = "-t", aliases = { "--target-url" }, required = true, - usage = "Specifies the server URL to POST the event to. Required") + @ParentCommand + private LureCommand lureCommand; + + @Option(names = { "-t", "--target-url" }, required = true, + description = "Specifies the server URL to POST the event to. Required") private String targetUrl; - @Option(name = "-e", aliases = { "--event-name" }, required = true, - usage = "Specifies the GitHub event name to send as. Required") + @Option(names = { "-e", "--event-name" }, required = true, + description = "Specifies the GitHub event name to send as. Required") private String eventName; @Nullable - @Option(name = "-s", aliases = { "--secret" }, required = false, - usage = "Specifies the webhook secret to secure the event post with") + @Option(names = { "-s", "--secret" }, required = false, + description = "Specifies the webhook secret to secure the event post with") private String webhookSecret; - @Option(name = "-c", aliases = { "--content" }, required = true, - usage = "Specifies the file containing the event content to send. Required") + @Option(names = { "-c", "--content" }, required = true, + description = "Specifies the file containing the event content to send. Required") private File contentFile; @Override