Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions apache-rat-core/src/main/java/org/apache/rat/CLIOption.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,21 @@
*/
package org.apache.rat;

import java.util.function.Function;

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;
import org.apache.rat.utils.CasedString;

/**
* The CLI option definition.
*/
public final class CLIOption extends UIOption<CLIOption> {

public CLIOption(final UIOptionCollection<CLIOption> collection, final Option option) {
super(collection, option, ArgumentTracker.extractName(option));
private CLIOption(final CLIBuilder builder) {
super(builder);
}

@Override
Expand Down Expand Up @@ -70,4 +72,20 @@ public String getExample() {
}
return sb.toString();
}

/**
* Builder for a CLI Option.
*/
public static class CLIBuilder extends UIOption.Builder<CLIOption, CLIBuilder> {

@Override
protected Function<Option, CasedString> getNameFactory() {
return ArgumentTracker::extractName;
}

@Override
protected CLIOption doBuild() {
return new CLIOption(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,23 @@
import org.apache.commons.cli.Option;
import org.apache.rat.ui.UIOptionCollection;

/**
* The collection of CLI Options.
*/
public final class CLIOptionCollection extends UIOptionCollection<CLIOption> {
/** 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() {
/**
* Constructs the CLIOption collection.
*/
public CLIOptionCollection() {
super(new Builder().uiOption(HELP));
}

private static final class Builder extends UIOptionCollection.Builder<CLIOption, Builder> {
private Builder() {
super(CLIOption::new);
super(CLIOption.CLIBuilder::new);
}
}
}
75 changes: 45 additions & 30 deletions apache-rat-core/src/main/java/org/apache/rat/OptionCollection.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
import org.apache.rat.license.LicenseSetFactory;
import org.apache.rat.report.Reportable;
import org.apache.rat.report.claim.ClaimStatistic;
import org.apache.rat.ui.ArgumentTracker;
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;
Expand All @@ -68,6 +70,11 @@ private OptionCollection() {
// do not instantiate
}

/**
* The collection of UI Options.
*/
private static UIOptionCollection baseOptionCollection = new CLIOptionCollection();

/**
* The Option comparator to sort the help.
*/
Expand Down Expand Up @@ -122,8 +129,8 @@ public static ReportConfiguration parseCommands(final File workingDirectory, fin
* Parses the standard options to create a ReportConfiguration.
* <p>
* This method is {@code synchronized} because it uses shared mutable state:
* the {@link Arg} enum's {@code OptionGroup} instances (whose {@code selected}
* field is mutated by {@link DefaultParser#parse}), and
* the {@link #baseOptionCollection}'s {@code OptionGroup} instances (whose {@code selected}
* field is mutated by {@link DefaultParser#parse(Options, String[])}), and
* {@link org.apache.rat.commandline.Converters#FILE_CONVERTER} (whose
* {@code workingDirectory} field is set during argument processing).
* Without synchronization, parallel Maven reactor threads (e.g. {@code mvn -T4})
Expand All @@ -140,29 +147,23 @@ public static ReportConfiguration parseCommands(final File workingDirectory, fin
*/
public static synchronized ReportConfiguration parseCommands(final File workingDirectory, final String[] args,
final Consumer<Options> helpCmd, final boolean noArgs) throws IOException {

Options opts = buildOptions();
CommandLine commandLine;
ArgumentContext argumentContext;
try {
commandLine = DefaultParser.builder().setDeprecatedHandler(DeprecationReporter.getLogReporter())
.setAllowPartialMatching(true).build().parse(opts, args);
argumentContext = new ArgumentContext(workingDirectory, opts, args);
} catch (ParseException e) {
DefaultLog.getInstance().error(e.getMessage());
DefaultLog.getInstance().error("Please use the \"--help\" option to see a list of valid commands and options.", e);
System.exit(1);
return null; // dummy return (won't be reached) to avoid Eclipse complaint about possible NPE
// for "commandLine"
}
Arg.processLogLevel(argumentContext, baseOptionCollection);

ArgumentContext argumentContext = new ArgumentContext(workingDirectory, commandLine);
Arg.processLogLevel(argumentContext, CLIOptionCollection.INSTANCE);

if (commandLine.hasOption(HELP)) {
if (argumentContext.getCommandLine().hasOption(HELP)) {
helpCmd.accept(opts);
return null;
}

if (commandLine.hasOption(Arg.HELP_LICENSES.option())) {
if (argumentContext.getCommandLine().hasOption(Arg.HELP_LICENSES.option())) {
new Licenses(createConfiguration(argumentContext), new PrintWriter(System.out, false, StandardCharsets.UTF_8)).printHelp();
return null;
}
Expand All @@ -188,25 +189,38 @@ public static synchronized ReportConfiguration parseCommands(final File workingD
* @see #parseCommands(File, String[], Consumer, boolean)
*/
public static ReportConfiguration createConfiguration(final ArgumentContext argumentContext) {
argumentContext.processArgs(CLIOptionCollection.INSTANCE);
final ReportConfiguration configuration = argumentContext.getConfiguration();
final CommandLine commandLine = argumentContext.getCommandLine();
Optional<Option> dirOpt = CLIOptionCollection.INSTANCE.getSelected(Arg.DIR);
if (dirOpt.isPresent()) {
try {
configuration.addSource(getReportable(commandLine.getParsedOptionValue(
dirOpt.get()), configuration));
} catch (ParseException e) {
throw new ConfigurationException("Unable to set parse " + dirOpt.get(), e);
try {
argumentContext.processArgs(baseOptionCollection);
final ReportConfiguration configuration = argumentContext.getConfiguration();
final CommandLine commandLine = argumentContext.getCommandLine();
Optional<Option> dirOpt = baseOptionCollection.getSelected(Arg.DIR);
dirOpt.ifPresent(opt -> {
try {
File directoryName = commandLine.getParsedOptionValue(opt);
configuration.addSource(getReportable(directoryName, configuration));
} catch (ParseException e) {
throw new ConfigurationException("Unable to set parse " + dirOpt.get(), e);
}
});
for (String s : commandLine.getArgs()) {
Reportable reportable = getReportable(new File(s), configuration);
if (reportable != null) {
configuration.addSource(reportable);
}
}
}
for (String s : commandLine.getArgs()) {
Reportable reportable = getReportable(new File(s), configuration);
if (reportable != null) {
configuration.addSource(reportable);
return configuration;
} catch (RuntimeException e) {
try (PrintWriter pw = new PrintWriter(DefaultLog.getInstance().asWriter(Level.ERROR))) {
pw.println("Unable to create Configuration: " + e.getMessage());
pw.println("=== Command line options ===");
for (Option opt : argumentContext.getCommandLine().getOptions()) {
String[] values = opt.getValues();
pw.printf(" %s: %s%n", ArgumentTracker.extractKey(opt), values == null ? "" : String.join(", ", values));
}
}
throw new ConfigurationException("Unable to create Configuration", e);
}
return configuration;

}

/**
Expand All @@ -215,7 +229,8 @@ public static ReportConfiguration createConfiguration(final ArgumentContext argu
* @return the Options comprised of the Options defined in this class.
*/
public static Options buildOptions() {
return CLIOptionCollection.INSTANCE.getOptions();
baseOptionCollection.resetSelected();
return baseOptionCollection.getOptions();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.lang3.StringUtils;
import org.apache.rat.api.RatException;
import org.apache.rat.commandline.Arg;
import org.apache.rat.commandline.ArgumentContext;
import org.apache.rat.help.Licenses;
import org.apache.rat.report.Reportable;
import org.apache.rat.ui.UIOption;
import org.apache.rat.ui.UIOptionCollection;
import org.apache.rat.utils.DefaultLog;

Expand All @@ -44,15 +46,21 @@
/**
* Uses the AbstractOptionCollection to parse the command line options.
* Contains utility methods to ReportConfiguration from the options and an array of arguments.
*
* @param <T> The UIOption type that this parser is handeling.
*/
@SuppressFBWarnings("EI_EXPOSE_REP2")
public final class OptionCollectionParser {
public final class OptionCollectionParser<T extends UIOption<T>> {
/**
* The OptionCollection that we are working with.
*/
private final UIOptionCollection<?> uiOptionCollection;
private final UIOptionCollection<T> uiOptionCollection;

public OptionCollectionParser(final UIOptionCollection<?> optionCollection) {
/**
* Constructor.
* @param optionCollection The option collection to use for
*/
public OptionCollectionParser(final UIOptionCollection<T> optionCollection) {
this.uiOptionCollection = optionCollection;
}

Expand All @@ -62,11 +70,10 @@ public OptionCollectionParser(final UIOptionCollection<?> optionCollection) {
* @param workingDirectory The directory to resolve relative file names against.
* @param args the arguments to parse
* @return the ArgumentContext for the process.
* @throws IOException on error.
* @throws ParseException on option parsing error.
* @throws RatException on error.
*/
public ArgumentContext parseCommands(final File workingDirectory, final String[] args)
throws IOException, ParseException {
throws RatException {
return parseCommands(workingDirectory, args, uiOptionCollection.getOptions());
}

Expand All @@ -77,8 +84,7 @@ public ArgumentContext parseCommands(final File workingDirectory, final String[]
* @return the CommandLine
* @throws ParseException on option parsing error.
*/
//@VisibleForTesting
CommandLine parseCommandLine(final Options opts, final String[] args) throws ParseException {
public static CommandLine parseCommandLine(final Options opts, final String[] args) throws ParseException {
try {
return DefaultParser.builder().setDeprecatedHandler(DeprecationReporter.getLogReporter())
.setAllowPartialMatching(true).build().parse(opts, args);
Expand All @@ -89,29 +95,39 @@ CommandLine parseCommandLine(final Options opts, final String[] args) throws Par
}
}

// visible for testing
void printHelp(final ArgumentContext argumentContext) throws RatException {
try {
new Licenses(argumentContext.getConfiguration(),
new PrintWriter(argumentContext.getConfiguration().getOutput().get(),
false, StandardCharsets.UTF_8)).printHelp();
} catch (IOException e) {
throw new RatException("Unable to print help: " + e.getMessage(), e);
}
}
/**
* Parses the standard options to create a ReportConfiguration.
*
* @param workingDirectory The directory to resolve relative file names against.
* @param args the arguments to parse.
* @param options An Options object containing Apache command line options.
* @return the ArgumentContext for the process.
* @throws IOException on error.
* @throws ParseException on option parsing error.
* @throws RatException on error.
*/
private ArgumentContext parseCommands(final File workingDirectory, final String[] args,
final Options options) throws IOException, ParseException {
CommandLine commandLine = parseCommandLine(options, args);
ArgumentContext argumentContext = new ArgumentContext(workingDirectory, commandLine);
Arg.processLogLevel(argumentContext, uiOptionCollection);
populateConfiguration(argumentContext);
if (uiOptionCollection.isSelected(Arg.HELP_LICENSES)) {
new Licenses(argumentContext.getConfiguration(),
new PrintWriter(argumentContext.getConfiguration().getOutput().get(),
false, StandardCharsets.UTF_8)).printHelp();
// visible for testing
ArgumentContext parseCommands(final File workingDirectory, final String[] args,
final Options options) throws RatException {
try {
ArgumentContext argumentContext = new ArgumentContext(workingDirectory, options, args);
Arg.processLogLevel(argumentContext, uiOptionCollection);
populateConfiguration(argumentContext);
if (uiOptionCollection.isSelected(Arg.HELP_LICENSES)) {
printHelp(argumentContext);
}
return argumentContext;
} catch (ParseException e) {
throw new RatException("Unable to parse command line: " + e.getMessage(), e);
}

return argumentContext;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -977,8 +977,8 @@ private static <T> T[] getParsedOptionValues(final Option selected, final Comman
try {
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++) {
T[] result = (T[]) Array.newInstance(clazz, values == null ? 0 : values.length);
for (int i = 0; i < result.length; i++) {
result[i] = clazz.cast(selected.getConverter().apply(values[i]));
}
return result;
Expand Down
Loading
Loading