Switch yang-model-validator to argparse4j 23/101123/22
authorOleksandrZharov <Oleksandr.Zharov@pantheon.tech>
Fri, 13 May 2022 18:13:23 +0000 (20:13 +0200)
committerRobert Varga <nite@hq.sk>
Mon, 23 May 2022 08:03:15 +0000 (08:03 +0000)
Switched to use argparse4j in yang-model-validator instead of
commons-cli.

Modernized both tools interactions with argparse4j to the
latest best recommended practice.

JIRA: YANGTOOLS-1424
Change-Id: I3520d6b398831cdac0843816e857026675fde5a2
Signed-off-by: OleksandrZharov <Oleksandr.Zharov@pantheon.tech>
Signed-off-by: Ivan Hrasko <ivan.hrasko@pantheon.tech>
tools/yang-model-validator/pom.xml
tools/yang-model-validator/src/main/java/org/opendaylight/yangtools/yang/validator/Main.java
tools/yang-validation-tool/src/main/java/org/opendaylight/yangtools/yang/validation/tool/Params.java

index bfbbb53c7a4abd9dc2bb8846a80e59800b55b198..75b0f620c8f54f19ee0d02f4369fa59ddbd8a159 100644 (file)
@@ -40,9 +40,9 @@
             <artifactId>logback-classic</artifactId>
         </dependency>
         <dependency>
-            <groupId>commons-cli</groupId>
-            <artifactId>commons-cli</artifactId>
-            <version>1.5.0</version>
+            <groupId>net.sourceforge.argparse4j</groupId>
+            <artifactId>argparse4j</artifactId>
+            <version>0.9.0</version>
         </dependency>
     </dependencies>
 
index 1d9aac62deaf758f987533ac6eaa8eebe4c0a7e0..26d5ffa3061a23612d22bfad3c9517f7b4f4daa4 100644 (file)
@@ -14,19 +14,14 @@ import ch.qos.logback.core.FileAppender;
 import com.google.common.base.Stopwatch;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.CommandLineParser;
-import org.apache.commons.cli.DefaultParser;
-import org.apache.commons.cli.HelpFormatter;
-import org.apache.commons.cli.Option;
-import org.apache.commons.cli.OptionGroup;
-import org.apache.commons.cli.Options;
-import org.apache.commons.cli.ParseException;
+import net.sourceforge.argparse4j.ArgumentParsers;
+import net.sourceforge.argparse4j.impl.Arguments;
+import net.sourceforge.argparse4j.inf.ArgumentParser;
+import net.sourceforge.argparse4j.inf.Namespace;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.slf4j.Logger;
@@ -36,21 +31,7 @@ import org.slf4j.LoggerFactory;
  * Main class of Yang parser system test.
  *
  * <p>
