diff --git a/apl-db-updater/pom.xml b/apl-db-updater/pom.xml
index 0f9449eefa..5207639d14 100644
--- a/apl-db-updater/pom.xml
+++ b/apl-db-updater/pom.xml
@@ -11,6 +11,18 @@
apl-db-updater
+
+
+
+ com.apollocurrency
+ apl-bom-ext
+ 2.0.1
+ pom
+ import
+
+
+
+
diff --git a/apl-dex/pom.xml b/apl-dex/pom.xml
index 4e983dae00..83ce19d1c1 100644
--- a/apl-dex/pom.xml
+++ b/apl-dex/pom.xml
@@ -150,4 +150,12 @@
+
+
+
+ maven-surefire-plugin
+
+
+
+
\ No newline at end of file
diff --git a/apl-exec/pom.xml b/apl-exec/pom.xml
index e332ddfe76..73fbb9dde0 100644
--- a/apl-exec/pom.xml
+++ b/apl-exec/pom.xml
@@ -46,6 +46,16 @@
com.beust
jcommander
+
+ info.picocli
+ picocli
+
+
+ org.projectlombok
+ lombok
+ provided
+
+
org.junit.platform
@@ -82,6 +92,11 @@
mockito-junit-jupiter
test
+
+ org.junit.jupiter
+ junit-jupiter-params
+ test
+
diff --git a/apl-exec/src/main/java/com/apollocurrency/aplwallet/apl/exec/Apollo.java b/apl-exec/src/main/java/com/apollocurrency/aplwallet/apl/exec/Apollo.java
index 9645f1cfec..4fda55b534 100644
--- a/apl-exec/src/main/java/com/apollocurrency/aplwallet/apl/exec/Apollo.java
+++ b/apl-exec/src/main/java/com/apollocurrency/aplwallet/apl/exec/Apollo.java
@@ -33,7 +33,6 @@
import com.apollocurrency.aplwallet.apl.util.env.dirprovider.DirProviderFactory;
import com.apollocurrency.aplwallet.apl.util.env.dirprovider.PredefinedDirLocations;
import com.apollocurrency.aplwallet.apl.util.injectable.PropertiesHolder;
-import com.beust.jcommander.JCommander;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -49,6 +48,8 @@
import java.util.Properties;
import java.util.UUID;
+import picocli.CommandLine;
+
/**
* Main Apollo startup class
*
@@ -178,26 +179,23 @@ public static void main(String[] argv) {
//parse command line first
CmdLineArgs args = new CmdLineArgs();
- JCommander jc = JCommander.newBuilder()
- .addObject(args)
- .build();
- jc.setProgramName(Constants.APPLICATION);
+ CommandLine pc = new CommandLine(args);
try {
- jc.parse(argv);
+ CommandLine.ParseResult parseResult = pc.parseArgs(argv);
+ if (args.help) {
+ pc.usage(System.err);
+ System.exit(PosixExitCodes.OK.exitCode());
+ }
} catch (RuntimeException ex) {
System.err.println("Error parsing command line arguments.");
System.err.println(ex.getMessage());
- jc.usage();
+ pc.usage(System.err);
System.exit(PosixExitCodes.EX_USAGE.exitCode());
}
if (args.getNetIdx() >= 0 && !args.chainId.isEmpty()) {
System.err.println("--chainId, --testnet and --net parameters are incompatible, please specify only one");
System.exit(PosixExitCodes.EX_USAGE.exitCode());
}
- if (args.help) {
- jc.usage();
- System.exit(PosixExitCodes.OK.exitCode());
- }
//set main application class to runtime
diff --git a/apl-exec/src/main/java/com/apollocurrency/aplwallet/apl/exec/CmdLineArgs.java b/apl-exec/src/main/java/com/apollocurrency/aplwallet/apl/exec/CmdLineArgs.java
index abf14d5dde..a969dbd2e5 100644
--- a/apl-exec/src/main/java/com/apollocurrency/aplwallet/apl/exec/CmdLineArgs.java
+++ b/apl-exec/src/main/java/com/apollocurrency/aplwallet/apl/exec/CmdLineArgs.java
@@ -1,64 +1,76 @@
-package com.apollocurrency.aplwallet.apl.exec;
-
-import com.beust.jcommander.Parameter;
-
-/**
+/*
+ * Copyright © 2018-2022 Apollo Foundation
* Command line parameters
*
* @author alukin@gmail.com
+ * @author tx_hv@ukr.net
*/
+
+package com.apollocurrency.aplwallet.apl.exec;
+
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
+
+@Command(name = "apollo-blockchain")
public class CmdLineArgs {
public static int DEFAULT_DEBUG_LEVEL = 2;
- @Parameter(names = {"--debug", "-d"}, description = "Debug level [0-4] from ERROR to TRACE")
+ @Option(names = {"--debug", "-d"}, description = "Common debug level [0-4] from ERROR=0, WARN=1, INFO=2, DEBUG=3, TRACE=4")
public int debug = DEFAULT_DEBUG_LEVEL;
- @Parameter(names = {"--debug-updater", "-du"}, description = "Force updater to use debug certificates for verifying update transactions")
+ @Option(names = {"--debug-updater", "-du"}, description = "Force updater to use debug certificates for verifying update transactions")
public boolean debugUpdater;
- @Parameter(names = {"--help", "-h"}, help = true, description = "Print help message")
+ @Option(names = {"--help", "-h"}, usageHelp = true, help = true, description = "Print help message")
public boolean help;
- @Parameter(names = {"--service-mode", "-s"}, help = true, description = "Run in service mode with current system user")
+ @Option(names = {"--service-mode", "-s"}, arity = "0..1", defaultValue = "false", fallbackValue = "true", description = "Run in service mode with current system user")
public boolean serviceMode;
- @Parameter(names = {"--ignore-resources"}, description = "Ignore resources bundled with application jar. Default is false")
- public boolean ingnoreResources = false;
- @Parameter(names = {"--config-dir", "-c"}, description = "Load all configuration and resources from specified path. System resources not ignored, standard config search is ignored.")
+ @Option(names = {"--ignore-resources"}, description = "Ignore resources bundled with application jar. Default is false")
+ public boolean ignoreResources = false;
+ @Option(names = {"--config-dir", "-c"}, description = "Load all configuration and resources from specified path. System resources not ignored, standard config search is ignored.")
public String configDir = "";
- @Parameter(names = {"--log-dir", "-l"}, description = "Save log files to from specified directory.")
+ @Option(names = {"--log-dir", "-l"}, description = "Save log files to from specified directory.")
public String logDir = "";
- @Parameter(names = {"--db-dir"}, description = "Load/Save DB files to from specified directory. Ignored if DB URL is remote.")
+ @Option(names = {"--db-dir"}, description = "Load/Save DB files to from specified directory. Ignored if DB URL is remote.")
public String dbDir = "";
- @Parameter(names = {"--vault-key-dir"}, description = "Load/Save vault wallets keys to/form specified keystore directory.")
+ @Option(names = {"--vault-key-dir"}, description = "Load/Save vault wallets keys to/form specified keystore directory.")
public String vaultKeystoreDir = "";
- @Parameter(names = {"--dex-key-dir"}, description = "Load/Save dex keys to/form specified keystore directory.")
+ @Option(names = {"--dex-key-dir"}, description = "Load/Save dex keys to/form specified keystore directory.")
public String dexKeystoreDir = "";
- @Parameter(names = {"--no-shard-import"}, description = "Start from Genesis block, do not try to import last shard")
+ @Option(names = {"--no-shard-import"}, arity = "0..1", defaultValue = "false", fallbackValue = "true",
+ description = "Empty node starts downloading blocks from Genesis block, does not try to import last shard downloaded from another sharded nodes." +
+ " Default: ${DEFAULT-VALUE}, if specified without parameter value is: ${FALLBACK-VALUE}."
+ )
public boolean noShardImport = false;
- @Parameter(names = {"--no-shard-create"}, description = "Do not create shards even if it configured to do so. Shards require much more resources")
+ @Option(names = {"--no-shard-create"}, arity = "0..1", defaultValue = "false", fallbackValue = "true",
+ description = "Do not create shards even if it configured to do so, default: ${DEFAULT-VALUE}, " +
+ "if specified without parameter: ${FALLBACK-VALUE}. Shards are require more OS resources."
+ )
public boolean noShardCreate = false;
- @Parameter(names = {"--update-attachment-file", "-u"}, description = "Full path to file which represent json of UpdateAttachment for local updates debug")
+ @Option(names = {"--update-attachment-file", "-u"},
+ description = "Full path to file which represent json of UpdateAttachment for local updates with debugging purpose.")
public String updateAttachmentFile = "";
// TODO cleanup apl-default.properties
- @Parameter(names = {"--2fa-dir"}, description = "Load/Save 2FA keys to/form specified directory. Note that this parameter will not work when you do not set apl.store2FAInFileSystem=true in apl-default.properties")
+ @Option(names = {"--2fa-dir"}, description = "Load/Save 2FA keys to/form specified directory. Note that this Option will not work when you do not set apl.store2FAInFileSystem=true in apl-default.properties")
public String twoFactorAuthDir = "";
- @Parameter(names = {"--dexp-dir"}, description = "Export/Import CSV data to/form specified directory.")
+ @Option(names = {"--dexp-dir"}, description = "Export/Import CSV data to/form specified directory.")
public String dataExportDir = "";
- @Parameter(names = {"--pid-file"}, description = "Save PID to specified file.")
+ @Option(names = {"--pid-file"}, description = "Save PID to specified file.")
public String pidFile = "";
- @Parameter(names = {"--net", "-n"}, help = true, description = "Connect to net [0-4]. 0 means mainnet, 1 - 1st testnet and so on")
+ @Option(names = {"--net", "-n"}, help = true, description = "Connect to net [0-4]. 0 means mainnet, 1 - 1st testnet and so on")
public int netIdx = -1;
- @Parameter(names = {"--chain", "-C"}, help = true, description = "Connect to net with given chainID. UUID of chain id may be specified partially, 6 symbos min. Configs must be present.")
+ @Option(names = {"--chain", "-C"}, help = true, description = "Connect to net with given chainID. UUID of chain id may be specified partially, 6 symbols min. Config file must be present.")
public String chainId = "";
- @Parameter(names = {"--testnet"}, help = true, description = "Connect to testent 1. Has higher priority then --net")
+ @Option(names = {"--testnet"}, help = true, description = "Connect to testent 1. Has higher priority then --net")
public boolean isTestnet = false;
//---
- @Parameter(names = {"--disable-weld-concurrent-deployment"},
- description = "If use it, Weld doesn't use ConcurrentDeployer and ConcurrentValidator to build the container. Default value is true.")
+ @Option(names = {"--disable-weld-concurrent-deployment"}, defaultValue = "false",
+ description = "If use it, Weld doesn't use ConcurrentDeployer and ConcurrentValidator to build the container. Default value is ${DEFAULT-VALUE}.")
public boolean disableWeldConcurrentDeployment = false;
public boolean isResourceIgnored() {
- return ingnoreResources;
+ return ignoreResources;
}
public int getNetIdx() {
diff --git a/apl-exec/src/test/java/com/apollocurrency/aplwallet/apl/exec/CmdLineArgsTest.java b/apl-exec/src/test/java/com/apollocurrency/aplwallet/apl/exec/CmdLineArgsTest.java
new file mode 100644
index 0000000000..7cd6a6ff02
--- /dev/null
+++ b/apl-exec/src/test/java/com/apollocurrency/aplwallet/apl/exec/CmdLineArgsTest.java
@@ -0,0 +1,200 @@
+package com.apollocurrency.aplwallet.apl.exec;
+
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+import picocli.CommandLine;
+
+import java.util.Arrays;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@Slf4j
+class CmdLineArgsTest {
+
+ String[] allArgStringArray = {
+ "--debug", "4",
+ "--debug-updater", "true",
+ "--help", "true",
+ "--service-mode", "true",
+ "--ignore-resources", "true",
+ "--config-dir", "/tmp",
+ "--log-dir", "/tmp",
+ "--db-dir", "/tmp",
+ "--vault-key-dir", "/tmp",
+ "--dex-key-dir", "/tmp",
+ "--no-shard-import", "true",
+ "--no-shard-create", "true",
+ "--update-attachment-file", "attach-file.bin",
+ "--2fa-dir", "/tmp",
+ "--dexp-dir", "/tmp",
+ "--pid-file", "/tmp/1.pid",
+ "--net", "3",
+ "--chain", "chains-1.json",
+ "--testnet", "false",
+ "--disable-weld-concurrent-deployment", "false"
+ };
+
+ String[] allArgShortArray = {
+ "-d", "1",
+ "-du", "true",
+ "-h", "true",
+ "-s", "true",
+ "--ignore-resources", "true",
+ "-c", "/tmp",
+ "-l", "/tmp",
+ "--db-dir", "/tmp",
+ "--vault-key-dir", "/tmp",
+ "--dex-key-dir", "/tmp",
+ "--no-shard-import", "false",
+ "--no-shard-create", "false",
+ "-u", "attach-file.bin",
+ "--2fa-dir", "/tmp",
+ "--dexp-dir", "/tmp",
+ "--pid-file", "/tmp/1.pid",
+ "-n", "3",
+ "-C", "chains-1.json",
+ "--testnet", "true",
+ "--disable-weld-concurrent-deployment", "false"
+ };
+
+ @Test
+ void testAllArgs_longStringValues() {
+ CmdLineArgs lineArgs = new CmdLineArgs();
+ CommandLine.ParseResult result = new CommandLine(lineArgs).parseArgs(allArgStringArray);
+ log.debug("args = {}, result = {}", allArgStringArray, result);
+ assertEquals(0, result.errors().size());
+ }
+
+ @Test
+ void testAllArgs_emptyValues() {
+ String[] emptyArgs = {};
+ CommandLine.ParseResult result = new CommandLine(new CmdLineArgs()).parseArgs(emptyArgs);
+ log.debug("args = {}, result = {}", allArgStringArray, result);
+ assertEquals(0, result.errors().size());
+ }
+
+ @Test
+ void testAllArgs_shortStringValues() {
+ CommandLine.ParseResult result = new CommandLine(new CmdLineArgs()).parseArgs(allArgShortArray);
+ log.debug("args = {}, result = {}", allArgStringArray, result);
+ assertEquals(0, result.errors().size());
+ }
+
+ @Test
+ void testAllArgs_unknownStringValues() {
+ String[] unknownArgsArray = {"--unknown-param", "-UP"};
+ Exception error = assertThrows(CommandLine.UnmatchedArgumentException.class,
+ () -> new CommandLine(new CmdLineArgs()).parseArgs(unknownArgsArray)
+ );
+ log.debug("args = {}, error = {}", Arrays.toString(unknownArgsArray), error.getMessage());
+ assertEquals("Unknown options: " +
+ Arrays.stream(unknownArgsArray).map(String::valueOf).reduce((a, b) -> "'" + a + "', '" + b).get() + "'",
+ error.getMessage());
+ }
+
+ @ParameterizedTest
+ @CsvSource(value = {"--debug-updater", "--help", "--service-mode", "--ignore-resources", "--no-shard-import",
+ "--no-shard-create", "--testnet", "--disable-weld-concurrent-deployment",
+ "-du", "-h", "-s"
+ })
+ void test_emptyBooleansEvaluatedToTrue(String paramName) {
+ CommandLine.ParseResult result = new CommandLine(new CmdLineArgs()).parseArgs(paramName);
+ log.debug("Parameter = {}, result = {}", paramName, result.errors());
+ assertEquals(0, result.errors().size());
+ assertTrue((Boolean) result.matchedArgs().get(0).typedValues().get(0));
+ }
+
+ @ParameterizedTest
+ @CsvSource(value = {"--debug-updater=false,false", "--help=false,false", "--service-mode=false,false", "--ignore-resources=false,false",
+ "--no-shard-import=false,false", "--no-shard-create=false,false", "--testnet=false,false", "--disable-weld-concurrent-deployment=false,false",
+ "-du,true", "-h,true", "-s,true"
+ })
+ void test_specifiedFalseBooleans(String paramName, String value) {
+ CommandLine.ParseResult result = new CommandLine(new CmdLineArgs()).parseArgs(paramName);
+ log.debug("Parameter = {}, result = {}", paramName, result.errors());
+ assertEquals(0, result.errors().size());
+ assertEquals(Boolean.valueOf(value), result.matchedArgs().get(0).typedValues().get(0));
+ }
+
+ @ParameterizedTest
+ @CsvSource(value = {"--debug-updater=true,true", "--help,true", "--service-mode=true,true", "--ignore-resources=true,true",
+ "--no-shard-import=true,true", "--no-shard-create=true,true", "--testnet=true,true", "--disable-weld-concurrent-deployment=true,true",
+ "-du,true", "-h,true", "-s,true"
+ })
+ void test_specifiedTrueBooleans(String paramName, String value) {
+ CommandLine.ParseResult result = new CommandLine(new CmdLineArgs()).parseArgs(paramName);
+ log.debug("Parameter = {}, result = {}", paramName, result.errors());
+ assertEquals(0, result.errors().size());
+ assertEquals(Boolean.valueOf(value), result.matchedArgs().get(0).typedValues().get(0));
+ }
+
+ @ParameterizedTest
+ @CsvSource(value = {"--debug-updater,true", "--help,true", "--service-mode,true", "--ignore-resources,true",
+ "--no-shard-import,true", "--no-shard-create,true", "--testnet,true", "--disable-weld-concurrent-deployment,true",
+ "-du,true", "-h,true", "-s,true"
+ })
+ void test_specifiedDefaults(String paramName, String value) {
+ CommandLine.ParseResult result = new CommandLine(new CmdLineArgs()).parseArgs(paramName);
+ log.debug("Parameter = {}, result = {}", paramName, result.errors());
+ assertEquals(0, result.errors().size());
+ assertEquals(Boolean.valueOf(value), result.matchedArgs().get(0).typedValues().get(0));
+ }
+
+ @ParameterizedTest
+ @CsvSource(value = {
+ "--config-dir=/tmp,/tmp",
+ "--log-dir=/tmp,/tmp",
+ "--db-dir=/tmp,/tmp",
+ "--vault-key-dir=/tmp,/tmp",
+ "--dex-key-dir=/tmp,/tmp",
+ "--update-attachment-file=attach-file.bin,attach-file.bin",
+ "--2fa-dir=/tmp,/tmp",
+ "--dexp-dir=/tmp,/tmp",
+ "--pid-file=/tmp/1.pid,/tmp/1.pid",
+ "--chain=chains-1.json,chains-1.json",
+ })
+ void test_longStringParamsSpecified(String paramName, String value) {
+ CommandLine.ParseResult result = new CommandLine(new CmdLineArgs()).parseArgs(paramName);
+ log.debug("Parameter = {}, result = {}", paramName, result.errors());
+ assertEquals(0, result.errors().size());
+ assertEquals(value, result.matchedArgs().get(0).typedValues().get(0));
+ }
+
+ @ParameterizedTest
+ @CsvSource(value = {
+ "-c /tmp,/tmp",
+ "-l /tmp,/tmp",
+ "-u attach-file.bin,attach-file.bin",
+ "-C chains-1.json,chains-1.json"
+ })
+ void test_shortStringParamsSpecified(String paramName, String value) {
+ CommandLine.ParseResult result = new CommandLine(new CmdLineArgs()).parseArgs(paramName);
+ log.debug("Parameter = {}, result = {}", paramName, result.errors());
+ assertEquals(0, result.errors().size());
+ assertEquals(value, result.matchedArgs().get(0).typedValues().get(0).toString().trim());
+ }
+
+ @ParameterizedTest
+ @CsvSource(value = {
+ "--config-dir",
+ "--log-dir",
+ "--db-dir",
+ "--vault-key-dir",
+ "--dex-key-dir",
+ "--update-attachment-file",
+ "--2fa-dir",
+ "--dexp-dir",
+ "--pid-file",
+ "--chain",
+ })
+ void test_errorWhenStringParamsIsNotSpecified(String paramName) {
+ Exception error = assertThrows(CommandLine.MissingParameterException.class,
+ () -> new CommandLine(new CmdLineArgs()).parseArgs(paramName)
+ );
+ log.debug("Parameter = {}, error = {}", paramName, error.getMessage());
+ assertTrue(error.getMessage().startsWith("Missing required parameter for option '" + paramName + "'"));
+ }
+
+}
\ No newline at end of file
diff --git a/apl-smc/pom.xml b/apl-smc/pom.xml
index 6b1ca63caa..e20bcc6ad1 100644
--- a/apl-smc/pom.xml
+++ b/apl-smc/pom.xml
@@ -140,4 +140,12 @@
+
+
+
+ maven-surefire-plugin
+
+
+
+
\ No newline at end of file
diff --git a/apl-updater/pom.xml b/apl-updater/pom.xml
index 01a7a7ac8a..316d0b0c29 100644
--- a/apl-updater/pom.xml
+++ b/apl-updater/pom.xml
@@ -105,7 +105,7 @@
maven-surefire-plugin
-
+
diff --git a/apl-vault-wallet/pom.xml b/apl-vault-wallet/pom.xml
index 8fdbdd6dbb..c76426fae8 100644
--- a/apl-vault-wallet/pom.xml
+++ b/apl-vault-wallet/pom.xml
@@ -144,8 +144,14 @@
janino
test
-
-
+
+
+
+ maven-surefire-plugin
+
+
+
+
\ No newline at end of file