-
Notifications
You must be signed in to change notification settings - Fork 6
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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"; | ||
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(); | ||
|
||
|
@@ -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++) { | ||
|
@@ -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) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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). There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
} | ||
|
||
/** | ||
|
@@ -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, | ||
|
@@ -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) { | ||
|
@@ -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()); | ||
|
@@ -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) { | ||
|
@@ -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); | ||
} | ||
} | ||
|
||
} | ||
|
||
/** | ||
|
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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).