diff --git a/apache-rat-core/pom.xml b/apache-rat-core/pom.xml
index 3984e84a9..a4c35b8c2 100644
--- a/apache-rat-core/pom.xml
+++ b/apache-rat-core/pom.xml
@@ -37,7 +37,6 @@
src/main/filtered-resources
- org.apache.rat
@@ -56,9 +55,6 @@
-
-
- org.apache.maven.pluginsmaven-jar-plugin
@@ -177,8 +173,20 @@
- org.apache.rat
- apache-rat-testdata
+ com.github.spotbugs
+ spotbugs-annotations
+
+
+ org.apache.velocity
+ velocity-engine-core
+
+
+ org.apache.velocity.tools
+ velocity-tools-generic
+
+
+ org.reflections
+ reflectionstest
@@ -213,11 +221,6 @@
junit-jupiter-apitest
-
- org.junit.vintage
- junit-vintage-engine
- test
- org.junit.jupiterjunit-jupiter-params
diff --git a/apache-rat-tools/src/main/java/org/apache/rat/documentation/options/CLIOption.java b/apache-rat-core/src/main/java/org/apache/rat/CLIOption.java
similarity index 81%
rename from apache-rat-tools/src/main/java/org/apache/rat/documentation/options/CLIOption.java
rename to apache-rat-core/src/main/java/org/apache/rat/CLIOption.java
index fc00e5e15..d7b84951e 100644
--- a/apache-rat-tools/src/main/java/org/apache/rat/documentation/options/CLIOption.java
+++ b/apache-rat-core/src/main/java/org/apache/rat/CLIOption.java
@@ -16,19 +16,21 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.rat.documentation.options;
+package org.apache.rat;
import org.apache.commons.cli.Option;
import org.apache.commons.lang3.StringUtils;
+import org.apache.rat.ui.ArgumentTracker;
+import org.apache.rat.ui.UIOption;
+import org.apache.rat.ui.UIOptionCollection;
-public class CLIOption extends AbstractOption {
-
- public static String createName(final Option option) {
- return StringUtils.defaultIfBlank(option.getLongOpt(), option.getOpt());
- }
+/**
+ * The CLI option definition.
+ */
+public final class CLIOption extends UIOption {
- public CLIOption(final Option option) {
- super(option, createName(option));
+ public CLIOption(final UIOptionCollection collection, final Option option) {
+ super(collection, option, ArgumentTracker.extractName(option));
}
@Override
@@ -47,7 +49,7 @@ public String getText() {
@Override
protected String cleanupName(final Option option) {
- return createName(option);
+ return ArgumentTracker.extractKey(option);
}
@Override
diff --git a/apache-rat-core/src/main/java/org/apache/rat/CLIOptionCollection.java b/apache-rat-core/src/main/java/org/apache/rat/CLIOptionCollection.java
new file mode 100644
index 000000000..feb1cbf51
--- /dev/null
+++ b/apache-rat-core/src/main/java/org/apache/rat/CLIOptionCollection.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.rat;
+
+import org.apache.commons.cli.Option;
+import org.apache.rat.ui.UIOptionCollection;
+
+public final class CLIOptionCollection extends UIOptionCollection {
+ /** The Help option */
+ static final Option HELP = new Option("?", "help", false, "Print help for the RAT command line interface and exit.");
+
+ /** The instance of the collection */
+ public static final CLIOptionCollection INSTANCE = new CLIOptionCollection();
+
+ private CLIOptionCollection() {
+ super(new Builder().uiOption(HELP)
+ .mapper(CLIOption::new));
+ }
+
+ private static final class Builder extends UIOptionCollection.Builder {
+ private Builder() {
+ super();
+ }
+ }
+}
diff --git a/apache-rat-core/src/main/java/org/apache/rat/OptionCollection.java b/apache-rat-core/src/main/java/org/apache/rat/OptionCollection.java
index 6ce2e1c2d..e083ec083 100644
--- a/apache-rat-core/src/main/java/org/apache/rat/OptionCollection.java
+++ b/apache-rat-core/src/main/java/org/apache/rat/OptionCollection.java
@@ -140,9 +140,8 @@ public static ReportConfiguration parseCommands(final File workingDirectory, fin
// for "commandLine"
}
- Arg.processLogLevel(commandLine);
-
ArgumentContext argumentContext = new ArgumentContext(workingDirectory, commandLine);
+ Arg.processLogLevel(argumentContext, CLIOptionCollection.INSTANCE);
if (commandLine.hasOption(HELP)) {
helpCmd.accept(opts);
@@ -175,14 +174,15 @@ public static ReportConfiguration parseCommands(final File workingDirectory, fin
* @see #parseCommands(File, String[], Consumer, boolean)
*/
static ReportConfiguration createConfiguration(final ArgumentContext argumentContext) {
- argumentContext.processArgs();
+ argumentContext.processArgs(CLIOptionCollection.INSTANCE);
final ReportConfiguration configuration = argumentContext.getConfiguration();
final CommandLine commandLine = argumentContext.getCommandLine();
- if (Arg.DIR.isSelected()) {
+ if (CLIOptionCollection.INSTANCE.isSelected(Arg.DIR)) {
try {
- configuration.addSource(getReportable(commandLine.getParsedOptionValue(Arg.DIR.getSelected()), configuration));
+ configuration.addSource(getReportable(commandLine.getParsedOptionValue(
+ CLIOptionCollection.INSTANCE.getSelected(Arg.DIR).get()), configuration));
} catch (ParseException e) {
- throw new ConfigurationException("Unable to set parse " + Arg.DIR.getSelected(), e);
+ throw new ConfigurationException("Unable to set parse " + CLIOptionCollection.INSTANCE.getSelected(Arg.DIR).get(), e);
}
}
for (String s : commandLine.getArgs()) {
@@ -200,7 +200,7 @@ static ReportConfiguration createConfiguration(final ArgumentContext argumentCon
* @return the Options comprised of the Options defined in this class.
*/
public static Options buildOptions() {
- return Arg.getOptions().addOption(HELP);
+ return CLIOptionCollection.INSTANCE.getOptions();
}
/**
diff --git a/apache-rat-core/src/main/java/org/apache/rat/OptionCollectionParser.java b/apache-rat-core/src/main/java/org/apache/rat/OptionCollectionParser.java
new file mode 100644
index 000000000..5798b7385
--- /dev/null
+++ b/apache-rat-core/src/main/java/org/apache/rat/OptionCollectionParser.java
@@ -0,0 +1,325 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ */
+package org.apache.rat;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Serial;
+import java.io.Serializable;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.rat.api.Document;
+import org.apache.rat.commandline.Arg;
+import org.apache.rat.commandline.ArgumentContext;
+import org.apache.rat.commandline.StyleSheets;
+import org.apache.rat.config.exclusion.StandardCollection;
+import org.apache.rat.document.DocumentName;
+import org.apache.rat.document.DocumentNameMatcher;
+import org.apache.rat.document.FileDocument;
+import org.apache.rat.help.Licenses;
+import org.apache.rat.license.LicenseSetFactory;
+import org.apache.rat.report.IReportable;
+import org.apache.rat.report.claim.ClaimStatistic;
+import org.apache.rat.ui.UIOptionCollection;
+import org.apache.rat.utils.DefaultLog;
+import org.apache.rat.utils.Log.Level;
+import org.apache.rat.walker.ArchiveWalker;
+import org.apache.rat.walker.DirectoryWalker;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+import static java.lang.String.format;
+
+/**
+ * Uses the AbstractOptionCollection to parse the command line options.
+ * contains utility methods to ReportConfiguration from the options and an array of arguments.
+ */
+@SuppressFBWarnings("EI_EXPOSE_REP2")
+public final class OptionCollectionParser {
+ /** The OptionCollection that we are working with */
+ private final UIOptionCollection> uiOptionCollection;
+
+ public OptionCollectionParser(final UIOptionCollection> optionCollection) {
+ this.uiOptionCollection = optionCollection;
+ }
+
+ /** The Option comparator to sort the help */
+ public static final Comparator
- * Each Arg contains an OptionGroup that contains the individual options that all resolve to the same option.
- * This allows us to deprecate options as we move forward in development.
+ * An enumeration of options that are recommended across all UIs. A UI may not implement some options if they are unsupportable
+ * within the UI.
+ * Each Arg contains:
+ *
+ *
An OptionGroup that contains the individual options that all resolve to the same option.
+ * This allows us to deprecate options as we move forward in development.
+ *
A {@code BiConsumer} that defines the process to configure the option in
+ * the {@code ArgumentContext.configuration}.
+ *
+ *
*/
public enum Arg {
-
///////////////////////// EDIT OPTIONS
/**
* Defines options to add copyright to files
@@ -79,7 +84,10 @@ public enum Arg {
.addOption(Option.builder().longOpt("edit-copyright").hasArg()
.desc("The copyright message to use in the license headers. Usually in the form of \"Copyright 2008 Foo\". "
+ "Only valid with --edit-license")
- .build())),
+ .build()),
+ (context, selected) -> {
+ throw new ImplementationException(String.format("'%s' should not be executed directly", selected));
+ }),
/**
* Causes file updates to overwrite existing files.
@@ -93,7 +101,11 @@ public enum Arg {
.addOption(Option.builder().longOpt("edit-overwrite")
.desc("Forces any changes in files to be written directly to the source files so that new files are not created. "
+ "Only valid with --edit-license.")
- .build())),
+ .build()),
+ (context, selected) -> {
+ throw new ImplementationException(String.format("'%s' should not be executed directly", selected));
+ }
+ ),
/**
* Defines options to add licenses to files
@@ -112,7 +124,11 @@ public enum Arg {
"Add the Apache-2.0 license header to any file with an unknown license that is not in the exclusion list. "
+ "By default new files will be created with the license header, "
+ "to force the modification of existing files use the --edit-overwrite option.").build()
- )),
+ ),
+ (context, selected) -> {
+ throw new ImplementationException(String.format("'%s' should not be executed directly", selected));
+ }
+ ),
//////////////////////////// CONFIGURATION OPTIONS
/**
@@ -129,7 +145,11 @@ public enum Arg {
.deprecated(DeprecatedAttributes.builder().setSince("0.17").setForRemoval(true).setDescription(StdMsgs.useMsg("--config")).get())
.converter(Converters.FILE_CONVERTER)
.type(File.class)
- .build())),
+ .build()),
+ (context, selected) -> {
+ throw new ImplementationException(String.format("'%s' should not be executed directly", selected));
+ }
+ ),
/**
* Group of options that skip the default configuration file
@@ -143,16 +163,22 @@ public enum Arg {
.setForRemoval(true)
.setDescription(StdMsgs.useMsg("--configuration-no-defaults")).get())
.desc("Ignore default configuration.")
- .build())),
+ .build()),
+ (context, selected) -> {
+ throw new ImplementationException(String.format("'%s' should not be executed directly", selected));
+ }),
/**
* Option that adds approved licenses to the list
*/
LICENSES_APPROVED(new OptionGroup().addOption(Option.builder().longOpt("licenses-approved").hasArg().argName("LicenseID")
.desc("A comma separated list of approved License IDs. These licenses will be added to the list of approved licenses.")
- .converter(Converters.TEXT_LIST_CONVERTER)
- .type(String[].class)
- .build())),
+ .converter(Converters.TEXT_LIST_CONVERTER)
+ .type(String[].class)
+ .build()),
+ (context, selected) ->
+ context.getConfiguration().addApprovedLicenseIds(processArrayArg(context, selected))
+ ),
/**
* Option that adds approved licenses from a file
@@ -161,7 +187,9 @@ public enum Arg {
.desc("Name of file containing comma separated lists of approved License IDs.")
.converter(Converters.FILE_CONVERTER)
.type(File.class)
- .build())),
+ .build()),
+ (context, selected) ->
+ context.getConfiguration().addApprovedLicenseIds(processArrayFile(context, selected))),
/**
* Option that specifies approved license families
@@ -170,7 +198,8 @@ public enum Arg {
.desc("A comma separated list of approved license family IDs. These license families will be added to the list of approved license families.")
.converter(Converters.TEXT_LIST_CONVERTER)
.type(String[].class)
- .build())),
+ .build()),
+ (context, selected) -> context.getConfiguration().addApprovedLicenseCategories(processArrayArg(context, selected))),
/**
* Option that specifies approved license families from a file
@@ -179,7 +208,9 @@ public enum Arg {
.desc("Name of file containing comma separated lists of approved family IDs.")
.converter(Converters.FILE_CONVERTER)
.type(File.class)
- .build())),
+ .build()),
+ (context, selected) -> context.getConfiguration().addApprovedLicenseCategories(processArrayFile(context, selected))
+ ),
/**
* Option to remove licenses from the approved list
@@ -190,7 +221,8 @@ public enum Arg {
"Once licenses are removed they can not be added back.")
.converter(Converters.TEXT_LIST_CONVERTER)
.type(String[].class)
- .build())),
+ .build()),
+ (context, selected) -> context.getConfiguration().removeApprovedLicenseIds(processArrayArg(context, selected))),
/**
* Option to read a file licenses to be removed from the approved list.
@@ -201,7 +233,8 @@ public enum Arg {
.desc("Name of file containing comma separated lists of the denied license IDs. " +
"These licenses will be removed from the list of approved licenses. " +
"Once licenses are removed they can not be added back.")
- .build())),
+ .build()),
+ (context, selected) -> context.getConfiguration().removeApprovedLicenseIds(processArrayFile(context, selected))),
/**
* Option to list license families to remove from the approved list.
@@ -213,7 +246,8 @@ public enum Arg {
"Once license families are removed they can not be added back.")
.converter(Converters.TEXT_LIST_CONVERTER)
.type(String[].class)
- .build())),
+ .build()),
+ (context, selected) -> context.getConfiguration().removeApprovedLicenseCategories(processArrayArg(context, selected))),
/**
* Option to read a list of license families to remove from the approved list.
@@ -224,7 +258,8 @@ public enum Arg {
"Once license families are removed they can not be added back.")
.type(File.class)
.converter(Converters.FILE_CONVERTER)
- .build())),
+ .build()),
+ (context, selected) -> context.getConfiguration().removeApprovedLicenseCategories(processArrayFile(context, selected))),
/**
* Option to specify an acceptable number of various counters.
@@ -233,7 +268,14 @@ public enum Arg {
.desc("The acceptable maximum number for the specified counter. A value of '-1' specifies an unlimited number.")
.converter(Converters.COUNTER_CONVERTER)
.type(Pair.class)
- .build())),
+ .build()),
+ (context, selected) -> {
+ for (String arg : context.getCommandLine().getOptionValues(selected)) {
+ Pair pair = Converters.COUNTER_CONVERTER.apply(arg);
+ int limit = pair.getValue();
+ context.getConfiguration().getClaimValidator().setMax(pair.getKey(), limit < 0 ? Integer.MAX_VALUE : limit);
+ }
+ }),
/**
* Option to specify an acceptable number of various counters.
@@ -242,7 +284,13 @@ public enum Arg {
.desc("The minimum number for the specified counter.")
.converter(Converters.COUNTER_CONVERTER)
.type(Pair.class)
- .build())),
+ .build()),
+ (context, selected) -> {
+ for (String arg : context.getCommandLine().getOptionValues(selected)) {
+ Pair pair = Converters.COUNTER_CONVERTER.apply(arg);
+ context.getConfiguration().getClaimValidator().setMin(pair.getKey(), pair.getValue());
+ }
+ }),
////////////////// INPUT OPTIONS
/**
@@ -256,7 +304,13 @@ public enum Arg {
"argument is located.")
.converter(Converters.FILE_CONVERTER)
.type(File.class)
- .build())),
+ .build()),
+ (context, selected) -> {
+ File[] files = getParsedOptionValues(selected, context.getCommandLine());
+ for (File f : files) {
+ context.getConfiguration().addSource(f);
+ }
+ }),
/**
* Excludes files by expression
@@ -269,7 +323,13 @@ public enum Arg {
.build())
.addOption(Option.builder().longOpt("input-exclude").hasArgs().argName("Expression")
.desc("Excludes files matching .")
- .build())),
+ .build()),
+ (context, selected) -> {
+ String[] excludes = context.getCommandLine().getOptionValues(selected);
+ if (excludes != null) {
+ context.getConfiguration().addExcludedPatterns(Arrays.asList(excludes));
+ }
+ }),
/**
* Excludes files based on the contents of a file.
@@ -286,7 +346,17 @@ public enum Arg {
.argName("File").hasArg().type(File.class)
.converter(Converters.FILE_CONVERTER)
.desc("Reads entries from a file. Entries will be excluded from processing.")
- .build())),
+ .build()),
+ (context, selected) -> {
+ try {
+ File excludeFileName = context.getCommandLine().getParsedOptionValue(selected);
+ if (excludeFileName != null) {
+ context.getConfiguration().addExcludedPatterns(ExclusionUtils.asIterable(excludeFileName, "#"));
+ }
+ } catch (Exception e) {
+ throw ConfigurationException.from(e);
+ }
+ }),
/**
* Excludes files based on standard groupings.
*/
@@ -296,8 +366,12 @@ public enum Arg {
.desc("Excludes files defined in standard collections based on commonly occurring groups. " +
"Excludes any path matcher actions but DOES NOT exclude any file processor actions.")
.type(StandardCollection.class)
- .build())
- ),
+ .build()),
+ (context, selected) -> {
+ for (String s : context.getCommandLine().getOptionValues(selected)) {
+ context.getConfiguration().addExcludedCollection(StandardCollection.valueOf(s));
+ }
+ }),
/**
* Excludes files if they are smaller than the given threshold.
@@ -306,8 +380,20 @@ public enum Arg {
.addOption(Option.builder().longOpt("input-exclude-size").argName("Integer")
.hasArg().type(Integer.class)
.desc("Excludes files with sizes less than the number of bytes specified.")
- .build())
- ),
+ .build()),
+ (context, selected) -> {
+ try {
+ final int maxSize = context.getCommandLine().getParsedOptionValue(selected);
+ DocumentNameMatcher matcher = new DocumentNameMatcher(String.format("File size < %s bytes", maxSize),
+ (Predicate) documentName -> {
+ File f = new File(documentName.getName());
+ return f.isFile() && f.length() < maxSize;
+ });
+ context.getConfiguration().addExcludedMatcher(matcher);
+ } catch (Exception e) {
+ throw ConfigurationException.from(e);
+ }
+ }),
/**
* Excludes files by expression.
*/
@@ -319,8 +405,13 @@ public enum Arg {
.desc("Includes files matching . Will override excluded files.")
.deprecated(DeprecatedAttributes.builder().setForRemoval(true).setSince("0.17")
.setDescription(StdMsgs.useMsg("--input-include")).get())
- .build())
- ),
+ .build()),
+ (context, selected) -> {
+ String[] includes = context.getCommandLine().getOptionValues(selected);
+ if (includes != null) {
+ context.getConfiguration().addIncludedPatterns(Arrays.asList(includes));
+ }
+ }),
/**
* Includes files based on the contents of a file.
@@ -337,7 +428,17 @@ public enum Arg {
.desc("Reads entries from a file. Entries will be excluded from processing.")
.deprecated(DeprecatedAttributes.builder().setForRemoval(true).setSince("0.17")
.setDescription(StdMsgs.useMsg("--input-include-file")).get())
- .build())),
+ .build()),
+ (context, selected) -> {
+ try {
+ File includeFileName = context.getCommandLine().getParsedOptionValue(selected);
+ if (includeFileName != null) {
+ context.getConfiguration().addIncludedPatterns(ExclusionUtils.asIterable(includeFileName, "#"));
+ }
+ } catch (Exception e) {
+ throw ConfigurationException.from(e);
+ }
+ }),
/**
* Includes files based on standard groups.
@@ -353,8 +454,17 @@ public enum Arg {
.desc("Scans hidden directories.")
.deprecated(DeprecatedAttributes.builder().setForRemoval(true).setSince("0.17")
.setDescription(StdMsgs.useMsg("--input-include-std with 'HIDDEN_DIR' argument")).get()).build()
- )
- ),
+ ),
+ (context, selected) -> {
+ // display deprecation log if needed.
+ if (context.getCommandLine().hasOption("scan-hidden-directories")) {
+ context.getConfiguration().addIncludedCollection(StandardCollection.HIDDEN_DIR);
+ } else {
+ for (String s : context.getCommandLine().getOptionValues(selected)) {
+ context.getConfiguration().addIncludedCollection(StandardCollection.valueOf(s));
+ }
+ }
+ }),
/**
* Excludes files based on SCM exclusion file processing.
@@ -366,17 +476,32 @@ public enum Arg {
.desc("Parse SCM based exclusion files to exclude specified files and directories. " +
"This action can apply to any standard collection that implements a file processor.")
.type(StandardCollection.class)
- .build())
- ),
+ .build()),
+ (context, selected) -> {
+ StandardCollection[] collections = getParsedOptionValues(selected, context.getCommandLine());
+ final ReportConfiguration configuration = context.getConfiguration();
+ for (StandardCollection collection : collections) {
+ if (collection == StandardCollection.ALL) {
+ Arrays.asList(StandardCollection.values()).forEach(configuration::addExcludedFileProcessor);
+ Arrays.asList(StandardCollection.values()).forEach(configuration::addExcludedCollection);
+ } else {
+ configuration.addExcludedFileProcessor(collection);
+ configuration.addExcludedCollection(collection);
+ }
+ }
+ }),
/**
* Stop processing an input stream and declare an input file.
*/
DIR(new OptionGroup().addOption(Option.builder().option("d").longOpt("dir").hasArg()
- .type(File.class)
+ .type(File.class)
.desc("Used to indicate end of list when using options that take multiple arguments.").argName("DirOrArchive")
.deprecated(DeprecatedAttributes.builder().setForRemoval(true).setSince("0.17")
- .setDescription("Use the standard '--' to signal the end of arguments.").get()).build())),
+ .setDescription("Use the standard '--' to signal the end of arguments.").get()).build()),
+ (context, selected) -> {
+ throw new ImplementationException(String.format("'%s' should not be executed directly", selected));
+ }),
/////////////// OUTPUT OPTIONS
/**
@@ -397,7 +522,22 @@ public enum Arg {
.setForRemoval(true)
.setDescription(StdMsgs.useMsg("--output-style with the 'xml' argument")).get())
.desc("forces XML output rather than the textual report.")
- .build())),
+ .build()),
+ (context, selected) -> {
+ String key = selected.getKey(); // is not null due to above isSelected()-call
+ if ("x".equals(key)) {
+ // display deprecated message.
+ context.getCommandLine().hasOption("x");
+ context.getConfiguration().setStyleSheet(StyleSheets.getStyleSheet("xml"));
+ } else {
+ String[] style = context.getCommandLine().getOptionValues(selected);
+ if (style.length != 1) {
+ DefaultLog.getInstance().error("Please specify a single stylesheet");
+ throw new ConfigurationException("Please specify a single stylesheet");
+ }
+ context.getConfiguration().setStyleSheet(StyleSheets.getStyleSheet(style[0]));
+ }
+ }),
/**
* Specifies the license definitions that should be included in the output.
@@ -411,7 +551,14 @@ public enum Arg {
.desc("List the defined licenses.")
.converter(s -> LicenseSetFactory.LicenseFilter.valueOf(s.toUpperCase()))
.deprecated(DeprecatedAttributes.builder().setSince("0.17").setForRemoval(true).setDescription(StdMsgs.useMsg("--output-licenses")).get())
- .build())),
+ .build()),
+ (context, selected) -> {
+ try {
+ context.getConfiguration().listLicenses(context.getCommandLine().getParsedOptionValue(selected));
+ } catch (ParseException e) {
+ context.logParseException(e, selected, Defaults.LIST_LICENSES);
+ }
+ }),
/**
* Specifies the license families that should be included in the output.
@@ -425,7 +572,14 @@ public enum Arg {
.desc("List the defined license families.")
.converter(s -> LicenseSetFactory.LicenseFilter.valueOf(s.toUpperCase()))
.deprecated(DeprecatedAttributes.builder().setSince("0.17").setForRemoval(true).setDescription(StdMsgs.useMsg("--output-families")).get())
- .build())),
+ .build()),
+ (context, selected) -> {
+ try {
+ context.getConfiguration().listFamilies(context.getCommandLine().getParsedOptionValue(selected));
+ } catch (ParseException e) {
+ context.logParseException(e, selected, Defaults.LIST_FAMILIES);
+ }
+ }),
/**
* Specifies the log level to log messages at.
@@ -434,14 +588,25 @@ public enum Arg {
.hasArg().argName("LogLevel")
.desc("Sets the log level.")
.converter(s -> Log.Level.valueOf(s.toUpperCase()))
- .build())),
+ .build()),
+ (context, selected) -> {
+ Log dLog = DefaultLog.getInstance();
+ try {
+ dLog.setLevel(context.getCommandLine().getParsedOptionValue(selected));
+ } catch (ParseException e) {
+ logParseException(DefaultLog.getInstance(), e, selected, context.getCommandLine(), dLog.getLevel());
+ }
+ }),
/**
* Specifies that the run should not perform any updates to files.
*/
DRY_RUN(new OptionGroup().addOption(Option.builder().longOpt("dry-run")
.desc("If set do not update the files but generate the reports.")
- .build())),
+ .build()),
+ (context, selected) ->
+ context.getConfiguration().setDryRun(true)
+ ),
/**
* Specifies where the output should be written.
@@ -457,7 +622,20 @@ public enum Arg {
.desc("Define the output file where to write a report to.")
.type(File.class)
.converter(Converters.FILE_CONVERTER)
- .build())),
+ .build()),
+ (context, selected) -> {
+ try {
+ File file = context.getCommandLine().getParsedOptionValue(selected);
+ File parent = file.getParentFile();
+ if (!parent.mkdirs() && !parent.isDirectory()) {
+ DefaultLog.getInstance().error("Could not create report parent directory " + file);
+ }
+ context.getConfiguration().setOut(file);
+ } catch (ParseException e) {
+ context.logParseException(e, selected, "System.out");
+ context.getConfiguration().setOut(() -> CloseShieldOutputStream.wrap(System.out));
+ }
+ }),
/**
* Specifies the level of reporting detail for archive files.
@@ -466,7 +644,15 @@ public enum Arg {
.addOption(Option.builder().longOpt("output-archive").hasArg().argName("ProcessingType")
.desc("Specifies the level of detail in ARCHIVE file reporting.")
.converter(s -> ReportConfiguration.Processing.valueOf(s.toUpperCase()))
- .build())),
+ .build()),
+ (context, selected) -> {
+ try {
+ context.getConfiguration().setArchiveProcessing(context.getCommandLine().getParsedOptionValue(selected));
+ } catch (ParseException e) {
+ context.logParseException(e, selected, Defaults.ARCHIVE_PROCESSING);
+ }
+ }
+ ),
/**
* Specifies the level of reporting detail for standard files.
@@ -475,51 +661,62 @@ public enum Arg {
.addOption(Option.builder().longOpt("output-standard").hasArg().argName("ProcessingType")
.desc("Specifies the level of detail in STANDARD file reporting.")
.converter(s -> ReportConfiguration.Processing.valueOf(s.toUpperCase()))
- .build())),
+ .build()),
+ (context, selected) -> {
+ try {
+ context.getConfiguration().setStandardProcessing(context.getCommandLine().getParsedOptionValue(selected));
+ } catch (ParseException e) {
+ context.logParseException(e, selected, Defaults.STANDARD_PROCESSING);
+ }
+ }),
/**
* Provide license definition listing of registered licenses.
*/
HELP_LICENSES(new OptionGroup()
.addOption(Option.builder().longOpt("help-licenses") //
- .desc("Print information about registered licenses.").build()));
+ .desc("Print information about registered licenses.").build()),
+ (context, selected) -> {
+ throw new ImplementationException(String.format("'%s' should not be executed directly", selected));
+ });
- /** The option group for the argument */
+ /**
+ * The option group for the argument
+ */
private final OptionGroup group;
+ /**
+ * The BiConsumer to apply the option to update the state of the context.configuration.
+ */
+ private final BiConsumer process;
+
/**
* Creates an Arg from an Option group.
*
* @param group The option group.
*/
- Arg(final OptionGroup group) {
+ Arg(final OptionGroup group, final BiConsumer process) {
this.group = group;
+ this.process = process;
}
/**
- * Determines if the group has a selected element.
- *
- * @return {@code true} if the group has a selected element.
+ * Executes the process associated with this Arg if the collection has an Option from this group selected.
+ * @param context the ArgumentContext that is being processed.
+ * @param optionCollection the OptionCollection that is available.
*/
- public boolean isSelected() {
- return group.getSelected() != null;
+ private void execute(final ArgumentContext context, final UIOptionCollection> optionCollection) {
+ optionCollection.getSelected(this)
+ .ifPresent(selected -> this.process.accept(context, selected));
}
/**
- * Gets the select element from the group.
+ * Determines if all the options have been removed from this argument.
*
- * @return the selected element or {@code null} if no element is selected.
- */
- public Option getSelected() {
- String s = group.getSelected();
- if (s != null) {
- for (Option result : group.getOptions()) {
- if (result.getKey().equals(s)) {
- return result;
- }
- }
- }
- return null;
+ * @return {@code true} if all the options have been removed from this argument.
+ */
+ public boolean isEmpty() {
+ return this.group().getOptions().isEmpty();
}
/**
@@ -538,14 +735,6 @@ public Option find(final String key) {
throw new IllegalArgumentException("Can not find " + key);
}
- /**
- * Gets the default value for this arg.
- * @return default value of this arg.
- */
- public String defaultValue() {
- return DEFAULT_VALUES.get(this);
- }
-
/**
* Gets the group for this arg.
*
@@ -558,20 +747,25 @@ public OptionGroup group() {
/**
* Returns the first non-deprecated option from the group.
*
- * @return the first non-deprecated option or {@code null} if no non-deprecated option is available.
+ * @return the first non-deprecated option or, if no non-deprecated option is available, the first option.
*/
public Option option() {
+ Option first = null;
for (Option result : group.getOptions()) {
+ if (first == null) {
+ first = result;
+ }
if (!result.isDeprecated()) {
return result;
}
}
- return null;
+ return first;
}
/**
* Gets the full set of options.
- * @return the full set of options for this Arg.
+ *
+ * @return the full set of options for this Arg.
*/
public static Options getOptions() {
Options options = new Options();
@@ -586,36 +780,56 @@ public static Options getOptions() {
*
* @param context the context to work with.
*/
- private static void processEditArgs(final ArgumentContext context) {
- if (EDIT_ADD.isSelected()) {
- context.getCommandLine().hasOption(Arg.EDIT_ADD.getSelected());
- boolean force = EDIT_OVERWRITE.isSelected();
+ private static void processEditArgs(final ArgumentContext context, final UIOptionCollection> optionCollection) {
+ optionCollection.getSelected(EDIT_ADD).ifPresent(option -> {
+ // prints deprecation
+ context.getCommandLine().hasOption(option);
+ boolean force = optionCollection.isSelected(EDIT_OVERWRITE);
if (force) {
- context.getCommandLine().hasOption(EDIT_OVERWRITE.getSelected());
+ // prints deprecation
+ optionCollection.getSelected(EDIT_OVERWRITE).ifPresent(context.getCommandLine()::hasOption);
}
context.getConfiguration().setAddLicenseHeaders(force ? AddLicenseHeaders.FORCED : AddLicenseHeaders.TRUE);
- if (EDIT_COPYRIGHT.isSelected()) {
- context.getConfiguration().setCopyrightMessage(context.getCommandLine().getOptionValue(EDIT_COPYRIGHT.getSelected()));
- }
- }
+ optionCollection.getSelected(EDIT_COPYRIGHT).
+ ifPresent(editOption -> context.getConfiguration().setCopyrightMessage(context.getCommandLine().getOptionValue(editOption)));
+ });
}
- private static List processArrayArg(final ArgumentContext context, final Arg arg) throws ParseException {
- String[] ids = context.getCommandLine().getParsedOptionValue(arg.getSelected());
- return Arrays.asList(ids);
+ /**
+ * Gets the list of Strings that are arguments for the option.
+ * @param context the ArgumentContext containing the command line.
+ * @param selected the selected option.
+ * @return the list of Strings that are aguments.
+ */
+ private static List processArrayArg(final ArgumentContext context, final Option selected) {
+ try {
+ return Arrays.asList(context.getCommandLine().getParsedOptionValue(selected));
+ } catch (ParseException e) {
+ throw new ConfigurationException(e);
+ }
}
- private static List processArrayFile(final ArgumentContext context, final Arg arg) throws ParseException {
+ /**
+ * parses lines with comma separated tokens from a file and returns the entire collection of tokens as a list of strings.
+ * @param context the Argument context that provides the command line.
+ * @param selected the selected option.
+ * @return the list of strings parsed from the file.
+ */
+ private static List processArrayFile(final ArgumentContext context, final Option selected) {
List result = new ArrayList<>();
- File file = context.getCommandLine().getParsedOptionValue(arg.getSelected());
- try (InputStream in = Files.newInputStream(file.toPath())) {
- for (String line : IOUtils.readLines(in, StandardCharsets.UTF_8)) {
- String[] ids = Converters.TEXT_LIST_CONVERTER.apply(line);
- result.addAll(Arrays.asList(ids));
+ try {
+ File file = context.getCommandLine().getParsedOptionValue(selected);
+ try (InputStream in = Files.newInputStream(file.toPath())) {
+ for (String line : IOUtils.readLines(in, StandardCharsets.UTF_8)) {
+ String[] ids = Converters.TEXT_LIST_CONVERTER.apply(line);
+ result.addAll(Arrays.asList(ids));
+ }
+ return result;
+ } catch (IOException e) {
+ throw new ConfigurationException(e);
}
- return result;
- } catch (IOException e) {
- throw new ConfigurationException(e);
+ } catch (ParseException e) {
+ throw ConfigurationException.from(e);
}
}
@@ -625,64 +839,28 @@ private static List processArrayFile(final ArgumentContext context, fina
* @param context the context to process.
* @throws ConfigurationException if configuration files can not be read.
*/
- private static void processConfigurationArgs(final ArgumentContext context) throws ConfigurationException {
- try {
- Defaults.Builder defaultBuilder = Defaults.builder();
- if (CONFIGURATION.isSelected()) {
- File[] files = CONFIGURATION.getParsedOptionValues(context.getCommandLine());
- for (File file : files) {
- defaultBuilder.add(file);
- }
- }
- if (CONFIGURATION_NO_DEFAULTS.isSelected()) {
- // display deprecation log if needed.
- context.getCommandLine().hasOption(CONFIGURATION_NO_DEFAULTS.getSelected());
- defaultBuilder.noDefault();
- }
- context.getConfiguration().setFrom(defaultBuilder.build());
-
- if (FAMILIES_APPROVED.isSelected()) {
- context.getConfiguration().addApprovedLicenseCategories(processArrayArg(context, FAMILIES_APPROVED));
- }
- if (FAMILIES_APPROVED_FILE.isSelected()) {
- context.getConfiguration().addApprovedLicenseCategories(processArrayFile(context, FAMILIES_APPROVED_FILE));
- }
- if (FAMILIES_DENIED.isSelected()) {
- context.getConfiguration().removeApprovedLicenseCategories(processArrayArg(context, FAMILIES_DENIED));
- }
- if (FAMILIES_DENIED_FILE.isSelected()) {
- context.getConfiguration().removeApprovedLicenseCategories(processArrayFile(context, FAMILIES_DENIED_FILE));
- }
-
- if (LICENSES_APPROVED.isSelected()) {
- context.getConfiguration().addApprovedLicenseIds(processArrayArg(context, LICENSES_APPROVED));
- }
+ private static void processConfigurationArgs(final ArgumentContext context, final UIOptionCollection> optionCollection) throws ConfigurationException {
- if (LICENSES_APPROVED_FILE.isSelected()) {
- context.getConfiguration().addApprovedLicenseIds(processArrayFile(context, LICENSES_APPROVED_FILE));
- }
- if (LICENSES_DENIED.isSelected()) {
- context.getConfiguration().removeApprovedLicenseIds(processArrayArg(context, LICENSES_DENIED));
- }
+ Defaults.Builder defaultBuilder = Defaults.builder();
- if (LICENSES_DENIED_FILE.isSelected()) {
- context.getConfiguration().removeApprovedLicenseIds(processArrayFile(context, LICENSES_DENIED_FILE));
- }
- if (COUNTER_MAX.isSelected()) {
- for (String arg : context.getCommandLine().getOptionValues(COUNTER_MAX.getSelected())) {
- Pair pair = Converters.COUNTER_CONVERTER.apply(arg);
- int limit = pair.getValue();
- context.getConfiguration().getClaimValidator().setMax(pair.getKey(), limit < 0 ? Integer.MAX_VALUE : limit);
- }
- }
- if (COUNTER_MIN.isSelected()) {
- for (String arg : context.getCommandLine().getOptionValues(COUNTER_MIN.getSelected())) {
- Pair pair = Converters.COUNTER_CONVERTER.apply(arg);
- context.getConfiguration().getClaimValidator().setMin(pair.getKey(), pair.getValue());
- }
- }
- } catch (Exception e) {
- throw ConfigurationException.from(e);
+ optionCollection.getSelected(CONFIGURATION).ifPresent(
+ selected -> {
+ File[] files = getParsedOptionValues(selected, context.getCommandLine());
+ for (File file : files) {
+ defaultBuilder.add(file);
+ }
+ });
+ optionCollection.getSelected(CONFIGURATION_NO_DEFAULTS).ifPresent(selected -> {
+ // display deprecation log if needed.
+ context.getCommandLine().hasOption(selected);
+ defaultBuilder.noDefault();
+ });
+ context.getConfiguration().setFrom(defaultBuilder.build());
+
+ for (Arg arg : new Arg[]{FAMILIES_APPROVED, FAMILIES_APPROVED_FILE, FAMILIES_DENIED, FAMILIES_DENIED_FILE,
+ LICENSES_APPROVED, LICENSES_APPROVED_FILE, LICENSES_DENIED, LICENSES_DENIED_FILE,
+ COUNTER_MAX, COUNTER_MIN}) {
+ arg.execute(context, optionCollection);
}
}
@@ -692,91 +870,21 @@ private static void processConfigurationArgs(final ArgumentContext context) thro
* @param context the context to work in.
* @throws ConfigurationException if an exclude file can not be read.
*/
- private static void processInputArgs(final ArgumentContext context) throws ConfigurationException {
- try {
- if (SOURCE.isSelected()) {
- File[] files = SOURCE.getParsedOptionValues(context.getCommandLine());
- for (File f : files) {
- context.getConfiguration().addSource(f);
- }
- }
- // TODO when include/exclude processing is updated check calling methods to ensure that all specified
- // directories are handled in the list of directories.
- if (EXCLUDE.isSelected()) {
- String[] excludes = context.getCommandLine().getOptionValues(EXCLUDE.getSelected());
- if (excludes != null) {
- context.getConfiguration().addExcludedPatterns(Arrays.asList(excludes));
- }
- }
- if (EXCLUDE_FILE.isSelected()) {
- File excludeFileName = context.getCommandLine().getParsedOptionValue(EXCLUDE_FILE.getSelected());
- if (excludeFileName != null) {
- context.getConfiguration().addExcludedPatterns(ExclusionUtils.asIterable(excludeFileName, "#"));
- }
- }
- if (EXCLUDE_STD.isSelected()) {
- for (String s : context.getCommandLine().getOptionValues(EXCLUDE_STD.getSelected())) {
- context.getConfiguration().addExcludedCollection(StandardCollection.valueOf(s));
- }
- }
- if (EXCLUDE_PARSE_SCM.isSelected()) {
- StandardCollection[] collections = EXCLUDE_PARSE_SCM.getParsedOptionValues(context.getCommandLine());
- final ReportConfiguration configuration = context.getConfiguration();
- for (StandardCollection collection : collections) {
- if (collection == StandardCollection.ALL) {
- Arrays.asList(StandardCollection.values()).forEach(configuration::addExcludedFileProcessor);
- Arrays.asList(StandardCollection.values()).forEach(configuration::addExcludedCollection);
- } else {
- configuration.addExcludedFileProcessor(collection);
- configuration.addExcludedCollection(collection);
- }
- }
- }
- if (EXCLUDE_SIZE.isSelected()) {
- final int maxSize = EXCLUDE_SIZE.getParsedOptionValue(context.getCommandLine());
- DocumentNameMatcher matcher = new DocumentNameMatcher(String.format("File size < %s bytes", maxSize),
- (Predicate) documentName -> {
- File f = new File(documentName.getName());
- return f.isFile() && f.length() < maxSize;
- });
- context.getConfiguration().addExcludedMatcher(matcher);
- }
- if (INCLUDE.isSelected()) {
- String[] includes = context.getCommandLine().getOptionValues(INCLUDE.getSelected());
- if (includes != null) {
- context.getConfiguration().addIncludedPatterns(Arrays.asList(includes));
- }
- }
- if (INCLUDE_FILE.isSelected()) {
- File includeFileName = context.getCommandLine().getParsedOptionValue(INCLUDE_FILE.getSelected());
- if (includeFileName != null) {
- context.getConfiguration().addIncludedPatterns(ExclusionUtils.asIterable(includeFileName, "#"));
- }
- }
- if (INCLUDE_STD.isSelected()) {
- Option selected = INCLUDE_STD.getSelected();
- // display deprecation log if needed.
- if (context.getCommandLine().hasOption("scan-hidden-directories")) {
- context.getConfiguration().addIncludedCollection(StandardCollection.HIDDEN_DIR);
- } else {
- for (String s : context.getCommandLine().getOptionValues(selected)) {
- context.getConfiguration().addIncludedCollection(StandardCollection.valueOf(s));
- }
- }
- }
- } catch (Exception e) {
- throw ConfigurationException.from(e);
+ private static void processInputArgs(final ArgumentContext context, final UIOptionCollection> optionCollection) throws ConfigurationException {
+ for (Arg arg : new Arg[]{SOURCE, EXCLUDE, EXCLUDE_FILE, EXCLUDE_STD, EXCLUDE_PARSE_SCM, EXCLUDE_SIZE,
+ INCLUDE, INCLUDE_FILE, INCLUDE_STD}) {
+ arg.execute(context, optionCollection);
}
}
/**
* Logs a ParseException as a warning.
*
- * @param log the Log to write to
+ * @param log the Log to write to
* @param exception the parse exception to log
- * @param opt the option being processed
- * @param cl the command line being processed
- * @param defaultValue The default value the option is being set to.
+ * @param opt the option being processed
+ * @param cl the command line being processed
+ * @param defaultValue The default value the option is being set to.
*/
private static void logParseException(final Log log, final ParseException exception, final Option opt, final CommandLine cl, final Object defaultValue) {
log.warn(format("Invalid %s specified: %s ", opt.getOpt(), cl.getOptionValue(opt)));
@@ -787,17 +895,10 @@ private static void logParseException(final Log log, final ParseException except
/**
* Process the log level setting.
*
- * @param commandLine The command line to process.
+ * @param context The argument context
*/
- public static void processLogLevel(final CommandLine commandLine) {
- if (LOG_LEVEL.getSelected() != null) {
- Log dLog = DefaultLog.getInstance();
- try {
- dLog.setLevel(commandLine.getParsedOptionValue(LOG_LEVEL.getSelected()));
- } catch (ParseException e) {
- logParseException(DefaultLog.getInstance(), e, LOG_LEVEL.getSelected(), commandLine, dLog.getLevel());
- }
- }
+ public static void processLogLevel(final ArgumentContext context, final UIOptionCollection> optionCollection) throws ConfigurationException {
+ LOG_LEVEL.execute(context, optionCollection);
}
/**
@@ -806,12 +907,12 @@ public static void processLogLevel(final CommandLine commandLine) {
* @param context the context in which to process the args.
* @throws ConfigurationException on error
*/
- public static void processArgs(final ArgumentContext context) throws ConfigurationException {
+ public static void processArgs(final ArgumentContext context, final UIOptionCollection> optionCollection) throws ConfigurationException {
Converters.FILE_CONVERTER.setWorkingDirectory(context.getWorkingDirectory());
- processOutputArgs(context);
- processEditArgs(context);
- processInputArgs(context);
- processConfigurationArgs(context);
+ processOutputArgs(context, optionCollection);
+ processEditArgs(context, optionCollection);
+ processInputArgs(context, optionCollection);
+ processConfigurationArgs(context, optionCollection);
}
/**
@@ -819,69 +920,9 @@ public static void processArgs(final ArgumentContext context) throws Configurati
*
* @param context the context in which to process the args.
*/
- private static void processOutputArgs(final ArgumentContext context) {
- context.getConfiguration().setDryRun(DRY_RUN.isSelected());
-
- if (OUTPUT_FAMILIES.isSelected()) {
- try {
- context.getConfiguration().listFamilies(context.getCommandLine().getParsedOptionValue(OUTPUT_FAMILIES.getSelected()));
- } catch (ParseException e) {
- context.logParseException(e, OUTPUT_FAMILIES.getSelected(), Defaults.LIST_FAMILIES);
- }
- }
-
- if (OUTPUT_LICENSES.isSelected()) {
- try {
- context.getConfiguration().listLicenses(context.getCommandLine().getParsedOptionValue(OUTPUT_LICENSES.getSelected()));
- } catch (ParseException e) {
- context.logParseException(e, OUTPUT_LICENSES.getSelected(), Defaults.LIST_LICENSES);
- }
- }
-
- if (OUTPUT_ARCHIVE.isSelected()) {
- try {
- context.getConfiguration().setArchiveProcessing(context.getCommandLine().getParsedOptionValue(OUTPUT_ARCHIVE.getSelected()));
- } catch (ParseException e) {
- context.logParseException(e, OUTPUT_ARCHIVE.getSelected(), Defaults.ARCHIVE_PROCESSING);
- }
- }
-
- if (OUTPUT_STANDARD.isSelected()) {
- try {
- context.getConfiguration().setStandardProcessing(context.getCommandLine().getParsedOptionValue(OUTPUT_STANDARD.getSelected()));
- } catch (ParseException e) {
- context.logParseException(e, OUTPUT_STANDARD.getSelected(), Defaults.STANDARD_PROCESSING);
- }
- }
-
- if (OUTPUT_FILE.isSelected()) {
- try {
- File file = context.getCommandLine().getParsedOptionValue(OUTPUT_FILE.getSelected());
- File parent = file.getParentFile();
- if (!parent.mkdirs() && !parent.isDirectory()) {
- DefaultLog.getInstance().error("Could not create report parent directory " + file);
- }
- context.getConfiguration().setOut(file);
- } catch (ParseException e) {
- context.logParseException(e, OUTPUT_FILE.getSelected(), "System.out");
- context.getConfiguration().setOut((IOSupplier) null);
- }
- }
-
- if (OUTPUT_STYLE.isSelected()) {
- String selected = OUTPUT_STYLE.getSelected().getKey(); // is not null due to above isSelected()-call
- if ("x".equals(selected)) {
- // display deprecated message.
- context.getCommandLine().hasOption("x");
- context.getConfiguration().setStyleSheet(StyleSheets.getStyleSheet("xml"));
- } else {
- String[] style = context.getCommandLine().getOptionValues(OUTPUT_STYLE.getSelected());
- if (style.length != 1) {
- DefaultLog.getInstance().error("Please specify a single stylesheet");
- throw new ConfigurationException("Please specify a single stylesheet");
- }
- context.getConfiguration().setStyleSheet(StyleSheets.getStyleSheet(style[0]));
- }
+ private static void processOutputArgs(final ArgumentContext context, final UIOptionCollection> optionCollection) throws ConfigurationException {
+ for (Arg arg : new Arg[]{DRY_RUN, OUTPUT_FAMILIES, OUTPUT_LICENSES, OUTPUT_ARCHIVE, OUTPUT_STANDARD, OUTPUT_FILE, OUTPUT_STYLE}) {
+ arg.execute(context, optionCollection);
}
}
@@ -898,27 +939,9 @@ public static void reset() {
}
}
- /**
- * Finds the Arg that an Option is in.
- *
- * @param optionToFind the Option to locate.
- * @return The Arg or {@code null} if no Arg is found.
- */
- public static Arg findArg(final Option optionToFind) {
- if (optionToFind != null) {
- for (Arg arg : Arg.values()) {
- for (Option candidate : arg.group.getOptions()) {
- if (optionToFind.equals(candidate)) {
- return arg;
- }
- }
- }
- }
- return null;
- }
-
/**
* Finds the Arg that contains an Option with the specified key.
+ *
* @param key the key for the Option to locate.
* @return The Arg or {@code null} if no Arg is found.
*/
@@ -935,31 +958,18 @@ public static Arg findArg(final String key) {
return null;
}
- private T getParsedOptionValue(final CommandLine commandLine) throws ParseException {
- return commandLine.getParsedOptionValue(this.getSelected());
- }
-
- private String getOptionValue(final CommandLine commandLine) {
- return commandLine.getOptionValue(this.getSelected());
- }
-
- private String[] getOptionValues(final CommandLine commandLine) {
- return commandLine.getOptionValues(this.getSelected());
- }
-
- private T[] getParsedOptionValues(final CommandLine commandLine) {
- Option option = getSelected();
+ private static T[] getParsedOptionValues(final Option selected, final CommandLine commandLine) {
try {
- Class extends T> clazz = (Class extends T>) option.getType();
- String[] values = commandLine.getOptionValues(option);
+ Class extends T> clazz = (Class extends T>) selected.getType();
+ String[] values = commandLine.getOptionValues(selected);
T[] result = (T[]) Array.newInstance(clazz, values.length);
for (int i = 0; i < values.length; i++) {
- result[i] = clazz.cast(option.getConverter().apply(values[i]));
+ result[i] = clazz.cast(selected.getConverter().apply(values[i]));
}
return result;
} catch (Throwable t) {
- throw new ConfigurationException(format("'%s' converter for %s '%s' does not produce a class of type %s", this,
- option.getKey(), option.getConverter().getClass().getName(), option.getType()), t);
+ throw new ConfigurationException(format("'%s' converter for %s '%s' does not produce a class of type %s", selected,
+ selected.getKey(), selected.getConverter().getClass().getName(), selected.getType()), t);
}
}
@@ -981,18 +991,4 @@ public static String useMsg(final String name) {
return format("Use %s instead.", name);
}
}
-
- /**
- * The default values description map
- */
- private static final Map DEFAULT_VALUES = new HashMap<>();
-
- static {
- DEFAULT_VALUES.put(OUTPUT_FILE, "System.out");
- DEFAULT_VALUES.put(LOG_LEVEL, Log.Level.WARN.name());
- DEFAULT_VALUES.put(OUTPUT_ARCHIVE, Defaults.ARCHIVE_PROCESSING.name());
- DEFAULT_VALUES.put(OUTPUT_STANDARD, Defaults.STANDARD_PROCESSING.name());
- DEFAULT_VALUES.put(OUTPUT_LICENSES, Defaults.LIST_LICENSES.name());
- DEFAULT_VALUES.put(OUTPUT_FAMILIES, Defaults.LIST_FAMILIES.name());
- }
}
diff --git a/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java b/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java
index ea672bc8d..d4374a57b 100644
--- a/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java
+++ b/apache-rat-core/src/main/java/org/apache/rat/commandline/ArgumentContext.java
@@ -25,6 +25,7 @@
import org.apache.commons.cli.ParseException;
import org.apache.rat.ReportConfiguration;
import org.apache.rat.document.DocumentName;
+import org.apache.rat.ui.UIOptionCollection;
import org.apache.rat.utils.DefaultLog;
import static java.lang.String.format;
@@ -33,7 +34,7 @@
* Provides the context necessary to process various arguments.
* @since 0.17
*/
-public class ArgumentContext {
+public final class ArgumentContext {
/** The report configuration that is being built */
private final ReportConfiguration configuration;
/** The command line that is building the configuration */
@@ -65,8 +66,8 @@ public ArgumentContext(final File workingDirectory, final CommandLine commandLin
/**
* Process the arguments specified in this context.
*/
- public void processArgs() {
- Arg.processArgs(this);
+ public void processArgs(final UIOptionCollection> uiOptionCollection) {
+ Arg.processArgs(this, uiOptionCollection);
}
/**
diff --git a/apache-rat-core/src/main/java/org/apache/rat/help/AbstractHelp.java b/apache-rat-core/src/main/java/org/apache/rat/help/AbstractHelp.java
index eff2b49a8..e7a8e3363 100644
--- a/apache-rat-core/src/main/java/org/apache/rat/help/AbstractHelp.java
+++ b/apache-rat-core/src/main/java/org/apache/rat/help/AbstractHelp.java
@@ -30,9 +30,9 @@
import org.apache.commons.cli.Options;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.WordUtils;
+import org.apache.rat.CLIOptionCollection;
import org.apache.rat.OptionCollection;
import org.apache.rat.VersionInfo;
-import org.apache.rat.commandline.Arg;
import static java.lang.String.format;
@@ -185,8 +185,7 @@ protected StringBuffer renderOptions(final StringBuffer sb, final int width, fin
optBuf.append(END_OF_OPTION_MSG);
}
// check for default value
- Arg arg = Arg.findArg(option);
- String defaultValue = arg == null ? null : arg.defaultValue();
+ String defaultValue = CLIOptionCollection.INSTANCE.defaultValue(option);
if (defaultValue != null) {
optBuf.append(format(" (Default value = %s)", defaultValue));
}
diff --git a/apache-rat-core/src/main/java/org/apache/rat/ui/AbstractCodeGenerator.java b/apache-rat-core/src/main/java/org/apache/rat/ui/AbstractCodeGenerator.java
new file mode 100644
index 000000000..3eb5cdae7
--- /dev/null
+++ b/apache-rat-core/src/main/java/org/apache/rat/ui/AbstractCodeGenerator.java
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.rat.ui;
+
+import java.io.IOException;
+import java.util.function.Function;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.text.WordUtils;
+import org.apache.rat.DeprecationReporter;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.runtime.RuntimeConstants;
+
+import static java.lang.String.format;
+import static org.apache.rat.OptionCollectionParser.ArgumentType.NONE;
+
+/**
+ * Generates the ${code org.apache.rat.maven.AbstractMaven} source code.
+ * @param The concrete implementation of the AbstractOption.
+ */
+public abstract class AbstractCodeGenerator> {
+ /** The base source directory */
+ protected final String baseDirectory;
+ /** the velocity engine to generate files with */
+ protected final VelocityEngine velocityEngine;
+ /**
+ * private constructor.
+ * @param baseDirectory The base source directory.
+ */
+ protected AbstractCodeGenerator(final String baseDirectory) {
+ this.baseDirectory = baseDirectory;
+ velocityEngine = new VelocityEngine();
+ velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
+ velocityEngine.setProperty("classpath.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
+ velocityEngine.init();
+ }
+
+ /**
+ * Gets the options for the command line.
+ * @return the command line options.
+ */
+ private static Options getOptions() {
+ return new Options()
+ .addOption(Option.builder("h").longOpt("help").desc("Print this message").build())
+ .addOption(Option.builder("p").longOpt("path").required().hasArg().desc("The path to the base of the generated java code directory").build());
+ }
+
+
+ /**
+ * Executable entry point.
+ * @param args the arguments for the executable
+ * @throws IOException on IO error.
+ */
+ protected static void processArgs(final String syntax,
+ final Function> instance,
+ final String[] args)
+ throws IOException {
+ CommandLine commandLine = null;
+ try {
+ commandLine = DefaultParser.builder().setDeprecatedHandler(DeprecationReporter.getLogReporter())
+ .build().parse(getOptions(), args);
+ } catch (ParseException pe) {
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp(syntax, pe.getMessage(), getOptions(), "");
+ System.exit(1);
+ }
+
+ if (commandLine.hasOption("h")) {
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp(syntax, getOptions());
+ System.exit(0);
+ }
+ AbstractCodeGenerator> codeGenerator = instance.apply(commandLine.getOptionValue("p"));
+ codeGenerator.execute();
+ }
+
+ /**
+ * Executes the code generation.
+ * @throws IOException on IO error
+ */
+ protected abstract void execute() throws IOException;
+
+ /**
+ * Creates the description for a method.
+ * @param abstractOption the option generating the method.
+ * @return the description for the method in {@code AbstractMaven.java}.
+ */
+ protected final String createDesc(final T abstractOption) {
+ String desc = abstractOption.getDescription();
+ if (desc == null) {
+ throw new IllegalStateException(format("Description for %s may not be null", abstractOption.getName()));
+ }
+ if (!desc.contains(".")) {
+ throw new IllegalStateException(format("First sentence of description for %s must end with a '.'", abstractOption.getName()));
+ }
+ if (abstractOption.getArgType() != NONE) {
+ desc = format("%s Argument%s should be %s%s. (See Argument Types for clarification)", desc, abstractOption.hasArgs() ? "s" : "",
+ abstractOption.hasArgs() ? "" : "a ", abstractOption.getArgName());
+ }
+ return desc;
+ }
+
+ /**
+ * Gets the argument description for the method returned from ${link createMethodName}.
+ * @param abstractOption the maven option generating the method.
+ * @param desc the description of the argument.
+ * @return the argument description for the method in {@code AbstractMaven.java}.
+ */
+ protected String createArgDesc(final T abstractOption, final String desc) {
+ if (abstractOption.hasArg()) {
+ String argDesc = desc.substring(desc.indexOf(" ") + 1, desc.indexOf(".") + 1);
+ return WordUtils.capitalize(argDesc.substring(0, 1)) + argDesc.substring(1);
+ } else {
+ return "The state";
+ }
+ }
+
+ /**
+ * Gets method name for the option.
+ * @param abstractOption the maven option generating the method.
+ * @return the method name description for the method in {@code AbstractMaven.java}.
+ */
+ protected abstract String createMethodName(T abstractOption);
+
+ /**
+ * Gathers all method definitions into a single string.
+ * @return the definition of all the methods.
+ */
+ protected abstract String gatherMethods();
+}
diff --git a/apache-rat-core/src/main/java/org/apache/rat/ui/ArgumentTracker.java b/apache-rat-core/src/main/java/org/apache/rat/ui/ArgumentTracker.java
new file mode 100644
index 000000000..83d2b1911
--- /dev/null
+++ b/apache-rat-core/src/main/java/org/apache/rat/ui/ArgumentTracker.java
@@ -0,0 +1,249 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.rat.ui;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.BiConsumer;
+import java.util.stream.Collectors;
+
+import org.apache.commons.cli.Option;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.rat.DeprecationReporter;
+import org.apache.rat.commandline.Arg;
+import org.apache.rat.utils.CasedString;
+import org.apache.rat.utils.DefaultLog;
+import org.apache.rat.utils.Log;
+
+/**
+ * Tracks Arg values that are set and their values for conversion from native UI to
+ * Apache Commons command line values.
+ */
+public final class ArgumentTracker {
+
+ /**
+ * List of deprecated arguments and their deprecation notice.
+ */
+ private final Map deprecatedArgs = new HashMap<>();
+
+ /**
+ * A map of CLI-based arguments to values.
+ */
+ private final Map> args = new HashMap<>();
+
+ /**
+ * The arguments understood by the UI for the current report execution.
+ * @param optionCollection The AbstractOptionCollection for this UI.
+ */
+ public ArgumentTracker(final UIOptionCollection> optionCollection) {
+ for (UIOption> abstractOption : optionCollection.getMappedOptions().toList()) {
+ if (abstractOption.isDeprecated()) {
+ deprecatedArgs.put(abstractOption.getName(),
+ String.format("Use of deprecated option '%s'. %s", abstractOption.getName(), abstractOption.getDeprecated()));
+ }
+ }
+ }
+
+ /**
+ * Extract the core name from the option. This is the {@link Option#getLongOpt()} if defined, otherwise
+ * the {@link Option#getOpt()}.
+ * @param option the commons cli option.
+ * @return the common cli based name.
+ */
+ public static String extractKey(final Option option) {
+ return StringUtils.defaultIfBlank(option.getLongOpt(), option.getOpt());
+ }
+
+ /**
+ * Generates the CasedString for the specified option.
+ * @param option
+ * @return the CasedString in KEBAB format.
+ */
+ public static CasedString extractName(final Option option) {
+ return new CasedString(CasedString.StringCase.KEBAB, ArgumentTracker.extractKey(option));
+ }
+
+ /**
+ * Sets the deprecation report method in the Apache Commons CLI processes.
+ */
+ private void setDeprecationReporter() {
+ DeprecationReporter.setLogReporter(opt -> {
+ String msg = deprecatedArgs.get(extractKey(opt));
+ if (msg == null) {
+ DeprecationReporter.getDefault().accept(opt);
+ } else {
+ DefaultLog.getInstance().warn(msg);
+ }
+ });
+ }
+
+ /**
+ * Gets the list of arguments prepared for the CLI code to parse.
+ * @return the List of arguments for the CLI command line.
+ */
+ public List args() {
+ final List result = new ArrayList<>();
+ for (Map.Entry> entry : args.entrySet()) {
+ result.add("--" + entry.getKey());
+ result.addAll(entry.getValue().stream().filter(Objects::nonNull).collect(Collectors.toList()));
+ }
+ return result;
+ }
+
+ /**
+ * Applies the consumer to each arg and list in turn.
+ */
+ public void apply(final BiConsumer> consumer) {
+ args.forEach((key, value) -> consumer.accept(key, new ArrayList<>(value)));
+ }
+
+ /**
+ * Validate that the option is defined in Args and has not already been set.
+ * This check will verify tha only one of the keys in the group can be set.
+ * @param key the key to check
+ * @return true if the key may be set.
+ */
+ private boolean validateSet(final String key) {
+ final Arg arg = Arg.findArg(key);
+ if (arg != null) {
+ final Option opt = arg.find(key);
+ final Option main = arg.option();
+ if (opt.isDeprecated()) {
+ args.remove(extractKey(main));
+ // deprecated options must be explicitly set so let it go.
+ return true;
+ }
+ // non-deprecated options may have default so ignore it if another option has already been set.
+ for (Option o : arg.group().getOptions()) {
+ if (!o.equals(main)) {
+ if (args.containsKey(extractKey(o))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Set a key and value into the argument list.
+ * Replaces any existing value.
+ * @param key the key for the map.
+ * @param value the value to set.
+ */
+ public void setArg(final UIOption> key, final String value) {
+ setArg(key.keyValue(), value);
+ }
+
+ /**
+ * Set a key and value into the argument list.
+ * Replaces any existing value.
+ * @param trackerKey the key for the map.
+ * @param value the value to set.
+ */
+ public void setArg(final String trackerKey, final String value) {
+ if (value == null || StringUtils.isNotBlank(value)) {
+ if (validateSet(trackerKey)) {
+ Option ratOption = Arg.findArg(trackerKey).find(trackerKey);
+ if (ratOption.hasArg()) {
+ List values = new ArrayList<>();
+ if (DefaultLog.getInstance().isEnabled(Log.Level.DEBUG)) {
+ DefaultLog.getInstance().debug(String.format("Setting %s to '%s'", trackerKey, value));
+ }
+ values.add(value);
+ args.put(trackerKey, values);
+ } else {
+ DefaultLog.getInstance().warn(String.format("Key '%s' does not accept arguments.", trackerKey));
+ }
+ } else {
+ DefaultLog.getInstance().warn(String.format("Key '%s' is unknown", trackerKey));
+ }
+ }
+ }
+
+ /**
+ * Get the list of values for a key.
+ * @param key the key for the map.
+ * @return the list of values for the key or {@code null} if not set.
+ */
+ public Optional> getArg(final String key) {
+ return Optional.ofNullable(args.get(key));
+ }
+
+ /**
+ * Add values to the key in the argument list.
+ * empty values are ignored. If no non-empty values are present no change is made.
+ * If the key does not exist, adds it.
+ * @param option the option to add values for.
+ * @param value the array of values to set.
+ */
+ public void addArg(final UIOption> option, final String... value) {
+ addArg(option.keyValue(), value);
+ }
+
+ /**
+ * Add values to the key in the argument list.
+ * empty values are ignored. If no non-empty values are present no change is made.
+ * If the key does not exist, adds it.
+ * @param trackerKey the key add values for.
+ * @param value the array of values to set.
+ */
+ public void addArg(final String trackerKey, final String... value) {
+ List newValues = Arrays.stream(value).filter(StringUtils::isNotBlank).collect(Collectors.toList());
+ if (!newValues.isEmpty()) {
+ if (validateSet(trackerKey)) {
+ Option ratOption = Arg.findArg(trackerKey).find(trackerKey);
+ if (ratOption.hasArgs()) {
+ if (DefaultLog.getInstance().isEnabled(Log.Level.DEBUG)) {
+ DefaultLog.getInstance().debug(String.format("Adding [%s] to %s", String.join(", ", Arrays.asList(value)), trackerKey));
+ }
+ List values = args.computeIfAbsent(trackerKey, k -> new ArrayList<>());
+ values.addAll(newValues);
+ } else {
+ DefaultLog.getInstance().warn(String.format("Key '%s' does not accept %sarguments.", trackerKey,
+ ratOption.hasArg() ? "more that one " : ""));
+ }
+ } else {
+ DefaultLog.getInstance().warn(String.format("Key '%s' is unknown", trackerKey));
+ }
+ }
+ }
+
+ /**
+ * Remove a key from the argument list.
+ * @param option the option to remove the key for.
+ */
+ public void removeArg(final UIOption> option) {
+ args.remove(option.keyValue());
+ }
+
+ /**
+ * Remove a key from the argument list.
+ * @param trackerKey the key remove.
+ */
+ public void removeArg(final String trackerKey) {
+ args.remove(trackerKey);
+ }
+}
diff --git a/apache-rat-core/src/main/java/org/apache/rat/ui/UI.java b/apache-rat-core/src/main/java/org/apache/rat/ui/UI.java
new file mode 100644
index 000000000..db1df6a5e
--- /dev/null
+++ b/apache-rat-core/src/main/java/org/apache/rat/ui/UI.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.rat.ui;
+
+public interface UI> {
+ /**
+ * Gets the common name of this UI.
+ * @return the common name of this UI.
+ */
+ default String name() {
+ return getClass().getSimpleName();
+ }
+
+ /**
+ * Gets the OptionFactory configuration for this UI.
+ *
+ * @return the OptionFactory configuration for this UI.
+ */
+ UIOptionCollection getOptionCollection();
+}
diff --git a/apache-rat-tools/src/main/java/org/apache/rat/documentation/options/AbstractOption.java b/apache-rat-core/src/main/java/org/apache/rat/ui/UIOption.java
similarity index 74%
rename from apache-rat-tools/src/main/java/org/apache/rat/documentation/options/AbstractOption.java
rename to apache-rat-core/src/main/java/org/apache/rat/ui/UIOption.java
index 84335831c..8b0ea1855 100644
--- a/apache-rat-tools/src/main/java/org/apache/rat/documentation/options/AbstractOption.java
+++ b/apache-rat-core/src/main/java/org/apache/rat/ui/UIOption.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.rat.documentation.options;
+package org.apache.rat.ui;
import java.util.HashMap;
import java.util.Locale;
@@ -27,48 +27,57 @@
import org.apache.commons.cli.Option;
import org.apache.commons.lang3.StringUtils;
-import org.apache.rat.OptionCollection;
-import org.apache.rat.commandline.Arg;
+import org.apache.rat.OptionCollectionParser;
+import org.apache.rat.utils.CasedString;
import static java.lang.String.format;
/**
* Abstract class that provides the framework for UI-specific RAT options.
- * In this context UI option means an option expressed in the specific UI, such as:
- * @see AntOption
- * @see MavenOption
- * @see CLIOption
+ * In this context UI option means an option expressed in the specific UI.
+ * @param the concrete implementation of AbstractOption.
*/
-public abstract class AbstractOption {
+public abstract class UIOption> {
/** The pattern to match CLI options in text */
protected static final Pattern PATTERN = Pattern.compile("-(-[a-z0-9]+)+");
/** The actual UI-specific name for the option */
protected final Option option;
/** The name for the option */
- protected final String name;
+ protected final CasedString name;
/** The argument type for this option */
- protected final OptionCollection.ArgumentType argumentType;
+ protected final OptionCollectionParser.ArgumentType argumentType;
+ /** The AbstractOptionCollection associated with this AbstractOption */
+ protected final UIOptionCollection optionCollection;
/**
* Constructor.
*
* @param option The CLI option
- * @param name the UI-specific name for the option.
+ * @param name the UI-specific name for the option
*/
- AbstractOption(final Option option, final String name) {
+ protected > UIOption(final C optionCollection, final Option option, final CasedString name) {
+ this.optionCollection = optionCollection;
this.option = option;
this.name = name;
argumentType = option.hasArg() ?
- option.getArgName() == null ? OptionCollection.ArgumentType.ARG :
- OptionCollection.ArgumentType.valueOf(option.getArgName().toUpperCase(Locale.ROOT)) :
- OptionCollection.ArgumentType.NONE;
+ option.getArgName() == null ? OptionCollectionParser.ArgumentType.ARG :
+ OptionCollectionParser.ArgumentType.valueOf(option.getArgName().toUpperCase(Locale.ROOT)) :
+ OptionCollectionParser.ArgumentType.NONE;
+ }
+
+ /**
+ * Gets the AbstractOptionCollection that this option is a member of.
+ * @return the AbstractOptionCollection that this option is a member of.
+ */
+ public final > X getOptionCollection() {
+ return (X) optionCollection;
}
/**
* Gets the option this abstract option is wrapping.
* @return the original Option.
*/
- public Option getOption() {
+ public final Option getOption() {
return option;
}
@@ -76,9 +85,8 @@ public Option getOption() {
* Return default value.
* @return default value or {@code null} if no argument given.
*/
- public String getDefaultValue() {
- Arg arg = Arg.findArg(option);
- return arg == null ? null : arg.defaultValue();
+ public final String getDefaultValue() {
+ return optionCollection.defaultValue(option);
}
/**
@@ -94,14 +102,6 @@ public String getDefaultValue() {
*/
public abstract String getExample();
- /**
- * Gets this option's cleaned up name.
- * @return This option's cleaned up name.
- */
- public String cleanupName() {
- return cleanupName(option);
- }
-
/**
* Replaces CLI pattern options with implementation specific pattern options.
* @param str the string to clean.
@@ -115,8 +115,8 @@ public String cleanup(final String str) {
while (matcher.find()) {
String key = matcher.group();
String optKey = key.substring(2);
- Optional