- * yang-system-test [-f features] [-h help] [-p path] [-v verbose] yangFiles...
- *  -f,--features &lt;arg&gt;   features is a string in the form
- *                        [feature(,feature)*] and feature is a string in the form
- *                        [($namespace?revision=$revision)$local_name].
- *                        This option is used to prune the data model by removing
- *                        all nodes that are defined with a "if-feature".
- *  -h,--help             print help message and exit.
- *  -p,--path &lt;arg&gt;       path is a colon (:) separated list of directories
- *                        to search for yang modules.
- *  -r, --recursive       recursive search of directories specified by -p option
- *  -v, --verbose         shows details about the results of test running.
- *  -o, --output          path to output file for logs. Output file will be overwritten.
- *  -m, --module-name     validate yang by module name.
- *  -K, --no-warning-for-unkeyed-lists
- *                        do not add warnings about unkeyed lists with config true.
+ * Type yang-system-test -h for usage.
  */
 @SuppressWarnings({"checkstyle:LoggerMustBeSlf4j", "checkstyle:LoggerFactoryClassParameter"})
 public final class Main {
@@ -59,82 +40,53 @@ public final class Main {
             (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
     private static final int MB = 1024 * 1024;
 
-    private static final Option FEATURE = new Option("f", "features", true,
-        "features is a string in the form [feature(,feature)*] and feature is a string in the form "
-                + "[($namespace?revision=$revision)$local_name]. This option is used to prune the data model "
-                + "by removing all nodes that are defined with a \"if-feature\".");
-
-    private static final Option HELP = new Option("h", "help", false, "print help message and exit.");
-    private static final Option MODULE_NAME = new Option("m", "module-name", true,
-            "validate yang model by module name.");
-    private static final Option OUTPUT = new Option("o", "output", true,
-            "path to output file for logs. Output file will be overwritten");
-    private static final Option PATH = new Option("p", "path", true,
-            "path is a colon (:) separated list of directories to search for yang modules.");
-    private static final Option RECURSIVE = new Option("r", "recursive", false,
-            "recursive search of directories specified by -p option.");
-
-    private static final Option DEBUG = new Option("d", "debug", false, "add debug output");
-    private static final Option QUIET = new Option("q", "quiet", false, "completely suppress output.");
-    private static final Option VERBOSE = new Option("v", "verbose", false,
-        "shows details about the results of test running.");
-    private static final Option LIST_WARNING_OFF = new Option("K", "no-warning-for-unkeyed-lists", false,
-        "do not add warnings about unkeyed lists with config true");
+    private static final String YANG_MODEL = "yang-model";
+    private static final String PATH = "path";
+    private static final String RECURSIVE = "recursive";
+    private static final String LIST_WARNING_OFF = "no-warning-for-unkeyed-lists";
+    private static final String OUTPUT = "output";
+    private static final String MODULE_NAME = "module-name";
+    private static final String FEATURES = "features";
+    private static final String DEBUG = "debug";
+    private static final String QUIET = "quiet";
+    private static final String VERBOSE = "verbose";
 
     private Main() {
         // Hidden on purpose
     }
 
-    private static Options createOptions() {
-        return new Options()
-            .addOption(HELP)
-            .addOption(PATH)
-            .addOption(RECURSIVE)
-            .addOptionGroup(new OptionGroup().addOption(DEBUG).addOption(QUIET).addOption(VERBOSE))
-            .addOption(LIST_WARNING_OFF)
-            .addOption(OUTPUT)
-            .addOption(MODULE_NAME)
-            .addOption(FEATURE);
-    }
-
     public static void main(final String[] args) {
-        final HelpFormatter formatter = new HelpFormatter();
-        final Options options = createOptions();
-        final CommandLine arguments = parseArguments(args, options, formatter);
-
-        if (arguments.hasOption(HELP.getLongOpt())) {
-            printHelp(options, formatter);
-            return;
-        }
+        final ArgumentParser parser = getParser();
+        final Namespace arguments = parser.parseArgsOrFail(args);
 
-        final String[] outputValues = arguments.getOptionValues(OUTPUT.getLongOpt());
+        final String outputValues = arguments.get(OUTPUT);
         if (outputValues != null) {
             setOutput(outputValues);
         }
 
         LOG_ROOT.setLevel(Level.WARN);
-        if (arguments.hasOption(DEBUG.getLongOpt())) {
+        if (arguments.getBoolean(DEBUG)) {
             LOG_ROOT.setLevel(Level.DEBUG);
-        } else if (arguments.hasOption(VERBOSE.getLongOpt())) {
+        } else if (arguments.getBoolean(VERBOSE)) {
             LOG_ROOT.setLevel(Level.INFO);
-        } else if (arguments.hasOption(QUIET.getLongOpt())) {
+        } else if (arguments.getBoolean(QUIET)) {
             LOG_ROOT.detachAndStopAllAppenders();
         }
 
-        final boolean warnForUnkeyedLists = !arguments.hasOption(LIST_WARNING_OFF.getLongOpt());
-
         final List<String> yangLibDirs = initYangDirsPath(arguments);
         final List<String> yangFiles = new ArrayList<>();
-        final String[] moduleNameValues = arguments.getOptionValues(MODULE_NAME.getLongOpt());
+        final List<String> moduleNameValues = arguments.get(MODULE_NAME);
         if (moduleNameValues != null) {
-            yangFiles.addAll(Arrays.asList(moduleNameValues));
+            yangFiles.addAll(moduleNameValues);
+        }
+        if (arguments.get(YANG_MODEL) != null) {
+            yangFiles.addAll(arguments.get(YANG_MODEL));
         }
-        yangFiles.addAll(Arrays.asList(arguments.getArgs()));
 
         final Set<QName> supportedFeatures = initSupportedFeatures(arguments);
 
-        runSystemTest(yangLibDirs, yangFiles, supportedFeatures, arguments.hasOption(RECURSIVE.getLongOpt()),
-            warnForUnkeyedLists);
+        runSystemTest(yangLibDirs, yangFiles, supportedFeatures, arguments.getBoolean(RECURSIVE),
+                !arguments.getBoolean(LIST_WARNING_OFF));
 
         LOG_ROOT.getLoggerContext().reset();
     }
@@ -190,23 +142,20 @@ public final class Main {
         printMemoryInfo("after gc");
     }
 
-    private static List<String> initYangDirsPath(final CommandLine arguments) {
+    private static List<String> initYangDirsPath(final Namespace arguments) {
         final List<String> yangDirs = new ArrayList<>();
-        if (arguments.hasOption("path")) {
-            for (final String pathArg : arguments.getOptionValues("path")) {
-                yangDirs.addAll(Arrays.asList(pathArg.split(":")));
-            }
+        final List<String> path = arguments.get(PATH);
+        if (path != null) {
+            yangDirs.addAll(path);
         }
         return yangDirs;
     }
 
-    private static Set<QName> initSupportedFeatures(final CommandLine arguments) {
-        Set<QName> supportedFeatures = null;
-        if (arguments.hasOption("features")) {
-            supportedFeatures = new HashSet<>();
-            for (final String pathArg : arguments.getOptionValues("features")) {
-                supportedFeatures.addAll(createQNames(pathArg.split(",")));
-            }
+    private static Set<QName> initSupportedFeatures(final Namespace arguments) {
+        final Set<QName> supportedFeatures = new HashSet<>();
+        final List<String> features = arguments.get(FEATURES);
+        if (features != null) {
+            supportedFeatures.addAll(createQNames(features.toArray(new String[0])));
         }
         return supportedFeatures;
     }
@@ -216,29 +165,62 @@ public final class Main {
         for (final String featureStr : featuresArg) {
             qnames.add(QName.create(featureStr));
         }
-
         return qnames;
     }
 
-    @SuppressFBWarnings("DM_EXIT")
-    private static CommandLine parseArguments(final String[] args, final Options options,
-            final HelpFormatter formatter) {
-        final CommandLineParser parser = new DefaultParser();
-
-        CommandLine cmd = null;
-        try {
-            cmd = parser.parse(options, args);
-        } catch (final ParseException e) {
-            LOG.error("Failed to parse command line options.", e);
-            printHelp(options, formatter);
-            System.exit(1);
-        }
-
-        return cmd;
-    }
-
-    private static void printHelp(final Options options, final HelpFormatter formatter) {
-        formatter.printHelp("yang-system-test [OPTION...] YANG-FILE...", options);
+    private static ArgumentParser getParser() {
+        final var parser = ArgumentParsers.newFor("yang-system-test").addHelp(true).build()
+                .description("Main class of Yang parser system test.");
+        parser.addArgument(YANG_MODEL)
+                .help("yang file(s) to validate")
+                .dest(YANG_MODEL)
+                .nargs("*")
+                .metavar(YANG_MODEL)
+                .type(String.class);
+        parser.addArgument("-p", "--path")
+                .help("path is a space separated list of directories to search for yang modules")
+                .dest(PATH)
+                .nargs("+")
+                .type(String.class);
+        parser.addArgument("-r", "--recursive")
+                .help("recursive search of directories specified by -p option")
+                .dest(RECURSIVE)
+                .action(Arguments.storeTrue());
+        parser.addArgument("-K", "--no-warning-for-unkeyed-lists")
+                .help("do not add warnings about unkeyed lists with config true")
+                .dest(LIST_WARNING_OFF)
+                .action(Arguments.storeTrue());
+        parser.addArgument("-o", "--output")
+                .help("path to output file for logs. Output file will be overwritten")
+                .dest(OUTPUT);
+        parser.addArgument("-m", "--module-name")
+                .help("validate yang model by module name.")
+                .dest(MODULE_NAME)
+                .nargs("+")
+                .type(String.class);
+        parser.addArgument("-f", "--features").help(
+                """
+                features is a space separated list strings in the form [($namespace?revision=$revision)$local_name].
+                This option is used to prune the data model by removing all nodes that are defined with a "if-feature".
+                """)
+                .dest(FEATURES)
+                .nargs("+")
+                .type(String.class);
+        final var group = parser.addMutuallyExclusiveGroup("logging")
+                .description("exclusive group for logging parameters");
+        group.addArgument("-d", "--debug")
+                .help("add debug output")
+                .dest(DEBUG)
+                .action(Arguments.storeTrue());
+        group.addArgument("-q", "--quiet")
+                .help("completely suppress output")
+                .dest(QUIET)
+                .action(Arguments.storeTrue());
+        group.addArgument("-v", "--verbose")
+                .help("shows details about the results of test running")
+                .dest(VERBOSE)
+                .action(Arguments.storeTrue());
+        return parser;
     }
 
     private static void printMemoryInfo(final String info) {
index aab1789532b1333a213788b2d7f303d462b2131d..4117c08f23b4ac40497f1b5e19cd3ce7407827aa 100644 (file)
@@ -21,7 +21,7 @@ final class Params {
     private File yangSourceDir;
 
     static ArgumentParser getParser() {
-        final ArgumentParser parser = ArgumentParsers.newArgumentParser("jar_file_name");
+        final ArgumentParser parser = ArgumentParsers.newFor("jar_file_name").addHelp(true).build();
         parser.description("Validation Tool for Yang Models")
             .formatUsage();