diff --git a/pulsar-broker/pom.xml b/pulsar-broker/pom.xml
index db839467ed2718..8264459c6d9ab7 100644
--- a/pulsar-broker/pom.xml
+++ b/pulsar-broker/pom.xml
@@ -322,8 +322,8 @@
- com.beust
- jcommander
+ info.picocli
+ picocli
diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/PulsarBrokerStarter.java b/pulsar-broker/src/main/java/org/apache/pulsar/PulsarBrokerStarter.java
index 1b24c806e62cb5..e3ba053d5d34af 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/PulsarBrokerStarter.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/PulsarBrokerStarter.java
@@ -23,9 +23,6 @@
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.pulsar.common.configuration.PulsarConfigurationLoader.create;
import static org.apache.pulsar.common.configuration.PulsarConfigurationLoader.isComplete;
-import com.beust.jcommander.JCommander;
-import com.beust.jcommander.Parameter;
-import com.beust.jcommander.Parameters;
import com.google.common.annotations.VisibleForTesting;
import java.io.File;
import java.io.FileInputStream;
@@ -34,10 +31,10 @@
import java.nio.file.Path;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
-import java.util.Arrays;
import java.util.Date;
import java.util.Objects;
import java.util.Optional;
+import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import org.apache.bookkeeper.common.component.ComponentStarter;
import org.apache.bookkeeper.common.component.LifecycleComponent;
@@ -63,6 +60,10 @@
import org.apache.pulsar.functions.worker.service.WorkerServiceLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
+import picocli.CommandLine.ScopeType;
public class PulsarBrokerStarter {
@@ -76,31 +77,31 @@ private static ServiceConfiguration loadConfig(String configFile) throws Excepti
}
@VisibleForTesting
- @Parameters(commandDescription = "Options")
+ @Command(description = "Options", showDefaultValues = true, scope = ScopeType.INHERIT)
private static class StarterArguments {
- @Parameter(names = {"-c", "--broker-conf"}, description = "Configuration file for Broker")
+ @Option(names = {"-c", "--broker-conf"}, description = "Configuration file for Broker")
private String brokerConfigFile = "conf/broker.conf";
- @Parameter(names = {"-rb", "--run-bookie"}, description = "Run Bookie together with Broker")
+ @Option(names = {"-rb", "--run-bookie"}, description = "Run Bookie together with Broker")
private boolean runBookie = false;
- @Parameter(names = {"-ra", "--run-bookie-autorecovery"},
+ @Option(names = {"-ra", "--run-bookie-autorecovery"},
description = "Run Bookie Autorecovery together with broker")
private boolean runBookieAutoRecovery = false;
- @Parameter(names = {"-bc", "--bookie-conf"}, description = "Configuration file for Bookie")
+ @Option(names = {"-bc", "--bookie-conf"}, description = "Configuration file for Bookie")
private String bookieConfigFile = "conf/bookkeeper.conf";
- @Parameter(names = {"-rfw", "--run-functions-worker"}, description = "Run functions worker with Broker")
+ @Option(names = {"-rfw", "--run-functions-worker"}, description = "Run functions worker with Broker")
private boolean runFunctionsWorker = false;
- @Parameter(names = {"-fwc", "--functions-worker-conf"}, description = "Configuration file for Functions Worker")
+ @Option(names = {"-fwc", "--functions-worker-conf"}, description = "Configuration file for Functions Worker")
private String fnWorkerConfigFile = "conf/functions_worker.yml";
- @Parameter(names = {"-h", "--help"}, description = "Show this help message")
+ @Option(names = {"-h", "--help"}, description = "Show this help message")
private boolean help = false;
- @Parameter(names = {"-g", "--generate-docs"}, description = "Generate docs")
+ @Option(names = {"-g", "--generate-docs"}, description = "Generate docs")
private boolean generateDocs = false;
}
@@ -125,43 +126,47 @@ private static ServerConfiguration readBookieConfFile(String bookieConfigFile) t
return bookieConf;
}
- private static boolean argsContains(String[] args, String arg) {
- return Arrays.asList(args).contains(arg);
- }
-
- private static class BrokerStarter {
- private final ServiceConfiguration brokerConfig;
- private final PulsarService pulsarService;
- private final LifecycleComponent bookieServer;
+ protected static class BrokerStarter implements Callable {
+ private ServiceConfiguration brokerConfig;
+ private PulsarService pulsarService;
+ private LifecycleComponent bookieServer;
private volatile CompletableFuture bookieStartFuture;
- private final AutoRecoveryMain autoRecoveryMain;
- private final StatsProvider bookieStatsProvider;
- private final ServerConfiguration bookieConfig;
- private final WorkerService functionsWorkerService;
- private final WorkerConfig workerConfig;
-
- BrokerStarter(String[] args) throws Exception {
- StarterArguments starterArguments = new StarterArguments();
- JCommander jcommander = new JCommander(starterArguments);
- jcommander.setProgramName("PulsarBrokerStarter");
-
- // parse args by JCommander
- jcommander.parse(args);
+ private AutoRecoveryMain autoRecoveryMain;
+ private StatsProvider bookieStatsProvider;
+ private ServerConfiguration bookieConfig;
+ private WorkerService functionsWorkerService;
+ private WorkerConfig workerConfig;
+
+ private CommandLine commander;
+
+ private final StarterArguments starterArguments;
+
+ BrokerStarter() {
+ starterArguments = new StarterArguments();
+ commander = new CommandLine(starterArguments);
+ commander.setCommandName("PulsarBrokerStarter");
+ }
+
+ public int start(String[] args) {
+ return commander.execute(args);
+ }
+
+ public Integer call() throws Exception {
if (starterArguments.help) {
- jcommander.usage();
- System.exit(0);
+ commander.usage(commander.getOut());
+ return 0;
}
if (starterArguments.generateDocs) {
CmdGenerateDocs cmd = new CmdGenerateDocs("pulsar");
- cmd.addCommand("broker", starterArguments);
+ cmd.addCommand("broker", commander);
cmd.run(null);
- System.exit(0);
+ return 0;
}
// init broker config
if (isBlank(starterArguments.brokerConfigFile)) {
- jcommander.usage();
+ commander.usage(commander.getOut());
throw new IllegalArgumentException("Need to specify a configuration file for broker");
} else {
final String filepath = Path.of(starterArguments.brokerConfigFile)
@@ -209,20 +214,16 @@ private static class BrokerStarter {
});
// if no argument to run bookie in cmd line, read from pulsar config
- if (!argsContains(args, "-rb") && !argsContains(args, "--run-bookie")) {
- checkState(!starterArguments.runBookie,
- "runBookie should be false if has no argument specified");
+ if (!starterArguments.runBookie) {
starterArguments.runBookie = brokerConfig.isEnableRunBookieTogether();
}
- if (!argsContains(args, "-ra") && !argsContains(args, "--run-bookie-autorecovery")) {
- checkState(!starterArguments.runBookieAutoRecovery,
- "runBookieAutoRecovery should be false if has no argument specified");
+ if (!starterArguments.runBookieAutoRecovery) {
starterArguments.runBookieAutoRecovery = brokerConfig.isEnableRunBookieAutoRecoveryTogether();
}
if ((starterArguments.runBookie || starterArguments.runBookieAutoRecovery)
- && isBlank(starterArguments.bookieConfigFile)) {
- jcommander.usage();
+ && isBlank(starterArguments.bookieConfigFile)) {
+ commander.usage(commander.getOut());
throw new IllegalArgumentException("No configuration file for Bookie");
}
@@ -257,9 +258,7 @@ && isBlank(starterArguments.bookieConfigFile)) {
} else {
autoRecoveryMain = null;
}
- }
- public void start() throws Exception {
if (bookieStatsProvider != null) {
bookieStatsProvider.start(bookieConfig);
log.info("started bookieStatsProvider.");
@@ -275,15 +274,17 @@ public void start() throws Exception {
pulsarService.start();
log.info("PulsarService started.");
+ return 0;
}
public void join() throws InterruptedException {
- pulsarService.waitUntilClosed();
-
- try {
- pulsarService.close();
- } catch (PulsarServerException e) {
- throw new RuntimeException();
+ if (pulsarService != null) {
+ pulsarService.waitUntilClosed();
+ try {
+ pulsarService.close();
+ } catch (PulsarServerException e) {
+ throw new RuntimeException();
+ }
}
if (bookieStartFuture != null) {
@@ -301,8 +302,10 @@ public void shutdown() throws Exception {
log.info("Shut down functions worker service successfully.");
}
- pulsarService.close();
- log.info("Shut down broker service successfully.");
+ if (pulsarService != null) {
+ pulsarService.close();
+ log.info("Shut down broker service successfully.");
+ }
if (bookieStatsProvider != null) {
bookieStatsProvider.stop();
@@ -317,6 +320,11 @@ public void shutdown() throws Exception {
log.info("Shut down autoRecoveryMain successfully.");
}
}
+
+ @VisibleForTesting
+ CommandLine getCommander() {
+ return commander;
+ }
}
@@ -330,7 +338,7 @@ public static void main(String[] args) throws Exception {
exception.printStackTrace(System.out);
});
- BrokerStarter starter = new BrokerStarter(args);
+ BrokerStarter starter = new BrokerStarter();
Runtime.getRuntime().addShutdownHook(
new Thread(() -> {
try {
@@ -344,16 +352,21 @@ public static void main(String[] args) throws Exception {
);
PulsarByteBufAllocator.registerOOMListener(oomException -> {
- if (starter.brokerConfig.isSkipBrokerShutdownOnOOM()) {
+ if (starter.brokerConfig != null && starter.brokerConfig.isSkipBrokerShutdownOnOOM()) {
log.error("-- Received OOM exception: {}", oomException.getMessage(), oomException);
} else {
log.error("-- Shutting down - Received OOM exception: {}", oomException.getMessage(), oomException);
- starter.pulsarService.shutdownNow();
+ if (starter.pulsarService != null) {
+ starter.pulsarService.shutdownNow();
+ }
}
});
try {
- starter.start();
+ int start = starter.start(args);
+ if (start != 0) {
+ System.exit(start);
+ }
} catch (Throwable t) {
log.error("Failed to start pulsar service.", t);
ShutdownUtil.triggerImmediateForcefulShutdown();
diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/PulsarClusterMetadataSetup.java b/pulsar-broker/src/main/java/org/apache/pulsar/PulsarClusterMetadataSetup.java
index 96ebadb1ff4aa2..854a5179161a4f 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/PulsarClusterMetadataSetup.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/PulsarClusterMetadataSetup.java
@@ -19,8 +19,6 @@
package org.apache.pulsar;
import static org.apache.pulsar.common.policies.data.PoliciesUtil.getBundles;
-import com.beust.jcommander.JCommander;
-import com.beust.jcommander.Parameter;
import java.io.IOException;
import java.util.Collections;
import java.util.Optional;
@@ -58,6 +56,10 @@
import org.apache.pulsar.metadata.impl.ZKMetadataStore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
+import picocli.CommandLine.ScopeType;
/**
* Setup the metadata for a new Pulsar cluster.
@@ -66,75 +68,76 @@ public class PulsarClusterMetadataSetup {
private static final int DEFAULT_BUNDLE_NUMBER = 16;
+ @Command(name = "initialize-cluster-metadata", showDefaultValues = true, scope = ScopeType.INHERIT)
private static class Arguments {
- @Parameter(names = { "-c", "--cluster" }, description = "Cluster name", required = true)
+ @Option(names = {"-c", "--cluster"}, description = "Cluster name", required = true)
private String cluster;
- @Parameter(names = {"-bn",
+ @Option(names = {"-bn",
"--default-namespace-bundle-number"},
description = "The bundle numbers for the default namespaces(public/default), default is 16",
required = false)
private int numberOfDefaultNamespaceBundles;
- @Parameter(names = { "-uw",
- "--web-service-url" }, description = "Web-service URL for new cluster", required = true)
+ @Option(names = {"-uw",
+ "--web-service-url"}, description = "Web-service URL for new cluster", required = true)
private String clusterWebServiceUrl;
- @Parameter(names = {"-tw",
+ @Option(names = {"-tw",
"--web-service-url-tls"},
description = "Web-service URL for new cluster with TLS encryption", required = false)
private String clusterWebServiceUrlTls;
- @Parameter(names = { "-ub",
- "--broker-service-url" }, description = "Broker-service URL for new cluster", required = false)
+ @Option(names = {"-ub",
+ "--broker-service-url"}, description = "Broker-service URL for new cluster", required = false)
private String clusterBrokerServiceUrl;
- @Parameter(names = {"-tb",
+ @Option(names = {"-tb",
"--broker-service-url-tls"},
description = "Broker-service URL for new cluster with TLS encryption", required = false)
private String clusterBrokerServiceUrlTls;
- @Parameter(names = { "-zk",
- "--zookeeper" }, description = "Local ZooKeeper quorum connection string",
+ @Option(names = {"-zk",
+ "--zookeeper"}, description = "Local ZooKeeper quorum connection string",
required = false,
hidden = true
- )
+ )
private String zookeeper;
- @Parameter(names = { "-md",
- "--metadata-store" }, description = "Metadata Store service url. eg: zk:my-zk:2181", required = false)
+ @Option(names = {"-md",
+ "--metadata-store"}, description = "Metadata Store service url. eg: zk:my-zk:2181", required = false)
private String metadataStoreUrl;
- @Parameter(names = {
- "--zookeeper-session-timeout-ms"
+ @Option(names = {
+ "--zookeeper-session-timeout-ms"
}, description = "Local zookeeper session timeout ms")
private int zkSessionTimeoutMillis = 30000;
- @Parameter(names = {"-gzk",
+ @Option(names = {"-gzk",
"--global-zookeeper"},
description = "Global ZooKeeper quorum connection string", required = false, hidden = true)
private String globalZookeeper;
- @Parameter(names = {"-cs",
+ @Option(names = {"-cs",
"--configuration-store"}, description = "Configuration Store connection string", hidden = true)
private String configurationStore;
- @Parameter(names = {"-cms",
+ @Option(names = {"-cms",
"--configuration-metadata-store"}, description = "Configuration Metadata Store connection string",
hidden = false)
private String configurationMetadataStore;
- @Parameter(names = {
- "--initial-num-stream-storage-containers"
+ @Option(names = {
+ "--initial-num-stream-storage-containers"
}, description = "Num storage containers of BookKeeper stream storage")
private int numStreamStorageContainers = 16;
- @Parameter(names = {
+ @Option(names = {
"--initial-num-transaction-coordinators"
}, description = "Num transaction coordinators will assigned in cluster")
private int numTransactionCoordinators = 16;
- @Parameter(names = {
+ @Option(names = {
"--existing-bk-metadata-service-uri"},
description = "The metadata service URI of the existing BookKeeper cluster that you want to use")
private String existingBkMetadataServiceUri;
@@ -142,26 +145,26 @@ private static class Arguments {
// Hide and marked as deprecated this flag because we use the new name '--existing-bk-metadata-service-uri' to
// pass the service url. For compatibility of the command, we should keep both to avoid the exceptions.
@Deprecated
- @Parameter(names = {
- "--bookkeeper-metadata-service-uri"},
- description = "The metadata service URI of the existing BookKeeper cluster that you want to use",
- hidden = true)
+ @Option(names = {
+ "--bookkeeper-metadata-service-uri"},
+ description = "The metadata service URI of the existing BookKeeper cluster that you want to use",
+ hidden = true)
private String bookieMetadataServiceUri;
- @Parameter(names = { "-pp",
- "--proxy-protocol" },
+ @Option(names = {"-pp",
+ "--proxy-protocol"},
description = "Proxy protocol to select type of routing at proxy. Possible Values: [SNI]",
required = false)
private ProxyProtocol clusterProxyProtocol;
- @Parameter(names = { "-pu",
- "--proxy-url" }, description = "Proxy-server URL to which to connect.", required = false)
+ @Option(names = {"-pu",
+ "--proxy-url"}, description = "Proxy-server URL to which to connect.", required = false)
private String clusterProxyUrl;
- @Parameter(names = { "-h", "--help" }, description = "Show this help message")
+ @Option(names = {"-h", "--help"}, description = "Show this help message")
private boolean help = false;
- @Parameter(names = {"-g", "--generate-docs"}, description = "Generate docs")
+ @Option(names = {"-g", "--generate-docs"}, description = "Generate docs")
private boolean generateDocs = false;
}
@@ -197,28 +200,27 @@ public static void main(String[] args) throws Exception {
System.setProperty("bookkeeper.metadata.client.drivers", PulsarMetadataClientDriver.class.getName());
Arguments arguments = new Arguments();
- JCommander jcommander = new JCommander();
+ CommandLine commander = new CommandLine(arguments);
try {
- jcommander.addObject(arguments);
- jcommander.parse(args);
+ commander.parseArgs(args);
if (arguments.help) {
- jcommander.usage();
+ commander.usage(commander.getOut());
return;
}
if (arguments.generateDocs) {
CmdGenerateDocs cmd = new CmdGenerateDocs("pulsar");
- cmd.addCommand("initialize-cluster-metadata", arguments);
+ cmd.addCommand("initialize-cluster-metadata", commander);
cmd.run(null);
return;
}
} catch (Exception e) {
- jcommander.usage();
+ commander.getErr().println(e);
throw e;
}
if (arguments.metadataStoreUrl == null && arguments.zookeeper == null) {
System.err.println("Metadata store address argument is required (--metadata-store)");
- jcommander.usage();
+ commander.usage(commander.getOut());
System.exit(1);
}
@@ -226,7 +228,7 @@ public static void main(String[] args) throws Exception {
&& arguments.globalZookeeper == null) {
System.err.println(
"Configuration metadata store address argument is required (--configuration-metadata-store)");
- jcommander.usage();
+ commander.usage(commander.getOut());
System.exit(1);
}
@@ -234,7 +236,7 @@ public static void main(String[] args) throws Exception {
|| arguments.globalZookeeper != null)) {
System.err.println("Configuration metadata store argument (--configuration-metadata-store) "
+ "supersedes the deprecated (--global-zookeeper and --configuration-store) argument");
- jcommander.usage();
+ commander.usage(commander.getOut());
System.exit(1);
}
diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/PulsarClusterMetadataTeardown.java b/pulsar-broker/src/main/java/org/apache/pulsar/PulsarClusterMetadataTeardown.java
index 01a9eedcca357f..a2984a352b9f88 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/PulsarClusterMetadataTeardown.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/PulsarClusterMetadataTeardown.java
@@ -18,8 +18,6 @@
*/
package org.apache.pulsar;
-import com.beust.jcommander.JCommander;
-import com.beust.jcommander.Parameter;
import com.google.protobuf.InvalidProtocolBufferException;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@@ -41,35 +39,40 @@
import org.apache.pulsar.metadata.api.extended.MetadataStoreExtended;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
+import picocli.CommandLine.ScopeType;
/**
* Teardown the metadata for a existed Pulsar cluster.
*/
public class PulsarClusterMetadataTeardown {
+ @Command(name = "delete-cluster-metadata", showDefaultValues = true, scope = ScopeType.INHERIT)
private static class Arguments {
- @Parameter(names = { "-zk",
+ @Option(names = { "-zk",
"--zookeeper"}, description = "Local ZooKeeper quorum connection string", required = true)
private String zookeeper;
- @Parameter(names = {
+ @Option(names = {
"--zookeeper-session-timeout-ms"
}, description = "Local zookeeper session timeout ms")
private int zkSessionTimeoutMillis = 30000;
- @Parameter(names = { "-c", "-cluster", "--cluster" }, description = "Cluster name")
+ @Option(names = { "-c", "-cluster", "--cluster" }, description = "Cluster name")
private String cluster;
- @Parameter(names = { "-cs", "--configuration-store" }, description = "Configuration Store connection string")
+ @Option(names = { "-cs", "--configuration-store" }, description = "Configuration Store connection string")
private String configurationStore;
- @Parameter(names = { "--bookkeeper-metadata-service-uri" }, description = "Metadata service uri of BookKeeper")
+ @Option(names = { "--bookkeeper-metadata-service-uri" }, description = "Metadata service uri of BookKeeper")
private String bkMetadataServiceUri;
- @Parameter(names = { "-h", "--help" }, description = "Show this help message")
+ @Option(names = { "-h", "--help" }, description = "Show this help message")
private boolean help = false;
- @Parameter(names = {"-g", "--generate-docs"}, description = "Generate docs")
+ @Option(names = {"-g", "--generate-docs"}, description = "Generate docs")
private boolean generateDocs = false;
}
@@ -78,22 +81,21 @@ private static class Arguments {
public static void main(String[] args) throws Exception {
Arguments arguments = new Arguments();
- JCommander jcommander = new JCommander();
+ CommandLine commander = new CommandLine(arguments);
try {
- jcommander.addObject(arguments);
- jcommander.parse(args);
+ commander.parseArgs(args);
if (arguments.help) {
- jcommander.usage();
+ commander.usage(commander.getOut());
return;
}
if (arguments.generateDocs) {
CmdGenerateDocs cmd = new CmdGenerateDocs("pulsar");
- cmd.addCommand("delete-cluster-metadata", arguments);
+ cmd.addCommand("delete-cluster-metadata", commander);
cmd.run(null);
return;
}
} catch (Exception e) {
- jcommander.usage();
+ commander.getErr().println(e);
throw e;
}
diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/PulsarInitialNamespaceSetup.java b/pulsar-broker/src/main/java/org/apache/pulsar/PulsarInitialNamespaceSetup.java
index 22b38e59676eca..891aa1aa421207 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/PulsarInitialNamespaceSetup.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/PulsarInitialNamespaceSetup.java
@@ -18,67 +18,70 @@
*/
package org.apache.pulsar;
-import com.beust.jcommander.JCommander;
-import com.beust.jcommander.Parameter;
import java.util.List;
import org.apache.pulsar.broker.resources.PulsarResources;
import org.apache.pulsar.common.naming.NamespaceName;
import org.apache.pulsar.docs.tools.CmdGenerateDocs;
import org.apache.pulsar.metadata.api.MetadataStore;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
+import picocli.CommandLine.Parameters;
+import picocli.CommandLine.ScopeType;
/**
* Setup the initial namespace of the cluster without startup the Pulsar broker.
*/
public class PulsarInitialNamespaceSetup {
+ @Command(name = "initialize-namespace", showDefaultValues = true, scope = ScopeType.INHERIT)
private static class Arguments {
- @Parameter(names = { "-c", "--cluster" }, description = "Cluster name", required = true)
+ @Option(names = { "-c", "--cluster" }, description = "Cluster name", required = true)
private String cluster;
- @Parameter(names = { "-cs",
+ @Option(names = { "-cs",
"--configuration-store" }, description = "Configuration Store connection string", required = true)
private String configurationStore;
- @Parameter(names = {
+ @Option(names = {
"--zookeeper-session-timeout-ms"
}, description = "Local zookeeper session timeout ms")
private int zkSessionTimeoutMillis = 30000;
- @Parameter(description = "tenant/namespace", required = true)
+ @Parameters(description = "tenant/namespace", arity = "1")
private List namespaces;
- @Parameter(names = { "-h", "--help" }, description = "Show this help message")
+ @Option(names = { "-h", "--help" }, description = "Show this help message")
private boolean help = false;
- @Parameter(names = {"-g", "--generate-docs"}, description = "Generate docs")
+ @Option(names = {"-g", "--generate-docs"}, description = "Generate docs")
private boolean generateDocs = false;
}
public static int doMain(String[] args) throws Exception {
Arguments arguments = new Arguments();
- JCommander jcommander = new JCommander();
+ CommandLine commander = new CommandLine(arguments);
try {
- jcommander.addObject(arguments);
- jcommander.parse(args);
+ commander.parseArgs(args);
if (arguments.help) {
- jcommander.usage();
+ commander.usage(commander.getOut());
return 0;
}
if (arguments.generateDocs) {
CmdGenerateDocs cmd = new CmdGenerateDocs("pulsar");
- cmd.addCommand("initialize-namespace", arguments);
+ cmd.addCommand("initialize-namespace", commander);
cmd.run(null);
return 0;
}
} catch (Exception e) {
- jcommander.usage();
+ commander.getErr().println(e);
return 1;
}
if (arguments.configurationStore == null) {
System.err.println("Configuration store address argument is required (--configuration-store)");
- jcommander.usage();
+ commander.usage(commander.getOut());
return 1;
}
diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/PulsarStandalone.java b/pulsar-broker/src/main/java/org/apache/pulsar/PulsarStandalone.java
index ba136e7c910586..b785448cdacafe 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/PulsarStandalone.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/PulsarStandalone.java
@@ -20,7 +20,6 @@
import static org.apache.pulsar.common.naming.NamespaceName.SYSTEM_NAMESPACE;
import static org.apache.pulsar.common.naming.SystemTopicNames.TRANSACTION_COORDINATOR_ASSIGN;
-import com.beust.jcommander.Parameter;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Sets;
import io.netty.util.internal.PlatformDependent;
@@ -52,8 +51,12 @@
import org.apache.pulsar.metadata.impl.ZKMetadataStore;
import org.apache.pulsar.packages.management.storage.filesystem.FileSystemPackagesStorageProvider;
import org.apache.pulsar.zookeeper.LocalBookkeeperEnsemble;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
+import picocli.CommandLine.ScopeType;
@Slf4j
+@Command(name = "standalone", showDefaultValues = true, scope = ScopeType.INHERIT)
public class PulsarStandalone implements AutoCloseable {
private static final String PULSAR_STANDALONE_USE_ZOOKEEPER = "PULSAR_STANDALONE_USE_ZOOKEEPER";
@@ -211,60 +214,60 @@ public boolean isHelp() {
return help;
}
- @Parameter(names = { "-c", "--config" }, description = "Configuration file path")
+ @Option(names = { "-c", "--config" }, description = "Configuration file path")
private String configFile;
- @Parameter(names = { "--wipe-data" }, description = "Clean up previous ZK/BK data")
+ @Option(names = { "--wipe-data" }, description = "Clean up previous ZK/BK data")
private boolean wipeData = false;
- @Parameter(names = { "--num-bookies" }, description = "Number of local Bookies")
+ @Option(names = { "--num-bookies" }, description = "Number of local Bookies")
private int numOfBk = 1;
- @Parameter(names = { "--metadata-dir" },
+ @Option(names = { "--metadata-dir" },
description = "Directory for storing metadata")
private String metadataDir = "data/metadata";
- @Parameter(names = { "--metadata-url" },
+ @Option(names = { "--metadata-url" },
description = "Metadata store url")
private String metadataStoreUrl = "";
- @Parameter(names = {"--zookeeper-port"}, description = "Local zookeeper's port",
+ @Option(names = {"--zookeeper-port"}, description = "Local zookeeper's port",
hidden = true)
private int zkPort = 2181;
- @Parameter(names = { "--bookkeeper-port" }, description = "Local bookies base port")
+ @Option(names = { "--bookkeeper-port" }, description = "Local bookies base port")
private int bkPort = 3181;
- @Parameter(names = { "--zookeeper-dir" },
+ @Option(names = { "--zookeeper-dir" },
description = "Local zooKeeper's data directory",
hidden = true)
private String zkDir = "data/standalone/zookeeper";
- @Parameter(names = { "--bookkeeper-dir" }, description = "Local bookies base data directory")
+ @Option(names = { "--bookkeeper-dir" }, description = "Local bookies base data directory")
private String bkDir = "data/standalone/bookkeeper";
- @Parameter(names = { "--no-broker" }, description = "Only start ZK and BK services, no broker")
+ @Option(names = { "--no-broker" }, description = "Only start ZK and BK services, no broker")
private boolean noBroker = false;
- @Parameter(names = { "--only-broker" }, description = "Only start Pulsar broker service (no ZK, BK)")
+ @Option(names = { "--only-broker" }, description = "Only start Pulsar broker service (no ZK, BK)")
private boolean onlyBroker = false;
- @Parameter(names = {"-nfw", "--no-functions-worker"}, description = "Run functions worker with Broker")
+ @Option(names = {"-nfw", "--no-functions-worker"}, description = "Run functions worker with Broker")
private boolean noFunctionsWorker = false;
- @Parameter(names = {"-fwc", "--functions-worker-conf"}, description = "Configuration file for Functions Worker")
+ @Option(names = {"-fwc", "--functions-worker-conf"}, description = "Configuration file for Functions Worker")
private String fnWorkerConfigFile = "conf/functions_worker.yml";
- @Parameter(names = {"-nss", "--no-stream-storage"}, description = "Disable stream storage")
+ @Option(names = {"-nss", "--no-stream-storage"}, description = "Disable stream storage")
private boolean noStreamStorage = false;
- @Parameter(names = { "--stream-storage-port" }, description = "Local bookies stream storage port")
+ @Option(names = { "--stream-storage-port" }, description = "Local bookies stream storage port")
private int streamStoragePort = 4181;
- @Parameter(names = { "-a", "--advertised-address" }, description = "Standalone broker advertised address")
+ @Option(names = { "-a", "--advertised-address" }, description = "Standalone broker advertised address")
private String advertisedAddress = null;
- @Parameter(names = { "-h", "--help" }, description = "Show this help message")
+ @Option(names = { "-h", "--help" }, description = "Show this help message")
private boolean help = false;
private boolean usingNewDefaultsPIP117;
diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/PulsarStandaloneStarter.java b/pulsar-broker/src/main/java/org/apache/pulsar/PulsarStandaloneStarter.java
index e3a5e66d4b6601..0ab731591da14a 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/PulsarStandaloneStarter.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/PulsarStandaloneStarter.java
@@ -19,8 +19,6 @@
package org.apache.pulsar;
import static org.apache.commons.lang3.StringUtils.isBlank;
-import com.beust.jcommander.JCommander;
-import com.beust.jcommander.Parameter;
import com.google.common.base.Strings;
import java.io.FileInputStream;
import java.util.Arrays;
@@ -30,23 +28,25 @@
import org.apache.pulsar.broker.ServiceConfiguration;
import org.apache.pulsar.common.configuration.PulsarConfigurationLoader;
import org.apache.pulsar.docs.tools.CmdGenerateDocs;
+import picocli.CommandLine;
+import picocli.CommandLine.Option;
@Slf4j
public class PulsarStandaloneStarter extends PulsarStandalone {
private static final String PULSAR_CONFIG_FILE = "pulsar.config.file";
- @Parameter(names = {"-g", "--generate-docs"}, description = "Generate docs")
+ @Option(names = {"-g", "--generate-docs"}, description = "Generate docs")
private boolean generateDocs = false;
public PulsarStandaloneStarter(String[] args) throws Exception {
- JCommander jcommander = new JCommander();
+ CommandLine commander = new CommandLine(this);
+
try {
- jcommander.addObject(this);
- jcommander.parse(args);
+ commander.parseArgs(args);
if (this.isHelp()) {
- jcommander.usage();
+ commander.usage(commander.getOut());
exit(0);
}
if (Strings.isNullOrEmpty(this.getConfigFile())) {
@@ -67,11 +67,11 @@ public PulsarStandaloneStarter(String[] args) throws Exception {
if (this.isNoBroker() && this.isOnlyBroker()) {
log.error("Only one option is allowed between '--no-broker' and '--only-broker'");
- jcommander.usage();
+ commander.usage(commander.getOut());
return;
}
} catch (Exception e) {
- jcommander.usage();
+ commander.usage(commander.getOut());
log.error(e.getMessage());
exit(1);
}
diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/PulsarTransactionCoordinatorMetadataSetup.java b/pulsar-broker/src/main/java/org/apache/pulsar/PulsarTransactionCoordinatorMetadataSetup.java
index 6aedfe13a5b50e..57b67b011913fe 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/PulsarTransactionCoordinatorMetadataSetup.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/PulsarTransactionCoordinatorMetadataSetup.java
@@ -18,13 +18,15 @@
*/
package org.apache.pulsar;
-import com.beust.jcommander.JCommander;
-import com.beust.jcommander.Parameter;
import org.apache.pulsar.broker.resources.PulsarResources;
import org.apache.pulsar.common.naming.NamespaceName;
import org.apache.pulsar.common.naming.SystemTopicNames;
import org.apache.pulsar.docs.tools.CmdGenerateDocs;
import org.apache.pulsar.metadata.api.extended.MetadataStoreExtended;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
+import picocli.CommandLine.ScopeType;
/**
* Set up the transaction coordinator metadata for a cluster, the setup will create pulsar/system namespace and create
@@ -32,56 +34,56 @@
*/
public class PulsarTransactionCoordinatorMetadataSetup {
+ @Command(name = "initialize-transaction-coordinator-metadata", showDefaultValues = true, scope = ScopeType.INHERIT)
private static class Arguments {
- @Parameter(names = { "-c", "--cluster" }, description = "Cluster name", required = true)
+ @Option(names = { "-c", "--cluster" }, description = "Cluster name", required = true)
private String cluster;
- @Parameter(names = { "-cs",
+ @Option(names = { "-cs",
"--configuration-store" }, description = "Configuration Store connection string", required = true)
private String configurationStore;
- @Parameter(names = {
+ @Option(names = {
"--zookeeper-session-timeout-ms"
}, description = "Local zookeeper session timeout ms")
private int zkSessionTimeoutMillis = 30000;
- @Parameter(names = {
+ @Option(names = {
"--initial-num-transaction-coordinators"
}, description = "Num transaction coordinators will assigned in cluster")
private int numTransactionCoordinators = 16;
- @Parameter(names = { "-h", "--help" }, description = "Show this help message")
+ @Option(names = { "-h", "--help" }, description = "Show this help message")
private boolean help = false;
- @Parameter(names = {"-g", "--generate-docs"}, description = "Generate docs")
+ @Option(names = {"-g", "--generate-docs"}, description = "Generate docs")
private boolean generateDocs = false;
}
public static void main(String[] args) throws Exception {
Arguments arguments = new Arguments();
- JCommander jcommander = new JCommander();
+ CommandLine commander = new CommandLine(arguments);
try {
- jcommander.addObject(arguments);
- jcommander.parse(args);
+ commander.parseArgs(args);
if (arguments.help) {
- jcommander.usage();
+ commander.usage(commander.getOut());
return;
}
if (arguments.generateDocs) {
CmdGenerateDocs cmd = new CmdGenerateDocs("pulsar");
- cmd.addCommand("initialize-transaction-coordinator-metadata", arguments);
+ cmd.addCommand("initialize-transaction-coordinator-metadata", commander);
cmd.run(null);
return;
}
} catch (Exception e) {
- jcommander.usage();
+ commander.usage(commander.getOut());
throw e;
}
if (arguments.configurationStore == null) {
System.err.println("Configuration store address argument is required (--configuration-store)");
- jcommander.usage();
+ commander.usage(commander.getOut());
System.exit(1);
}
diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/PulsarVersionStarter.java b/pulsar-broker/src/main/java/org/apache/pulsar/PulsarVersionStarter.java
index 85a6c4156dbe4e..556b3ebfd84b6e 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/PulsarVersionStarter.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/PulsarVersionStarter.java
@@ -18,41 +18,43 @@
*/
package org.apache.pulsar;
-import com.beust.jcommander.JCommander;
-import com.beust.jcommander.Parameter;
import org.apache.pulsar.docs.tools.CmdGenerateDocs;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
+import picocli.CommandLine.ScopeType;
/**
* Pulsar version entry point.
*/
public class PulsarVersionStarter {
+ @Command(name = "version", showDefaultValues = true, scope = ScopeType.INHERIT)
private static class Arguments {
- @Parameter(names = {"-h", "--help"}, description = "Show this help message")
+ @Option(names = {"-h", "--help"}, description = "Show this help message")
private boolean help = false;
- @Parameter(names = {"-g", "--generate-docs"}, description = "Generate docs")
+ @Option(names = {"-g", "--generate-docs"}, description = "Generate docs")
private boolean generateDocs = false;
}
public static void main(String[] args) {
Arguments arguments = new Arguments();
- JCommander jcommander = new JCommander();
+ CommandLine commander = new CommandLine(arguments);
try {
- jcommander.addObject(arguments);
- jcommander.parse(args);
+ commander.parseArgs(args);
if (arguments.help) {
- jcommander.usage();
+ commander.usage(commander.getOut());
return;
}
if (arguments.generateDocs) {
CmdGenerateDocs cmd = new CmdGenerateDocs("pulsar");
- cmd.addCommand("version", arguments);
+ cmd.addCommand("version", commander);
cmd.run(null);
return;
}
} catch (Exception e) {
- jcommander.usage();
+ commander.getErr().println(e);
return;
}
System.out.println("Current version of pulsar is: " + PulsarVersion.getVersion());
diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/tools/BrokerTool.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/tools/BrokerTool.java
index 2a479ce4b90c81..980c92fee8a5e4 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/tools/BrokerTool.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/tools/BrokerTool.java
@@ -18,30 +18,32 @@
*/
package org.apache.pulsar.broker.tools;
-import org.apache.bookkeeper.tools.framework.Cli;
-import org.apache.bookkeeper.tools.framework.CliFlags;
-import org.apache.bookkeeper.tools.framework.CliSpec;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
+import picocli.CommandLine.ScopeType;
/**
* broker-tool is used for operations on a specific broker.
*/
+@Command(name = "broker-tool", description = "broker-tool is used for operations on a specific broker",
+ showDefaultValues = true, scope = ScopeType.INHERIT)
public class BrokerTool {
- public static final String NAME = "broker-tool";
+ @Option(
+ names = {"-h", "--help"},
+ description = "Display help information",
+ usageHelp = true
+ )
+ public boolean help = false;
public static int run(String[] args) {
- CliSpec.Builder specBuilder = CliSpec.newBuilder()
- .withName(NAME)
- .withUsage(NAME + " [flags] [commands]")
- .withDescription(NAME + " is used for operations on a specific broker")
- .withFlags(new CliFlags())
- .withConsole(System.out)
- .addCommand(new LoadReportCommand())
- .addCommand(new GenerateDocsCommand());
-
- CliSpec spec = specBuilder.build();
-
- return Cli.runCli(spec, args);
+ BrokerTool brokerTool = new BrokerTool();
+ CommandLine commander = new CommandLine(brokerTool);
+ GenerateDocsCommand generateDocsCommand = new GenerateDocsCommand(commander);
+ commander.addSubcommand(LoadReportCommand.class)
+ .addSubcommand(generateDocsCommand);
+ return commander.execute(args);
}
public static void main(String[] args) {
diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/tools/GenerateDocsCommand.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/tools/GenerateDocsCommand.java
index b020b4bfd8bd10..b0ed54bc53fd07 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/tools/GenerateDocsCommand.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/tools/GenerateDocsCommand.java
@@ -18,63 +18,42 @@
*/
package org.apache.pulsar.broker.tools;
-import com.beust.jcommander.JCommander;
-import com.beust.jcommander.Parameter;
import java.util.ArrayList;
import java.util.List;
-import org.apache.bookkeeper.tools.framework.Cli;
-import org.apache.bookkeeper.tools.framework.CliCommand;
-import org.apache.bookkeeper.tools.framework.CliFlags;
-import org.apache.bookkeeper.tools.framework.CliSpec;
+import java.util.concurrent.Callable;
import org.apache.pulsar.docs.tools.CmdGenerateDocs;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
/**
* The command to generate documents of broker-tool.
*/
-public class GenerateDocsCommand extends CliCommand {
+@Command(name = "gen-doc", description = "Generate documents of broker-tool")
+public class GenerateDocsCommand implements Callable {
+ @Option(
+ names = {"-n", "--command-names"},
+ description = "List of command names",
+ arity = "0..1"
+ )
+ private List commandNames = new ArrayList<>();
+ private final CommandLine rootCmd;
- private static final String NAME = "gen-doc";
- private static final String DESC = "Generate documents of broker-tool";
-
- /**
- * The CLI flags of gen docs command.
- */
- protected static class GenDocFlags extends CliFlags {
- @Parameter(
- names = {"-n", "--command-names"},
- description = "List of command names"
- )
- private List commandNames = new ArrayList<>();
- }
-
- public GenerateDocsCommand() {
- super(CliSpec.newBuilder()
- .withName(NAME)
- .withDescription(DESC)
- .withFlags(new GenDocFlags())
- .build());
+ public GenerateDocsCommand(CommandLine rootCmd) {
+ this.rootCmd = rootCmd;
}
@Override
- public Boolean apply(CliFlags globalFlags, String[] args) {
- CliSpec newSpec = CliSpec.newBuilder(spec)
- .withRunFunc(cmdFlags -> apply(cmdFlags))
- .build();
- return 0 == Cli.runCli(newSpec, args);
- }
-
- private boolean apply(GenerateDocsCommand.GenDocFlags flags) {
+ public Integer call() throws Exception {
CmdGenerateDocs cmd = new CmdGenerateDocs("pulsar");
- JCommander commander = new JCommander();
- commander.addCommand("load-report", new LoadReportCommand.Flags());
- cmd.addCommand("broker-tool", commander);
- if (flags.commandNames.isEmpty()) {
+ cmd.addCommand("broker-tool", rootCmd);
+ if (commandNames.isEmpty()) {
cmd.run(null);
} else {
- ArrayList args = new ArrayList(flags.commandNames);
+ ArrayList args = new ArrayList(commandNames);
args.add(0, "-n");
cmd.run(args.toArray(new String[0]));
}
- return true;
+ return 0;
}
}
diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/tools/LoadReportCommand.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/tools/LoadReportCommand.java
index 935e3a9f2fa1ae..f1f4a917571be0 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/tools/LoadReportCommand.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/tools/LoadReportCommand.java
@@ -18,76 +18,48 @@
*/
package org.apache.pulsar.broker.tools;
-import com.beust.jcommander.Parameter;
import java.util.Optional;
+import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
-import org.apache.bookkeeper.tools.framework.Cli;
-import org.apache.bookkeeper.tools.framework.CliCommand;
-import org.apache.bookkeeper.tools.framework.CliFlags;
-import org.apache.bookkeeper.tools.framework.CliSpec;
import org.apache.commons.lang3.SystemUtils;
import org.apache.pulsar.broker.loadbalance.BrokerHostUsage;
import org.apache.pulsar.broker.loadbalance.impl.GenericBrokerHostUsageImpl;
import org.apache.pulsar.broker.loadbalance.impl.LinuxBrokerHostUsageImpl;
-import org.apache.pulsar.broker.tools.LoadReportCommand.Flags;
import org.apache.pulsar.client.util.ExecutorProvider;
import org.apache.pulsar.policies.data.loadbalancer.ResourceUsage;
import org.apache.pulsar.policies.data.loadbalancer.SystemResourceUsage;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Model.CommandSpec;
+import picocli.CommandLine.Option;
+import picocli.CommandLine.Spec;
/**
* The command to collect the load report of a specific broker.
*/
-public class LoadReportCommand extends CliCommand {
+@Command(name = "load-report", description = "Collect the load report of a specific broker")
+public class LoadReportCommand implements Callable {
- private static final String NAME = "load-report";
- private static final String DESC = "Collect the load report of a specific broker";
+ @Option(names = {"-i", "--interval-ms"}, description = "Interval to collect load report, in milliseconds")
+ public int intervalMilliseconds = 100;
- /**
- * The CLI flags of load report command.
- */
- public static class Flags extends CliFlags {
-
- @Parameter(
- names = {
- "-i", "--interval-ms"
- },
- description = "Interval to collect load report, in milliseconds"
- )
- public int intervalMilliseconds = 100;
-
- }
-
- public LoadReportCommand() {
- super(CliSpec.newBuilder()
- .withName(NAME)
- .withDescription(DESC)
- .withFlags(new Flags())
- .build());
- }
+ @Spec
+ CommandSpec spec;
@Override
- public Boolean apply(CliFlags globalFlags, String[] args) {
- CliSpec newSpec = CliSpec.newBuilder(spec)
- .withRunFunc(cmdFlags -> apply(cmdFlags))
- .build();
- return 0 == Cli.runCli(newSpec, args);
- }
-
- private boolean apply(Flags flags) {
-
+ public Integer call() throws Exception {
boolean isLinux = SystemUtils.IS_OS_LINUX;
- spec.console().println("OS ARCH: " + SystemUtils.OS_ARCH);
- spec.console().println("OS NAME: " + SystemUtils.OS_NAME);
- spec.console().println("OS VERSION: " + SystemUtils.OS_VERSION);
- spec.console().println("Linux: " + isLinux);
- spec.console().println("--------------------------------------");
- spec.console().println();
- spec.console().println("Load Report Interval : " + flags.intervalMilliseconds + " ms");
- spec.console().println();
- spec.console().println("--------------------------------------");
- spec.console().println();
+ spec.commandLine().getOut().println("OS ARCH: " + SystemUtils.OS_ARCH);
+ spec.commandLine().getOut().println("OS NAME: " + SystemUtils.OS_NAME);
+ spec.commandLine().getOut().println("OS VERSION: " + SystemUtils.OS_VERSION);
+ spec.commandLine().getOut().println("Linux: " + isLinux);
+ spec.commandLine().getOut().println("--------------------------------------");
+ spec.commandLine().getOut().println();
+ spec.commandLine().getOut().println("Load Report Interval : " + intervalMilliseconds + " ms");
+ spec.commandLine().getOut().println();
+ spec.commandLine().getOut().println("--------------------------------------");
+ spec.commandLine().getOut().println();
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(
new ExecutorProvider.ExtendedThreadFactory("load-report"));
@@ -105,7 +77,7 @@ private boolean apply(Flags flags) {
hostUsage.calculateBrokerHostUsage();
try {
- TimeUnit.MILLISECONDS.sleep(flags.intervalMilliseconds);
+ TimeUnit.MILLISECONDS.sleep(intervalMilliseconds);
} catch (InterruptedException e) {
}
hostUsage.calculateBrokerHostUsage();
@@ -117,13 +89,13 @@ private boolean apply(Flags flags) {
printResourceUsage("Bandwidth In", usage.bandwidthIn);
printResourceUsage("Bandwidth Out", usage.bandwidthOut);
- return true;
+ return 0;
} finally {
scheduler.shutdown();
}
}
private void printResourceUsage(String name, ResourceUsage usage) {
- spec.console().println(name + " : usage = " + usage.usage + ", limit = " + usage.limit);
+ spec.commandLine().getOut().println(name + " : usage = " + usage.usage + ", limit = " + usage.limit);
}
}
diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/compaction/CompactorTool.java b/pulsar-broker/src/main/java/org/apache/pulsar/compaction/CompactorTool.java
index 83ff790228108b..f8cc95e6ac0ba8 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/compaction/CompactorTool.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/compaction/CompactorTool.java
@@ -20,8 +20,6 @@
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
-import com.beust.jcommander.JCommander;
-import com.beust.jcommander.Parameter;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import io.netty.channel.EventLoopGroup;
import io.netty.util.concurrent.DefaultThreadFactory;
@@ -48,20 +46,25 @@
import org.apache.pulsar.policies.data.loadbalancer.AdvertisedListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
+import picocli.CommandLine.ScopeType;
+@Command(name = "compact-topic", showDefaultValues = true, scope = ScopeType.INHERIT)
public class CompactorTool {
private static class Arguments {
- @Parameter(names = {"-c", "--broker-conf"}, description = "Configuration file for Broker")
+ @Option(names = {"-c", "--broker-conf"}, description = "Configuration file for Broker")
private String brokerConfigFile = "conf/broker.conf";
- @Parameter(names = {"-t", "--topic"}, description = "Topic to compact", required = true)
+ @Option(names = {"-t", "--topic"}, description = "Topic to compact", required = true)
private String topic;
- @Parameter(names = {"-h", "--help"}, description = "Show this help message")
+ @Option(names = {"-h", "--help"}, description = "Show this help message")
private boolean help = false;
- @Parameter(names = {"-g", "--generate-docs"}, description = "Generate docs")
+ @Option(names = {"-g", "--generate-docs"}, description = "Generate docs")
private boolean generateDocs = false;
}
@@ -107,13 +110,11 @@ public static PulsarClient createClient(ServiceConfiguration brokerConfig) throw
public static void main(String[] args) throws Exception {
Arguments arguments = new Arguments();
- JCommander jcommander = new JCommander(arguments);
- jcommander.setProgramName("PulsarTopicCompactor");
-
- // parse args by JCommander
- jcommander.parse(args);
+ CommandLine commander = new CommandLine(arguments);
+ commander.setCommandName("PulsarTopicCompactor");
+ commander.parseArgs(args);
if (arguments.help) {
- jcommander.usage();
+ commander.usage(commander.getOut());
System.exit(0);
}
@@ -126,7 +127,7 @@ public static void main(String[] args) throws Exception {
// init broker config
if (isBlank(arguments.brokerConfigFile)) {
- jcommander.usage();
+ commander.usage(commander.getOut());
throw new IllegalArgumentException("Need to specify a configuration file for broker");
}
diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/utils/auth/tokens/TokensCliUtils.java b/pulsar-broker/src/main/java/org/apache/pulsar/utils/auth/tokens/TokensCliUtils.java
index fa3a7bed8f6411..4ae28b2c0bdb80 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/utils/auth/tokens/TokensCliUtils.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/utils/auth/tokens/TokensCliUtils.java
@@ -18,11 +18,7 @@
*/
package org.apache.pulsar.utils.auth.tokens;
-import com.beust.jcommander.DefaultUsageFormatter;
-import com.beust.jcommander.IUsageFormatter;
-import com.beust.jcommander.JCommander;
-import com.beust.jcommander.Parameter;
-import com.beust.jcommander.Parameters;
+import com.google.common.annotations.VisibleForTesting;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.Jwts;
@@ -31,7 +27,6 @@
import io.jsonwebtoken.io.Encoders;
import io.jsonwebtoken.security.Keys;
import java.io.BufferedReader;
-import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
@@ -40,34 +35,42 @@
import java.security.KeyPair;
import java.util.Date;
import java.util.Optional;
+import java.util.concurrent.Callable;
import javax.crypto.SecretKey;
import lombok.Cleanup;
import org.apache.pulsar.broker.authentication.utils.AuthTokenUtils;
-import org.apache.pulsar.cli.converters.TimeUnitToSecondsConverter;
+import org.apache.pulsar.cli.converters.picocli.TimeUnitToSecondsConverter;
import org.apache.pulsar.docs.tools.CmdGenerateDocs;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
+import picocli.CommandLine.Parameters;
+import picocli.CommandLine.ScopeType;
+@Command(name = "tokens", showDefaultValues = true, scope = ScopeType.INHERIT)
public class TokensCliUtils {
- public static class Arguments {
- @Parameter(names = {"-h", "--help"}, description = "Show this help message")
- private boolean help = false;
- }
+ private final CommandLine commander;
+
+ @Option(names = {"-h", "--help"}, usageHelp = true, description = "Show this help message")
+ private boolean help;
- @Parameters(commandDescription = "Create a new secret key")
- public static class CommandCreateSecretKey {
- @Parameter(names = {"-a",
+ @Command(description = "Create a new secret key")
+ public static class CommandCreateSecretKey implements Callable {
+ @Option(names = {"-a",
"--signature-algorithm"}, description = "The signature algorithm for the new secret key.")
SignatureAlgorithm algorithm = SignatureAlgorithm.HS256;
- @Parameter(names = {"-o",
+ @Option(names = {"-o",
"--output"}, description = "Write the secret key to a file instead of stdout")
String outputFile;
- @Parameter(names = {
+ @Option(names = {
"-b", "--base64"}, description = "Encode the key in base64")
boolean base64 = false;
- public void run() throws IOException {
+ @Override
+ public Integer call() throws Exception {
SecretKey secretKey = AuthTokenUtils.createSecretKey(algorithm);
byte[] encoded = secretKey.getEncoded();
@@ -80,67 +83,73 @@ public void run() throws IOException {
} else {
System.out.write(encoded);
}
+
+ return 0;
}
}
- @Parameters(commandDescription = "Create a new or pair of keys public/private")
- public static class CommandCreateKeyPair {
- @Parameter(names = {"-a",
+ @Command(description = "Create a new or pair of keys public/private")
+ public static class CommandCreateKeyPair implements Callable {
+ @Option(names = {"-a",
"--signature-algorithm"}, description = "The signature algorithm for the new key pair.")
SignatureAlgorithm algorithm = SignatureAlgorithm.RS256;
- @Parameter(names = {
+ @Option(names = {
"--output-private-key"}, description = "File where to write the private key", required = true)
String privateKeyFile;
- @Parameter(names = {
+ @Option(names = {
"--output-public-key"}, description = "File where to write the public key", required = true)
String publicKeyFile;
- public void run() throws IOException {
+ @Override
+ public Integer call() throws Exception {
KeyPair pair = Keys.keyPairFor(algorithm);
Files.write(Paths.get(publicKeyFile), pair.getPublic().getEncoded());
Files.write(Paths.get(privateKeyFile), pair.getPrivate().getEncoded());
+
+ return 0;
}
}
- @Parameters(commandDescription = "Create a new token")
- public static class CommandCreateToken {
- @Parameter(names = {"-a",
+ @Command(description = "Create a new token")
+ public static class CommandCreateToken implements Callable {
+ @Option(names = {"-a",
"--signature-algorithm"}, description = "The signature algorithm for the new key pair.")
SignatureAlgorithm algorithm = SignatureAlgorithm.RS256;
- @Parameter(names = {"-s",
+ @Option(names = {"-s",
"--subject"},
description = "Specify the 'subject' or 'principal' associate with this token", required = true)
private String subject;
- @Parameter(names = {"-e",
+ @Option(names = {"-e",
"--expiry-time"},
description = "Relative expiry time for the token (eg: 1h, 3d, 10y)."
+ " (m=minutes) Default: no expiration",
- converter = TimeUnitToSecondsConverter.class)
+ converter = TimeUnitToSecondsConverter.class)
private Long expiryTime = null;
- @Parameter(names = {"-sk",
+ @Option(names = {"-sk",
"--secret-key"},
description = "Pass the secret key for signing the token. This can either be: data:, file:, etc..")
private String secretKey;
- @Parameter(names = {"-pk",
+ @Option(names = {"-pk",
"--private-key"},
description = "Pass the private key for signing the token. This can either be: data:, file:, etc..")
private String privateKey;
- public void run() throws Exception {
+ @Override
+ public Integer call() throws Exception {
if (secretKey == null && privateKey == null) {
System.err.println(
"Either --secret-key or --private-key needs to be passed for signing a token");
- System.exit(1);
+ return 1;
} else if (secretKey != null && privateKey != null) {
System.err.println(
"Only one of --secret-key and --private-key needs to be passed for signing a token");
- System.exit(1);
+ return 1;
}
Key signingKey;
@@ -159,27 +168,30 @@ public void run() throws Exception {
String token = AuthTokenUtils.createToken(signingKey, subject, optExpiryTime);
System.out.println(token);
+
+ return 0;
}
}
- @Parameters(commandDescription = "Show the content of token")
- public static class CommandShowToken {
+ @Command(description = "Show the content of token")
+ public static class CommandShowToken implements Callable {
- @Parameter(description = "The token string", arity = 1)
- private java.util.List args;
+ @Parameters(description = "The token string", arity = "0..1")
+ private String args;
- @Parameter(names = {"-i",
+ @Option(names = {"-i",
"--stdin"}, description = "Read token from standard input")
private Boolean stdin = false;
- @Parameter(names = {"-f",
+ @Option(names = {"-f",
"--token-file"}, description = "Read token from a file")
private String tokenFile;
- public void run() throws Exception {
+ @Override
+ public Integer call() throws Exception {
String token;
if (args != null) {
- token = args.get(0);
+ token = args;
} else if (stdin) {
@Cleanup
BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
@@ -192,59 +204,61 @@ public void run() throws Exception {
System.err.println(
"Token needs to be either passed as an argument or through `--stdin`,"
+ " `--token-file` or by the `TOKEN` environment variable");
- System.exit(1);
- return;
+ return 1;
}
String[] parts = token.split("\\.");
System.out.println(new String(Decoders.BASE64URL.decode(parts[0])));
System.out.println("---");
System.out.println(new String(Decoders.BASE64URL.decode(parts[1])));
+
+ return 0;
}
}
- @Parameters(commandDescription = "Validate a token against a key")
- public static class CommandValidateToken {
+ @Command(description = "Validate a token against a key")
+ public static class CommandValidateToken implements Callable {
- @Parameter(names = {"-a",
+ @Option(names = {"-a",
"--signature-algorithm"}, description = "The signature algorithm for the key pair if using public key.")
SignatureAlgorithm algorithm = SignatureAlgorithm.RS256;
- @Parameter(description = "The token string", arity = 1)
- private java.util.List args;
+ @Parameters(description = "The token string", arity = "0..1")
+ private String args;
- @Parameter(names = {"-i",
+ @Option(names = {"-i",
"--stdin"}, description = "Read token from standard input")
private Boolean stdin = false;
- @Parameter(names = {"-f",
+ @Option(names = {"-f",
"--token-file"}, description = "Read token from a file")
private String tokenFile;
- @Parameter(names = {"-sk",
+ @Option(names = {"-sk",
"--secret-key"},
description = "Pass the secret key for validating the token. This can either be: data:, file:, etc..")
private String secretKey;
- @Parameter(names = {"-pk",
+ @Option(names = {"-pk",
"--public-key"},
description = "Pass the public key for validating the token. This can either be: data:, file:, etc..")
private String publicKey;
- public void run() throws Exception {
+ @Override
+ public Integer call() throws Exception {
if (secretKey == null && publicKey == null) {
System.err.println(
"Either --secret-key or --public-key needs to be passed for signing a token");
- System.exit(1);
+ return 1;
} else if (secretKey != null && publicKey != null) {
System.err.println(
"Only one of --secret-key and --public-key needs to be passed for signing a token");
- System.exit(1);
+ return 1;
}
String token;
if (args != null) {
- token = args.get(0);
+ token = args;
} else if (stdin) {
@Cleanup
BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
@@ -257,8 +271,7 @@ public void run() throws Exception {
System.err.println(
"Token needs to be either passed as an argument or through `--stdin`,"
+ " `--token-file` or by the `TOKEN` environment variable");
- System.exit(1);
- return;
+ return 1;
}
Key validationKey;
@@ -279,64 +292,46 @@ public void run() throws Exception {
.parse(token);
System.out.println(jwt.getBody());
+ return 0;
}
}
- public static void main(String[] args) throws Exception {
- Arguments arguments = new Arguments();
- JCommander jcommander = new JCommander(arguments);
- IUsageFormatter usageFormatter = new DefaultUsageFormatter(jcommander);
-
- CommandCreateSecretKey commandCreateSecretKey = new CommandCreateSecretKey();
- jcommander.addCommand("create-secret-key", commandCreateSecretKey);
-
- CommandCreateKeyPair commandCreateKeyPair = new CommandCreateKeyPair();
- jcommander.addCommand("create-key-pair", commandCreateKeyPair);
-
- CommandCreateToken commandCreateToken = new CommandCreateToken();
- jcommander.addCommand("create", commandCreateToken);
-
- CommandShowToken commandShowToken = new CommandShowToken();
- jcommander.addCommand("show", commandShowToken);
+ @Command
+ static class GenDoc implements Callable {
- CommandValidateToken commandValidateToken = new CommandValidateToken();
- jcommander.addCommand("validate", commandValidateToken);
+ private final CommandLine rootCmd;
- jcommander.addCommand("gen-doc", new Object());
-
- try {
- jcommander.parse(args);
-
- if (arguments.help || jcommander.getParsedCommand() == null) {
- jcommander.usage();
- System.exit(1);
- }
- } catch (Exception e) {
- System.err.println(e);
- String chosenCommand = jcommander.getParsedCommand();
- usageFormatter.usage(chosenCommand);
- System.exit(1);
+ public GenDoc(CommandLine rootCmd) {
+ this.rootCmd = rootCmd;
}
- String cmd = jcommander.getParsedCommand();
-
- if (cmd.equals("create-secret-key")) {
- commandCreateSecretKey.run();
- } else if (cmd.equals("create-key-pair")) {
- commandCreateKeyPair.run();
- } else if (cmd.equals("create")) {
- commandCreateToken.run();
- } else if (cmd.equals("show")) {
- commandShowToken.run();
- } else if (cmd.equals("validate")) {
- commandValidateToken.run();
- } else if (cmd.equals("gen-doc")) {
+ @Override
+ public Integer call() throws Exception {
CmdGenerateDocs genDocCmd = new CmdGenerateDocs("pulsar");
- genDocCmd.addCommand("tokens", jcommander);
+ genDocCmd.addCommand("tokens", rootCmd);
genDocCmd.run(null);
- } else {
- System.err.println("Invalid command: " + cmd);
- System.exit(1);
+
+ return 0;
}
}
+
+ TokensCliUtils() {
+ commander = new CommandLine(this);
+ commander.addSubcommand("create-secret-key", CommandCreateSecretKey.class);
+ commander.addSubcommand("create-key-pair", CommandCreateKeyPair.class);
+ commander.addSubcommand("create", CommandCreateToken.class);
+ commander.addSubcommand("show", CommandShowToken.class);
+ commander.addSubcommand("validate", CommandValidateToken.class);
+ commander.addSubcommand("gen-doc", new GenDoc(commander));
+ }
+
+ @VisibleForTesting
+ int execute(String[] args) {
+ return commander.execute(args);
+ }
+
+ public static void main(String[] args) throws Exception {
+ TokensCliUtils tokensCliUtils = new TokensCliUtils();
+ System.exit(tokensCliUtils.execute(args));
+ }
}
diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/PulsarBrokerStarterTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/PulsarBrokerStarterTest.java
index 1bc3bd26f12947..4c05a991b7ffeb 100644
--- a/pulsar-broker/src/test/java/org/apache/pulsar/PulsarBrokerStarterTest.java
+++ b/pulsar-broker/src/test/java/org/apache/pulsar/PulsarBrokerStarterTest.java
@@ -22,7 +22,6 @@
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
-import com.beust.jcommander.Parameter;
import com.google.common.collect.Sets;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -32,14 +31,16 @@
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.PrintWriter;
-import java.lang.reflect.Constructor;
+import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
+import lombok.Cleanup;
+import org.apache.pulsar.PulsarBrokerStarter.BrokerStarter;
import org.apache.pulsar.broker.ServiceConfiguration;
-import org.apache.pulsar.docs.tools.CmdGenerateDocs;
import org.testng.annotations.Test;
+import picocli.CommandLine.Option;
@Test(groups = "broker")
public class PulsarBrokerStarterTest {
@@ -282,12 +283,14 @@ public void testGlobalZooKeeperConfig() throws SecurityException, NoSuchMethodEx
*/
@Test
public void testMainWithNoArgument() throws Exception {
- try {
- PulsarBrokerStarter.main(new String[0]);
- fail("No argument to main should've raised FileNotFoundException for no broker config!");
- } catch (FileNotFoundException e) {
- // code should reach here.
- }
+ BrokerStarter brokerStarter = new BrokerStarter();
+ @Cleanup
+ StringWriter err = new StringWriter();
+ @Cleanup
+ PrintWriter printWriter = new PrintWriter(err);
+ brokerStarter.getCommander().setErr(printWriter);
+ assertEquals(brokerStarter.start(new String[0]), 1);
+ assertTrue(err.toString().contains("FileNotFoundException"));
}
/**
@@ -296,16 +299,16 @@ public void testMainWithNoArgument() throws Exception {
*/
@Test
public void testMainRunBookieAndAutoRecoveryNoConfig() throws Exception {
- try {
- File testConfigFile = createValidBrokerConfigFile();
- String[] args = {"-c", testConfigFile.getAbsolutePath(), "-rb", "-ra", "-bc", ""};
- PulsarBrokerStarter.main(args);
- fail("No Config file for bookie auto recovery should've raised IllegalArgumentException!");
- } catch (IllegalArgumentException e) {
- // code should reach here.
- e.printStackTrace();
- assertEquals(e.getMessage(), "No configuration file for Bookie");
- }
+ File testConfigFile = createValidBrokerConfigFile();
+ String[] args = {"-c", testConfigFile.getAbsolutePath(), "-rb", "-ra", "-bc", ""};
+ BrokerStarter starter = new BrokerStarter();
+ @Cleanup
+ StringWriter err = new StringWriter();
+ @Cleanup
+ PrintWriter printWriter = new PrintWriter(err);
+ starter.getCommander().setErr(printWriter);
+ assertEquals(starter.start(args), 1);
+ assertTrue(err.toString().contains("No configuration file for Bookie"));
}
/**
@@ -314,15 +317,16 @@ public void testMainRunBookieAndAutoRecoveryNoConfig() throws Exception {
*/
@Test
public void testMainRunBookieRecoveryNoConfig() throws Exception {
- try {
- File testConfigFile = createValidBrokerConfigFile();
- String[] args = {"-c", testConfigFile.getAbsolutePath(), "-ra", "-bc", ""};
- PulsarBrokerStarter.main(args);
- fail("No Config file for bookie auto recovery should've raised IllegalArgumentException!");
- } catch (IllegalArgumentException e) {
- // code should reach here.
- assertEquals(e.getMessage(), "No configuration file for Bookie");
- }
+ File testConfigFile = createValidBrokerConfigFile();
+ String[] args = {"-c", testConfigFile.getAbsolutePath(), "-ra", "-bc", ""};
+ BrokerStarter starter = new BrokerStarter();
+ @Cleanup
+ StringWriter err = new StringWriter();
+ @Cleanup
+ PrintWriter printWriter = new PrintWriter(err);
+ starter.getCommander().setErr(printWriter);
+ assertEquals(starter.start(args), 1);
+ assertTrue(err.toString().contains("No configuration file for Bookie"));
}
/**
@@ -330,15 +334,16 @@ public void testMainRunBookieRecoveryNoConfig() throws Exception {
*/
@Test
public void testMainRunBookieNoConfig() throws Exception {
- try {
- File testConfigFile = createValidBrokerConfigFile();
- String[] args = {"-c", testConfigFile.getAbsolutePath(), "-rb", "-bc", ""};
- PulsarBrokerStarter.main(args);
- fail("No Config file for bookie should've raised IllegalArgumentException!");
- } catch (IllegalArgumentException e) {
- // code should reach here
- assertEquals(e.getMessage(), "No configuration file for Bookie");
- }
+ File testConfigFile = createValidBrokerConfigFile();
+ String[] args = {"-c", testConfigFile.getAbsolutePath(), "-rb", "-bc", ""};
+ BrokerStarter starter = new BrokerStarter();
+ @Cleanup
+ StringWriter err = new StringWriter();
+ @Cleanup
+ PrintWriter printWriter = new PrintWriter(err);
+ starter.getCommander().setErr(printWriter);
+ assertEquals(starter.start(args), 1);
+ assertTrue(err.toString().contains("No configuration file for Bookie"));
}
/**
@@ -346,14 +351,16 @@ public void testMainRunBookieNoConfig() throws Exception {
*/
@Test
public void testMainEnableRunBookieThroughBrokerConfig() throws Exception {
- try {
- File testConfigFile = createValidBrokerConfigFile();
- String[] args = {"-c", testConfigFile.getAbsolutePath()};
- PulsarBrokerStarter.main(args);
- fail("No argument to main should've raised IllegalArgumentException for no bookie config!");
- } catch (IllegalArgumentException e) {
- // code should reach here.
- }
+ File testConfigFile = createValidBrokerConfigFile();
+ String[] args = {"-c", testConfigFile.getAbsolutePath()};
+ BrokerStarter starter = new BrokerStarter();
+ @Cleanup
+ StringWriter err = new StringWriter();
+ @Cleanup
+ PrintWriter printWriter = new PrintWriter(err);
+ starter.getCommander().setErr(printWriter);
+ assertEquals(starter.start(args), 1);
+ assertTrue(err.toString().contains("IllegalArgumentException"));
}
@Test
@@ -364,21 +371,15 @@ public void testMainGenerateDocs() throws Exception {
System.setOut(new PrintStream(baoStream));
Class argumentsClass = Class.forName("org.apache.pulsar.PulsarBrokerStarter$StarterArguments");
- Constructor constructor = argumentsClass.getDeclaredConstructor();
- constructor.setAccessible(true);
- Object obj = constructor.newInstance();
-
- CmdGenerateDocs cmd = new CmdGenerateDocs("pulsar");
- cmd.addCommand("broker", obj);
- cmd.run(null);
+ PulsarBrokerStarter.main(new String[]{"-g"});
String message = baoStream.toString();
Field[] fields = argumentsClass.getDeclaredFields();
for (Field field : fields) {
- boolean fieldHasAnno = field.isAnnotationPresent(Parameter.class);
+ boolean fieldHasAnno = field.isAnnotationPresent(Option.class);
if (fieldHasAnno) {
- Parameter fieldAnno = field.getAnnotation(Parameter.class);
+ Option fieldAnno = field.getAnnotation(Option.class);
String[] names = fieldAnno.names();
String nameStr = Arrays.asList(names).toString();
nameStr = nameStr.substring(1, nameStr.length() - 1);
diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/PulsarClusterMetadataSetupTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/PulsarClusterMetadataSetupTest.java
index 6196f666988696..710e040f8df1cd 100644
--- a/pulsar-broker/src/test/java/org/apache/pulsar/PulsarClusterMetadataSetupTest.java
+++ b/pulsar-broker/src/test/java/org/apache/pulsar/PulsarClusterMetadataSetupTest.java
@@ -19,13 +19,15 @@
package org.apache.pulsar;
import static org.testng.Assert.assertTrue;
-import com.beust.jcommander.Parameter;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.util.Arrays;
+import lombok.extern.slf4j.Slf4j;
import org.testng.annotations.Test;
+import picocli.CommandLine.Option;
+@Slf4j
public class PulsarClusterMetadataSetupTest {
@Test
public void testMainGenerateDocs() throws Exception {
@@ -43,16 +45,16 @@ public void testMainGenerateDocs() throws Exception {
Field[] fields = argumentsClass.getDeclaredFields();
for (Field field : fields) {
- boolean fieldHasAnno = field.isAnnotationPresent(Parameter.class);
+ boolean fieldHasAnno = field.isAnnotationPresent(Option.class);
if (fieldHasAnno) {
- Parameter fieldAnno = field.getAnnotation(Parameter.class);
+ Option fieldAnno = field.getAnnotation(Option.class);
String[] names = fieldAnno.names();
- if (names.length == 0) {
+ if (names.length == 0 || fieldAnno.hidden()) {
continue;
}
String nameStr = Arrays.asList(names).toString();
nameStr = nameStr.substring(1, nameStr.length() - 1);
- assertTrue(message.indexOf(nameStr) > 0);
+ assertTrue(message.indexOf(nameStr) > 0, nameStr);
}
}
} finally {
diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/PulsarClusterMetadataTeardownTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/PulsarClusterMetadataTeardownTest.java
index f6a388dac76e3e..95d12f378c55fd 100644
--- a/pulsar-broker/src/test/java/org/apache/pulsar/PulsarClusterMetadataTeardownTest.java
+++ b/pulsar-broker/src/test/java/org/apache/pulsar/PulsarClusterMetadataTeardownTest.java
@@ -19,12 +19,12 @@
package org.apache.pulsar;
import static org.testng.Assert.assertTrue;
-import com.beust.jcommander.Parameter;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.util.Arrays;
import org.testng.annotations.Test;
+import picocli.CommandLine.Option;
public class PulsarClusterMetadataTeardownTest {
@Test
@@ -43,9 +43,9 @@ public void testMainGenerateDocs() throws Exception {
Field[] fields = argumentsClass.getDeclaredFields();
for (Field field : fields) {
- boolean fieldHasAnno = field.isAnnotationPresent(Parameter.class);
+ boolean fieldHasAnno = field.isAnnotationPresent(Option.class);
if (fieldHasAnno) {
- Parameter fieldAnno = field.getAnnotation(Parameter.class);
+ Option fieldAnno = field.getAnnotation(Option.class);
String[] names = fieldAnno.names();
if (names.length == 0) {
continue;
diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/PulsarInitialNamespaceSetupTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/PulsarInitialNamespaceSetupTest.java
index c1ad8c621c46d6..0c6ba05b460e77 100644
--- a/pulsar-broker/src/test/java/org/apache/pulsar/PulsarInitialNamespaceSetupTest.java
+++ b/pulsar-broker/src/test/java/org/apache/pulsar/PulsarInitialNamespaceSetupTest.java
@@ -19,12 +19,12 @@
package org.apache.pulsar;
import static org.testng.Assert.assertTrue;
-import com.beust.jcommander.Parameter;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.util.Arrays;
import org.testng.annotations.Test;
+import picocli.CommandLine.Option;
public class PulsarInitialNamespaceSetupTest {
@Test
@@ -43,9 +43,9 @@ public void testMainGenerateDocs() throws Exception {
Field[] fields = argumentsClass.getDeclaredFields();
for (Field field : fields) {
- boolean fieldHasAnno = field.isAnnotationPresent(Parameter.class);
+ boolean fieldHasAnno = field.isAnnotationPresent(Option.class);
if (fieldHasAnno) {
- Parameter fieldAnno = field.getAnnotation(Parameter.class);
+ Option fieldAnno = field.getAnnotation(Option.class);
String[] names = fieldAnno.names();
if (names.length == 0) {
continue;
diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/PulsarTransactionCoordinatorMetadataSetupTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/PulsarTransactionCoordinatorMetadataSetupTest.java
index 70c7c7bd62ee98..6ff055385b2a45 100644
--- a/pulsar-broker/src/test/java/org/apache/pulsar/PulsarTransactionCoordinatorMetadataSetupTest.java
+++ b/pulsar-broker/src/test/java/org/apache/pulsar/PulsarTransactionCoordinatorMetadataSetupTest.java
@@ -19,12 +19,12 @@
package org.apache.pulsar;
import static org.testng.Assert.assertTrue;
-import com.beust.jcommander.Parameter;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.util.Arrays;
import org.testng.annotations.Test;
+import picocli.CommandLine.Option;
public class PulsarTransactionCoordinatorMetadataSetupTest {
@Test
@@ -43,9 +43,9 @@ public void testMainGenerateDocs() throws Exception {
Field[] fields = argumentsClass.getDeclaredFields();
for (Field field : fields) {
- boolean fieldHasAnno = field.isAnnotationPresent(Parameter.class);
+ boolean fieldHasAnno = field.isAnnotationPresent(Option.class);
if (fieldHasAnno) {
- Parameter fieldAnno = field.getAnnotation(Parameter.class);
+ Option fieldAnno = field.getAnnotation(Option.class);
String[] names = fieldAnno.names();
if (names.length == 0) {
continue;
diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/PulsarVersionStarterTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/PulsarVersionStarterTest.java
index 219e3b80cd3080..b921c3d3843152 100644
--- a/pulsar-broker/src/test/java/org/apache/pulsar/PulsarVersionStarterTest.java
+++ b/pulsar-broker/src/test/java/org/apache/pulsar/PulsarVersionStarterTest.java
@@ -19,12 +19,12 @@
package org.apache.pulsar;
import static org.testng.Assert.assertTrue;
-import com.beust.jcommander.Parameter;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.util.Arrays;
import org.testng.annotations.Test;
+import picocli.CommandLine.Option;
public class PulsarVersionStarterTest {
@Test
@@ -43,9 +43,9 @@ public void testMainGenerateDocs() throws Exception {
Field[] fields = argumentsClass.getDeclaredFields();
for (Field field : fields) {
- boolean fieldHasAnno = field.isAnnotationPresent(Parameter.class);
+ boolean fieldHasAnno = field.isAnnotationPresent(Option.class);
if (fieldHasAnno) {
- Parameter fieldAnno = field.getAnnotation(Parameter.class);
+ Option fieldAnno = field.getAnnotation(Option.class);
String[] names = fieldAnno.names();
if (names.length == 0) {
continue;
diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/tools/BrokerToolTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/tools/BrokerToolTest.java
index ad2cf7784eb1f4..063c041f2e0fe5 100644
--- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/tools/BrokerToolTest.java
+++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/tools/BrokerToolTest.java
@@ -19,12 +19,12 @@
package org.apache.pulsar.broker.tools;
import static org.testng.Assert.assertTrue;
-import com.beust.jcommander.Parameter;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.util.Arrays;
import org.testng.annotations.Test;
+import picocli.CommandLine.Option;
/**
* Broker Tool Tests.
@@ -47,12 +47,12 @@ public void testGenerateDocs() throws Exception {
String message = baoStream.toString();
- Class argumentsClass = Class.forName("org.apache.pulsar.broker.tools.LoadReportCommand$Flags");
+ Class argumentsClass = Class.forName("org.apache.pulsar.broker.tools.LoadReportCommand");
Field[] fields = argumentsClass.getDeclaredFields();
for (Field field : fields) {
- boolean fieldHasAnno = field.isAnnotationPresent(Parameter.class);
+ boolean fieldHasAnno = field.isAnnotationPresent(Option.class);
if (fieldHasAnno) {
- Parameter fieldAnno = field.getAnnotation(Parameter.class);
+ Option fieldAnno = field.getAnnotation(Option.class);
String[] names = fieldAnno.names();
String nameStr = Arrays.asList(names).toString();
nameStr = nameStr.substring(1, nameStr.length() - 1);
diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/compaction/CompactorToolTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/compaction/CompactorToolTest.java
index fb8d6566d9a0d3..72b8628cacaa8c 100644
--- a/pulsar-broker/src/test/java/org/apache/pulsar/compaction/CompactorToolTest.java
+++ b/pulsar-broker/src/test/java/org/apache/pulsar/compaction/CompactorToolTest.java
@@ -22,7 +22,6 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.testng.Assert.assertTrue;
-import com.beust.jcommander.Parameter;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Constructor;
@@ -37,6 +36,7 @@
import org.apache.pulsar.client.api.PulsarClientException;
import org.apache.pulsar.docs.tools.CmdGenerateDocs;
import org.testng.annotations.Test;
+import picocli.CommandLine.Option;
/**
* CompactorTool Tests.
@@ -69,9 +69,9 @@ public void testGenerateDocs() throws Exception {
Field[] fields = argumentsClass.getDeclaredFields();
for (Field field : fields) {
- boolean fieldHasAnno = field.isAnnotationPresent(Parameter.class);
+ boolean fieldHasAnno = field.isAnnotationPresent(Option.class);
if (fieldHasAnno) {
- Parameter fieldAnno = field.getAnnotation(Parameter.class);
+ Option fieldAnno = field.getAnnotation(Option.class);
String[] names = fieldAnno.names();
String nameStr = Arrays.asList(names).toString();
nameStr = nameStr.substring(1, nameStr.length() - 1);
diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/utils/auth/tokens/TokensCliUtilsTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/utils/auth/tokens/TokensCliUtilsTest.java
index a488e4d958429e..d5dc259438ea8c 100644
--- a/pulsar-broker/src/test/java/org/apache/pulsar/utils/auth/tokens/TokensCliUtilsTest.java
+++ b/pulsar-broker/src/test/java/org/apache/pulsar/utils/auth/tokens/TokensCliUtilsTest.java
@@ -19,12 +19,12 @@
package org.apache.pulsar.utils.auth.tokens;
import static org.testng.Assert.assertTrue;
-import com.beust.jcommander.Parameter;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.util.Arrays;
import org.testng.annotations.Test;
+import picocli.CommandLine.Option;
/**
* TokensCliUtils Tests.
@@ -43,7 +43,7 @@ public void testGenerateDocs() throws Exception {
ByteArrayOutputStream baoStream = new ByteArrayOutputStream();
System.setOut(new PrintStream(baoStream));
- TokensCliUtils.main(new String[]{"gen-doc"});
+ new TokensCliUtils().execute(new String[]{"gen-doc"});
String message = baoStream.toString();
@@ -68,9 +68,9 @@ private void assertInnerClass(String className, String message) throws Exception
Class argumentsClass = Class.forName(className);
Field[] fields = argumentsClass.getDeclaredFields();
for (Field field : fields) {
- boolean fieldHasAnno = field.isAnnotationPresent(Parameter.class);
+ boolean fieldHasAnno = field.isAnnotationPresent(Option.class);
if (fieldHasAnno) {
- Parameter fieldAnno = field.getAnnotation(Parameter.class);
+ Option fieldAnno = field.getAnnotation(Option.class);
String[] names = fieldAnno.names();
if (names.length < 1) {
continue;
diff --git a/pulsar-docs-tools/pom.xml b/pulsar-docs-tools/pom.xml
index 40bddfde53276f..e275d128fb01eb 100644
--- a/pulsar-docs-tools/pom.xml
+++ b/pulsar-docs-tools/pom.xml
@@ -43,8 +43,8 @@
swagger-core
- com.beust
- jcommander
+ info.picocli
+ picocli
diff --git a/pulsar-docs-tools/src/main/java/org/apache/pulsar/docs/tools/BaseGenerateDocumentation.java b/pulsar-docs-tools/src/main/java/org/apache/pulsar/docs/tools/BaseGenerateDocumentation.java
index db6178a7fda4d5..ff474d98edc1a3 100644
--- a/pulsar-docs-tools/src/main/java/org/apache/pulsar/docs/tools/BaseGenerateDocumentation.java
+++ b/pulsar-docs-tools/src/main/java/org/apache/pulsar/docs/tools/BaseGenerateDocumentation.java
@@ -18,8 +18,6 @@
*/
package org.apache.pulsar.docs.tools;
-import com.beust.jcommander.JCommander;
-import com.beust.jcommander.Parameter;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import java.lang.annotation.Annotation;
@@ -28,6 +26,7 @@
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
+import java.util.concurrent.Callable;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import lombok.SneakyThrows;
@@ -35,49 +34,44 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.apache.commons.lang3.tuple.Pair;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
+import picocli.CommandLine.ScopeType;
@Slf4j
-public abstract class BaseGenerateDocumentation {
+@Command(name = "gen-doc", showDefaultValues = true, scope = ScopeType.INHERIT)
+public abstract class BaseGenerateDocumentation implements Callable {
- JCommander jcommander;
+ CommandLine commander;
- @Parameter(names = {"-c", "--class-names"}, description =
+ @Option(names = {"-c", "--class-names"}, description =
"List of class names, generate documentation based on the annotations in the Class")
private List classNames = new ArrayList<>();
- @Parameter(names = {"-h", "--help"}, help = true, description = "Show this help.")
+ @Option(names = {"-h", "--help"}, usageHelp = true, description = "Show this help.")
boolean help;
public BaseGenerateDocumentation() {
- jcommander = new JCommander();
- jcommander.setProgramName("pulsar-generateDocumentation");
- jcommander.addObject(this);
+ commander = new CommandLine(this);
}
- public boolean run(String[] args) throws Exception {
- if (args.length == 0) {
- jcommander.usage();
- return false;
- }
-
- if (help) {
- jcommander.usage();
- return true;
- }
-
- try {
- jcommander.parse(Arrays.copyOfRange(args, 0, args.length));
- } catch (Exception e) {
- System.err.println(e.getMessage());
- jcommander.usage();
- return false;
- }
+ @Override
+ public Integer call() throws Exception {
if (classNames != null) {
for (String className : classNames) {
System.out.println(generateDocumentByClassName(className));
}
}
- return true;
+ return 0;
+ }
+
+ public boolean run(String[] args) throws Exception {
+ if (args.length == 0) {
+ commander.usage(commander.getOut());
+ return false;
+ }
+ return commander.execute(args) == 0;
}
protected abstract String generateDocumentByClassName(String className) throws Exception;
diff --git a/pulsar-docs-tools/src/main/java/org/apache/pulsar/docs/tools/CmdGenerateDocs.java b/pulsar-docs-tools/src/main/java/org/apache/pulsar/docs/tools/CmdGenerateDocs.java
index 8f784c1eca1fa8..a66da9fd6c6505 100644
--- a/pulsar-docs-tools/src/main/java/org/apache/pulsar/docs/tools/CmdGenerateDocs.java
+++ b/pulsar-docs-tools/src/main/java/org/apache/pulsar/docs/tools/CmdGenerateDocs.java
@@ -18,144 +18,155 @@
*/
package org.apache.pulsar.docs.tools;
-import com.beust.jcommander.JCommander;
-import com.beust.jcommander.Parameter;
-import com.beust.jcommander.ParameterDescription;
-import com.beust.jcommander.Parameters;
+import com.google.common.annotations.VisibleForTesting;
import java.util.ArrayList;
-import java.util.Comparator;
import java.util.List;
-import java.util.Map;
+import java.util.concurrent.Callable;
import lombok.Getter;
import lombok.Setter;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Model.ArgSpec;
+import picocli.CommandLine.Model.OptionSpec;
+import picocli.CommandLine.Option;
+import picocli.CommandLine.ScopeType;
@Getter
@Setter
-@Parameters(commandDescription = "Generate documentation automatically.")
-public class CmdGenerateDocs {
+@Command(showDefaultValues = true, scope = ScopeType.INHERIT)
+public class CmdGenerateDocs implements Callable {
- @Parameter(
+ @Option(
names = {"-h", "--help"},
- description = "Display help information"
+ description = "Display help information",
+ usageHelp = true
)
public boolean help;
- @Parameter(
+ @Option(
names = {"-n", "--command-names"},
description = "List of command names"
)
private List commandNames = new ArrayList<>();
private static final String name = "gen-doc";
- private final JCommander jcommander;
+ private final CommandLine commander;
public CmdGenerateDocs(String cmdName) {
- jcommander = new JCommander(this);
- jcommander.setProgramName(cmdName);
+ commander = new CommandLine(this);
+ commander.setCommandName(cmdName);
}
public CmdGenerateDocs addCommand(String name, Object command) {
- jcommander.addCommand(name, command);
+ commander.addSubcommand(name, command);
return this;
}
public boolean run(String[] args) {
- JCommander tmpCmd = new JCommander(this);
- tmpCmd.setProgramName(jcommander.getProgramName() + " " + name);
- try {
- if (args == null) {
- args = new String[]{};
- }
- tmpCmd.parse(args);
- } catch (Exception e) {
- System.err.println(e.getMessage());
- System.err.println();
- tmpCmd.usage();
- return false;
+ if (args == null) {
+ args = new String[]{};
}
- if (help) {
- tmpCmd.usage();
- return true;
+ return commander.execute(args) == 0;
+ }
+
+ private static String getCommandDescription(CommandLine commandLine) {
+ String[] description = commandLine.getCommandSpec().usageMessage().description();
+ if (description != null && description.length != 0) {
+ return description[0];
}
+ return "";
+ }
- if (commandNames.size() == 0) {
- for (Map.Entry cmd : jcommander.getCommands().entrySet()) {
- if (cmd.getKey().equals(name)) {
- continue;
- }
- System.out.println(generateDocument(cmd.getKey(), jcommander));
- }
- } else {
- for (String commandName : commandNames) {
- if (commandName.equals(name)) {
- continue;
- }
- if (!jcommander.getCommands().keySet().contains(commandName)) {
- continue;
- }
- System.out.println(generateDocument(commandName, jcommander));
- }
+ private static String getArgDescription(ArgSpec argSpec) {
+ String[] description = argSpec.description();
+ if (description != null && description.length != 0) {
+ return description[0];
}
- return true;
+ return "";
}
- private String generateDocument(String module, JCommander commander) {
- JCommander cmd = commander.getCommands().get(module);
+ private String generateDocument(String module, CommandLine commander) {
StringBuilder sb = new StringBuilder();
sb.append("# ").append(module).append("\n\n");
- String desc = commander.getUsageFormatter().getCommandDescription(module);
+ String desc = getCommandDescription(commander);
if (null != desc && !desc.isEmpty()) {
sb.append(desc).append("\n");
}
sb.append("\n\n```shell\n")
.append("$ ");
- if (null != jcommander.getProgramName() && !jcommander.getProgramName().isEmpty()) {
- sb.append(jcommander.getProgramName()).append(" ");
- }
- sb.append(module);
- if (cmd.getObjects().size() > 0
- && cmd.getObjects().get(0).getClass().getName().equals("com.beust.jcommander.JCommander")) {
- JCommander cmdObj = (JCommander) cmd.getObjects().get(0);
+ String commandName = commander.getCommandName();
+ sb.append(this.commander.getCommandName() + " " + commandName);
+ if (!commander.getSubcommands().isEmpty()) {
sb.append(" subcommand").append("\n```").append("\n\n");
- cmdObj.getCommands().forEach((subK, subV) -> {
+ commander.getSubcommands().forEach((subK, subV) -> {
if (!subK.equals(name)) {
sb.append("\n\n## ").append(subK).append("\n\n");
- String subDesc = cmdObj.getUsageFormatter().getCommandDescription(subK);
+ String subDesc = getCommandDescription(subV);
if (null != subDesc && !subDesc.isEmpty()) {
sb.append(subDesc).append("\n");
}
sb.append("```shell\n$ ");
- if (null != jcommander.getProgramName() && !jcommander.getProgramName().isEmpty()) {
- sb.append(jcommander.getProgramName()).append(" ");
- }
+ sb.append(this.commander.getCommandName()).append(" ");
sb.append(module).append(" ").append(subK).append(" options").append("\n```\n\n");
- List options = cmdObj.getCommands().get(subK).getParameters();
- if (options.size() > 0) {
+ List argSpecs = subV.getCommandSpec().args();
+ if (argSpecs.size() > 0) {
sb.append("|Flag|Description|Default|\n");
sb.append("|---|---|---|\n");
}
- options.forEach((option) ->
- sb.append("| `").append(option.getNames())
- .append("` | ").append(option.getDescription().replace("\n", " "))
- .append("|").append(option.getDefault()).append("|\n")
- );
+
+ argSpecs.forEach(option -> {
+ if (option.hidden() || !(option instanceof OptionSpec)) {
+ return;
+ }
+ sb.append("| `").append(String.join(", ", ((OptionSpec) option).names()))
+ .append("` | ").append(getArgDescription(option).replace("\n", " "))
+ .append("|").append(option.defaultValueString()).append("|\n");
+ });
}
});
} else {
sb.append(" options").append("\n```").append("\n\n");
sb.append("|Flag|Description|Default|\n");
sb.append("|---|---|---|\n");
- List options = cmd.getParameters();
- options.stream().sorted(Comparator.comparing(ParameterDescription::getLongestName))
- .forEach((option) ->
- sb.append("| `")
- .append(option.getNames())
- .append("` | ")
- .append(option.getDescription().replace("\n", " "))
- .append("|")
- .append(option.getDefault()).append("|\n")
- );
+ List argSpecs = commander.getCommandSpec().args();
+ argSpecs.forEach(option -> {
+ if (option.hidden() || !(option instanceof OptionSpec)) {
+ return;
+ }
+ sb.append("| `")
+ .append(String.join(", ", ((OptionSpec) option).names()))
+ .append("` | ")
+ .append(getArgDescription(option).replace("\n", " "))
+ .append("|")
+ .append(option.defaultValueString()).append("|\n");
+ });
}
return sb.toString();
}
+
+ @Override
+ public Integer call() throws Exception {
+ if (commandNames.size() == 0) {
+ commander.getSubcommands().forEach((name, cmd) -> {
+ commander.getOut().println(generateDocument(name, cmd));
+ });
+ } else {
+ for (String commandName : commandNames) {
+ if (commandName.equals(name)) {
+ continue;
+ }
+ CommandLine cmd = commander.getSubcommands().get(commandName);
+ if (cmd == null) {
+ continue;
+ }
+ commander.getOut().println(generateDocument(commandName, cmd));
+ }
+ }
+ return 0;
+ }
+
+ @VisibleForTesting
+ CommandLine getCommander() {
+ return commander;
+ }
}
diff --git a/pulsar-docs-tools/src/test/java/org/apache/pulsar/docs/tools/CmdGenerateDocsTest.java b/pulsar-docs-tools/src/test/java/org/apache/pulsar/docs/tools/CmdGenerateDocsTest.java
index 3f96ddaef591a1..0f0f96f80ecb0d 100644
--- a/pulsar-docs-tools/src/test/java/org/apache/pulsar/docs/tools/CmdGenerateDocsTest.java
+++ b/pulsar-docs-tools/src/test/java/org/apache/pulsar/docs/tools/CmdGenerateDocsTest.java
@@ -19,79 +19,63 @@
package org.apache.pulsar.docs.tools;
import static org.testng.Assert.assertEquals;
-import com.beust.jcommander.Parameter;
-import com.beust.jcommander.Parameters;
-import java.io.ByteArrayOutputStream;
-import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import org.testng.annotations.Test;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
public class CmdGenerateDocsTest {
- @Parameters(commandDescription = "Options")
+ @Command
public class Arguments {
- @Parameter(names = {"-h", "--help"}, description = "Show this help message")
+ @Option(names = {"-h", "--help"}, description = "Show this help message")
private boolean help = false;
- @Parameter(names = {"-n", "--name"}, description = "Name")
+ @Option(names = {"-n", "--name"}, description = "Name")
private String name;
}
@Test
public void testHelp() {
- PrintStream oldStream = System.out;
- try {
- ByteArrayOutputStream baoStream = new ByteArrayOutputStream(2048);
- PrintStream cacheStream = new PrintStream(baoStream);
- System.setOut(cacheStream);
+ CmdGenerateDocs cmd = new CmdGenerateDocs("pulsar");
+ cmd.addCommand("test", new Arguments());
+ StringWriter stringWriter = new StringWriter();
+ cmd.getCommander().setOut(new PrintWriter(stringWriter));
+ cmd.run(new String[]{"-h"});
- CmdGenerateDocs cmd = new CmdGenerateDocs("pulsar");
- cmd.addCommand("test", new Arguments());
- cmd.run(new String[]{"-h"});
-
- String message = baoStream.toString();
- String rightMsg = "Usage: pulsar gen-doc [options]\n"
- + " Options:\n"
- + " -n, --command-names\n"
- + " List of command names\n"
- + " Default: []\n"
- + " -h, --help\n"
- + " Display help information\n"
- + " Default: false\n"
- + System.lineSeparator();
- assertEquals(rightMsg, message);
- } finally {
- System.setOut(oldStream);
- }
+ String message = stringWriter.toString();
+ String rightMsg = "Usage: pulsar [-h] [-n=]... [COMMAND]\n"
+ + " -h, --help Display help information\n"
+ + " -n, --command-names=\n"
+ + " List of command names\n"
+ + " Default: []\n"
+ + "Commands:\n"
+ + " test\n";
+ assertEquals(message, rightMsg);
}
@Test
public void testGenerateDocs() {
- PrintStream oldStream = System.out;
- try {
- ByteArrayOutputStream baoStream = new ByteArrayOutputStream(2048);
- PrintStream cacheStream = new PrintStream(baoStream);
- System.setOut(cacheStream);
-
- CmdGenerateDocs cmd = new CmdGenerateDocs("pulsar");
- cmd.addCommand("test", new Arguments());
- cmd.run(null);
+ CmdGenerateDocs cmd = new CmdGenerateDocs("pulsar");
+ cmd.addCommand("test", new Arguments());
+ StringWriter stringWriter = new StringWriter();
+ cmd.getCommander().setOut(new PrintWriter(stringWriter));
+ cmd.run(null);
- String message = baoStream.toString();
- String rightMsg = "# test\n\n"
- + "Options\n\n"
- + "\n"
- + "```shell\n"
- + "$ pulsar test options\n"
- + "```\n"
- + "\n"
- + "|Flag|Description|Default|\n"
- + "|---|---|---|\n"
- + "| `-h, --help` | Show this help message|false|\n"
- + "| `-n, --name` | Name|null|\n"
- + System.lineSeparator();
- assertEquals(rightMsg, message);
- } finally {
- System.setOut(oldStream);
- }
+ String message = stringWriter.toString();
+ String rightMsg = "# test\n\n"
+ + "\n"
+ + "\n"
+ + "```shell\n"
+ + "$ pulsar test options\n"
+ + "```\n"
+ + "\n"
+ + "|Flag|Description|Default|\n"
+ + "|---|---|---|\n"
+ + "| `-h, --help` | Show this help message|false|\n"
+ + "| `-n, --name` | Name|null|\n"
+ + System.lineSeparator();
+ assertEquals(message, rightMsg);
}
}
diff --git a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/FunctionWorkerStarter.java b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/FunctionWorkerStarter.java
index 679ce1db70d97a..c5fb552d9cc800 100644
--- a/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/FunctionWorkerStarter.java
+++ b/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/FunctionWorkerStarter.java
@@ -19,11 +19,13 @@
package org.apache.pulsar.functions.worker;
import static org.apache.commons.lang3.StringUtils.isBlank;
-import com.beust.jcommander.JCommander;
-import com.beust.jcommander.Parameter;
import lombok.extern.slf4j.Slf4j;
import org.apache.pulsar.common.util.ShutdownUtil;
import org.apache.pulsar.docs.tools.CmdGenerateDocs;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
+import picocli.CommandLine.ScopeType;
/**
* A starter to start function worker.
@@ -31,35 +33,36 @@
@Slf4j
public class FunctionWorkerStarter {
+ @Command(name = "functions-worker", showDefaultValues = true, scope = ScopeType.INHERIT)
private static class WorkerArguments {
- @Parameter(
+ @Option(
names = { "-c", "--conf" },
description = "Configuration File for Function Worker")
private String configFile;
- @Parameter(names = {"-h", "--help"}, description = "Show this help message")
+ @Option(names = {"-h", "--help"}, description = "Show this help message")
private boolean help = false;
- @Parameter(names = {"-g", "--generate-docs"}, description = "Generate docs")
+ @Option(names = {"-g", "--generate-docs"}, description = "Generate docs")
private boolean generateDocs = false;
}
+
public static void main(String[] args) throws Exception {
WorkerArguments workerArguments = new WorkerArguments();
- JCommander commander = new JCommander(workerArguments);
- commander.setProgramName("FunctionWorkerStarter");
+ CommandLine commander = new CommandLine(workerArguments);
+ commander.setCommandName("FunctionWorkerStarter");
- // parse args by commander
- commander.parse(args);
+ commander.parseArgs(args);
if (workerArguments.help) {
- commander.usage();
+ commander.usage(commander.getOut());
return;
}
if (workerArguments.generateDocs) {
CmdGenerateDocs cmd = new CmdGenerateDocs("pulsar");
- cmd.addCommand("functions-worker", workerArguments);
+ cmd.addCommand("functions-worker", commander);
cmd.run(null);
return;
}
diff --git a/pulsar-functions/worker/src/test/java/org/apache/pulsar/functions/worker/FunctionWorkerStarterTest.java b/pulsar-functions/worker/src/test/java/org/apache/pulsar/functions/worker/FunctionWorkerStarterTest.java
index 51bcd974f509a3..6fa0bec1b362d4 100644
--- a/pulsar-functions/worker/src/test/java/org/apache/pulsar/functions/worker/FunctionWorkerStarterTest.java
+++ b/pulsar-functions/worker/src/test/java/org/apache/pulsar/functions/worker/FunctionWorkerStarterTest.java
@@ -19,12 +19,12 @@
package org.apache.pulsar.functions.worker;
import static org.testng.Assert.assertTrue;
-import com.beust.jcommander.Parameter;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.util.Arrays;
import org.testng.annotations.Test;
+import picocli.CommandLine.Option;
public class FunctionWorkerStarterTest {
@Test
@@ -43,9 +43,9 @@ public void testMainGenerateDocs() throws Exception {
Field[] fields = argumentsClass.getDeclaredFields();
for (Field field : fields) {
- boolean fieldHasAnno = field.isAnnotationPresent(Parameter.class);
+ boolean fieldHasAnno = field.isAnnotationPresent(Option.class);
if (fieldHasAnno) {
- Parameter fieldAnno = field.getAnnotation(Parameter.class);
+ Option fieldAnno = field.getAnnotation(Option.class);
String[] names = fieldAnno.names();
String nameStr = Arrays.asList(names).toString();
nameStr = nameStr.substring(1, nameStr.length() - 1);
diff --git a/pulsar-io/docs/pom.xml b/pulsar-io/docs/pom.xml
index adbc2f4efad396..0fd774aaafeb5d 100644
--- a/pulsar-io/docs/pom.xml
+++ b/pulsar-io/docs/pom.xml
@@ -42,8 +42,8 @@
reflections
- com.beust
- jcommander
+ info.picocli
+ picocli
diff --git a/pulsar-proxy/pom.xml b/pulsar-proxy/pom.xml
index 55dfd11e40e93d..64ca301facf4d1 100644
--- a/pulsar-proxy/pom.xml
+++ b/pulsar-proxy/pom.xml
@@ -184,8 +184,8 @@
- com.beust
- jcommander
+ info.picocli
+ picocli
diff --git a/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ProxyServiceStarter.java b/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ProxyServiceStarter.java
index 1a98601f2a95d3..72d54601995f1d 100644
--- a/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ProxyServiceStarter.java
+++ b/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ProxyServiceStarter.java
@@ -23,8 +23,6 @@
import static org.apache.commons.lang3.StringUtils.isEmpty;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.pulsar.common.stats.JvmMetrics.getJvmDirectMemoryUsed;
-import com.beust.jcommander.JCommander;
-import com.beust.jcommander.Parameter;
import com.google.common.annotations.VisibleForTesting;
import io.prometheus.client.CollectorRegistry;
import io.prometheus.client.Gauge;
@@ -61,40 +59,45 @@
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
+import picocli.CommandLine.ScopeType;
/**
* Starts an instance of the Pulsar ProxyService.
*/
+@Command(name = "proxy", showDefaultValues = true, scope = ScopeType.INHERIT)
public class ProxyServiceStarter {
- @Parameter(names = { "-c", "--config" }, description = "Configuration file path", required = true)
+ @Option(names = { "-c", "--config" }, description = "Configuration file path", required = true)
private String configFile;
@Deprecated
- @Parameter(names = { "-zk", "--zookeeper-servers" },
+ @Option(names = { "-zk", "--zookeeper-servers" },
description = "Local zookeeper connection string, please use --metadata-store instead")
private String zookeeperServers = "";
- @Parameter(names = { "-md", "--metadata-store" }, description = "Metadata Store service url. eg: zk:my-zk:2181")
+ @Option(names = { "-md", "--metadata-store" }, description = "Metadata Store service url. eg: zk:my-zk:2181")
private String metadataStoreUrl = "";
@Deprecated
- @Parameter(names = { "-gzk", "--global-zookeeper-servers" },
+ @Option(names = { "-gzk", "--global-zookeeper-servers" },
description = "Global zookeeper connection string, please use --configuration-metadata-store instead")
private String globalZookeeperServers = "";
@Deprecated
- @Parameter(names = { "-cs", "--configuration-store-servers" },
+ @Option(names = { "-cs", "--configuration-store-servers" },
description = "Configuration store connection string, "
+ "please use --configuration-metadata-store instead")
private String configurationStoreServers = "";
- @Parameter(names = { "-cms", "--configuration-metadata-store" },
+ @Option(names = { "-cms", "--configuration-metadata-store" },
description = "The metadata store URL for the configuration data")
private String configurationMetadataStoreUrl = "";
- @Parameter(names = { "-h", "--help" }, description = "Show this help message")
+ @Option(names = { "-h", "--help" }, description = "Show this help message")
private boolean help = false;
- @Parameter(names = {"-g", "--generate-docs"}, description = "Generate docs")
+ @Option(names = {"-g", "--generate-docs"}, description = "Generate docs")
private boolean generateDocs = false;
private ProxyConfiguration config;
@@ -116,23 +119,22 @@ public ProxyServiceStarter(String[] args) throws Exception {
exception.printStackTrace(System.out);
});
- JCommander jcommander = new JCommander();
+ CommandLine commander = new CommandLine(this);
try {
- jcommander.addObject(this);
- jcommander.parse(args);
+ commander.parseArgs(args);
if (help || isBlank(configFile)) {
- jcommander.usage();
+ commander.usage(commander.getOut());
return;
}
if (this.generateDocs) {
CmdGenerateDocs cmd = new CmdGenerateDocs("pulsar");
- cmd.addCommand("proxy", this);
+ cmd.addCommand("proxy", commander);
cmd.run(null);
System.exit(0);
}
} catch (Exception e) {
- jcommander.usage();
+ commander.getErr().println(e);
System.exit(1);
}
diff --git a/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/service/WebSocketServiceStarter.java b/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/service/WebSocketServiceStarter.java
index fd38208323c49c..ed1a99b8133316 100644
--- a/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/service/WebSocketServiceStarter.java
+++ b/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/service/WebSocketServiceStarter.java
@@ -22,8 +22,6 @@
import static org.apache.pulsar.websocket.admin.WebSocketWebResource.ADMIN_PATH_V1;
import static org.apache.pulsar.websocket.admin.WebSocketWebResource.ADMIN_PATH_V2;
import static org.apache.pulsar.websocket.admin.WebSocketWebResource.ATTRIBUTE_PROXY_SERVICE_NAME;
-import com.beust.jcommander.JCommander;
-import com.beust.jcommander.Parameter;
import org.apache.pulsar.common.configuration.PulsarConfigurationLoader;
import org.apache.pulsar.common.configuration.VipStatus;
import org.apache.pulsar.common.util.ShutdownUtil;
@@ -37,37 +35,42 @@
import org.apache.pulsar.websocket.admin.v2.WebSocketProxyStatsV2;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
+import picocli.CommandLine.Parameters;
+import picocli.CommandLine.ScopeType;
public class WebSocketServiceStarter {
+ @Command(name = "websocket", showDefaultValues = true, scope = ScopeType.INHERIT)
private static class Arguments {
- @Parameter(description = "config file")
+ @Parameters(description = "config file", arity = "0..1")
private String configFile = "";
- @Parameter(names = {"-h", "--help"}, description = "Show this help message")
+ @Option(names = {"-h", "--help"}, description = "Show this help message")
private boolean help = false;
- @Parameter(names = {"-g", "--generate-docs"}, description = "Generate docs")
+ @Option(names = {"-g", "--generate-docs"}, description = "Generate docs")
private boolean generateDocs = false;
}
public static void main(String[] args) throws Exception {
Arguments arguments = new Arguments();
- JCommander jcommander = new JCommander();
+ CommandLine commander = new CommandLine(arguments);
try {
- jcommander.addObject(arguments);
- jcommander.parse(args);
+ commander.parseArgs(args);
if (arguments.help) {
- jcommander.usage();
+ commander.usage(commander.getOut());
return;
}
if (arguments.generateDocs && arguments.configFile != null) {
CmdGenerateDocs cmd = new CmdGenerateDocs("pulsar");
- cmd.addCommand("websocket", arguments);
+ cmd.addCommand("websocket", commander);
cmd.run(null);
return;
}
} catch (Exception e) {
- jcommander.usage();
+ commander.getErr().println(e);
return;
}
diff --git a/pulsar-websocket/src/test/java/org/apache/pulsar/websocket/service/WebSocketServiceStarterTest.java b/pulsar-websocket/src/test/java/org/apache/pulsar/websocket/service/WebSocketServiceStarterTest.java
index c898a07e228004..f9a190cf8662de 100644
--- a/pulsar-websocket/src/test/java/org/apache/pulsar/websocket/service/WebSocketServiceStarterTest.java
+++ b/pulsar-websocket/src/test/java/org/apache/pulsar/websocket/service/WebSocketServiceStarterTest.java
@@ -19,12 +19,12 @@
package org.apache.pulsar.websocket.service;
import static org.testng.Assert.assertTrue;
-import com.beust.jcommander.Parameter;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.util.Arrays;
import org.testng.annotations.Test;
+import picocli.CommandLine.Option;
public class WebSocketServiceStarterTest {
@Test
@@ -43,9 +43,9 @@ public void testMainGenerateDocs() throws Exception {
Field[] fields = argumentsClass.getDeclaredFields();
for (Field field : fields) {
- boolean fieldHasAnno = field.isAnnotationPresent(Parameter.class);
+ boolean fieldHasAnno = field.isAnnotationPresent(Option.class);
if (fieldHasAnno) {
- Parameter fieldAnno = field.getAnnotation(Parameter.class);
+ Option fieldAnno = field.getAnnotation(Option.class);
String[] names = fieldAnno.names();
if (names.length == 0) {
continue;