Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add suppressFileExpansion property to @Argument. #125

Merged
merged 1 commit into from
Jan 26, 2018
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@
*/
boolean common() default false;

/**
* Suppress automatic expansion of files with names ending in recognized extensions
* ({@link CommandLineArgumentParser#COLLECTION_LIST_FILE_EXTENSIONS}) when such files are provided
* on the commandline for collection arguments.
* @return true if file expansion should be suppressed for this argument
*/
boolean suppressFileExpansion() default false;

/**
* Does this option have special treatment in the argument parsing system.
* Some examples are arguments_file and help, which have special behavior in the parser.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,13 @@ public final class CommandLineArgumentParser implements CommandLineParser {
public static final String COMMENT = "#";
public static final String POSITIONAL_ARGUMENTS_NAME = "Positional Argument";

// Extension for collection argument list files
static final String COLLECTION_LIST_FILE_EXTENSION = ".args";
/**
* Extensions recognized for collection argument file expansion.
*/
static final String COLLECTION_LIST_FILE_EXTENSIONS_LIST = ".list";
static final String COLLECTION_LIST_FILE_EXTENSIONS_ARGS = ".args";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that it might be better to add the class for configuration at this stage (see #95), because each of this changes is generating a breaking change. I think that the configuration is a breaking change but flexible enough to avoid the change of the collection file extension here and keep it only in GATK.

I will open a new PR with that solution to have a clean branch instead of an outdated PR that get lost because its purpose was changed.

Copy link
Collaborator Author

@cmnbroad cmnbroad Jan 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Taking #95 would require a major version bump (by semantic versioning, which I'd like to follow as much as possible), which we just did, and which I'd like to avoid until we can bundle in all other changes that are not BWC. This PR introduces only a minor change in runtime behavior (no source or binary incompatibility), and the runtime behavior change has a pretty easy workaround (to change the file extension being used).

Also, I think we've accumulated enough other feature requests that involve customization that we need an even more general mechanism than the config class as in #95. Instead, I think we should take this change as is, and implement the scheme outlined in (#127) is more sustainable in the long run.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds reasonable. Looking forward to the next version bump with #127 implemented (and maybe we can add the #68 (although it will require to clean up the branch, which is quite outdated).

static final Set<String> COLLECTION_LIST_FILE_EXTENSIONS = new HashSet<>(
Arrays.asList(COLLECTION_LIST_FILE_EXTENSIONS_LIST, COLLECTION_LIST_FILE_EXTENSIONS_ARGS));

private static final Logger logger = LogManager.getLogger();

Expand Down Expand Up @@ -630,7 +635,7 @@ private void setArgument(ArgumentDefinition argumentDefinition, List<String> val
final Collection c = (Collection) argumentDefinition.getFieldValue();
c.clear();
}
values = expandListFile(values);
values = expandListFile(argumentDefinition, values);
}

for (int i = 0; i < values.size(); i++) {
Expand Down Expand Up @@ -709,24 +714,34 @@ private void setArgument(ArgumentDefinition argumentDefinition, List<String> val
}

/**
* Expand any collection values that are ".list" argument files, and add them
* to the list of values for that argument.
* @param originalValues
* Expand any collection value that references a filename that ends in one of the accepted expansion
* extensions, and add the contents of the file to the list of values for that argument.
* @param argDef the ArgumentDefinition being populated
* @param originalValues list of original values provided on the command line
* @return a list containing the original entries in {@code originalValues}, with any
* values from list files expanded in place, preserving both the original list order and
* the file order
*/
private List<String> expandListFile(final List<String> originalValues) {
List<String> expandedValues = new ArrayList<>(originalValues.size());
for (String stringValue: originalValues) {
if (stringValue.endsWith(COLLECTION_LIST_FILE_EXTENSION)) {
expandedValues.addAll(loadCollectionListFile(stringValue));
}
else {
expandedValues.add(stringValue);
private List<String> expandListFile(final ArgumentDefinition argDef, final List<String> originalValues) {
if (!argDef.suppressFileExpansion) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this change (although I prefer to being able to change the extension in a per-argument basis), but the configuration sounds much better for the change of the extensions itself. Have a look to the clean PR (I will comment with the number once it is here).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New PR for config interface in #126

List<String> expandedValues = new ArrayList<>(originalValues.size());
for (final String stringValue: originalValues) {
if (COLLECTION_LIST_FILE_EXTENSIONS.stream().anyMatch(ext -> stringValue.endsWith(ext))) {
// If any value provided for this argument is an expansion file, expand it in place,
// but also preserve the original values for subsequent retrieval during command line
// display, since expansion files can result in very large post-expansion command lines
// (its harmless to update this multiple times).
expandedValues.addAll(loadCollectionListFile(stringValue));
argDef.preserveOriginalValueList(originalValues);
}
else {
expandedValues.add(stringValue);
}
}
return expandedValues;
} else {
return originalValues;
}
return expandedValues;
}

/**
Expand Down Expand Up @@ -1134,6 +1149,13 @@ public static class ArgumentDefinition {
final Double minRecommendedValue;
final boolean isHidden;
final boolean isAdvanced;
final boolean suppressFileExpansion;

// Override values to be used when displaying this argument as part of the command line. When argument
// file expansion is triggered, this is used to preserve the original values provided by the user so that
// these are displayed, rather than the expanded values, which may be large, and can consist of intermixed
// literal values and expansion file names.
private List<String> originalCommandLineValues;

public ArgumentDefinition(
final Field field,
Expand All @@ -1154,6 +1176,11 @@ public ArgumentDefinition(

this.mutuallyExclusive = new LinkedHashSet<>(Arrays.asList(annotation.mutex()));
this.controllingDescriptor = controllingDescriptor;
this.suppressFileExpansion = annotation.suppressFileExpansion();

if (suppressFileExpansion && !isCollection) {
throw new CommandLineException.CommandLineParserInternalException("Can only suppress file expansion for collection arguments");
}

Object tmpDefault = getFieldValue();
if (tmpDefault != null) {
Expand Down Expand Up @@ -1261,7 +1288,7 @@ public String getLongName(){
}

/**
* Comparator for sorting ArgumentDefinitions in alphabetical order b y longName
* Comparator for sorting ArgumentDefinitions in alphabetical order by longName
*/
public static Comparator<ArgumentDefinition> sortByLongName =
(argDef1, argDef2) -> String.CASE_INSENSITIVE_ORDER.compare(argDef1.getLongName(), argDef2.getLongName());
Expand All @@ -1270,7 +1297,6 @@ public String getLongName(){
* Helper for pretty printing this option.
* @param value A value this argument was given
* @return a string
*
*/
private String prettyNameValue(Object value) {
if (value != null) {
Expand All @@ -1288,23 +1314,32 @@ private String prettyNameValue(Object value) {
return "";
}

/**
* Provide an override value to be used when when displaying this field as part of a command line. This is
* used to record the original value provided by the user when file expansion was used.
* @param commandLineDisplayValue
*/
void preserveOriginalValueList(final List<String> commandLineDisplayValue) {
this.originalCommandLineValues = commandLineDisplayValue;
}

/**
* @return A string representation of this argument and it's value(s) which would be valid if copied and pasted
* back as a command line argument
*/
public String toCommandLineString(){
final Object value = getFieldValue();
if (this.isCollection){
Collection<?> collect = (Collection<?>)value;
Collection<?> collect = originalCommandLineValues == null ?
(Collection<?>)value :
originalCommandLineValues;
return collect.stream()
.map(this::prettyNameValue)
.collect(Collectors.joining(" "));

} else {
return prettyNameValue(value);
}
}

}

/**
Expand Down
Loading