Skip to content

Commit

Permalink
Warn on file expansion for files with strings and leading . (#161)
Browse files Browse the repository at this point in the history
  • Loading branch information
cmnbroad authored Mar 9, 2020
1 parent 0abd84d commit 2441209
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.broadinstitute.barclay.utils.Utils;

import java.io.PrintStream;
import java.lang.reflect.*;
import java.util.*;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -88,12 +89,14 @@ public Object getArgumentValue() {
*
* @param commandLineArgumentParser the {@code CommandLineArgumentParser} managing this argument, used to resolve
* tag surrogates
* @param messageStream output stream where error messages should be written
* @param preprocessedValues the values to be used to populate the argument. these values may be tag surrogates
* created by the {@link TaggedArgumentParser} that must be resolved using {@link
* TaggedArgumentParser#getTaggedOptionForSurrogate(String)}.
*/
public abstract void setArgumentValues(
final CommandLineArgumentParser commandLineArgumentParser,
final PrintStream messageStream,
final List<String> preprocessedValues);

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ public boolean parseArguments(final PrintStream messageStream, String[] args) {
return parseArguments(messageStream, newArgs.toArray(new String[newArgs.size()]));
}
}
return propagateParsedValues(parsedArguments);
return propagateParsedValues(parsedArguments, messageStream);
}

/**
Expand Down Expand Up @@ -477,14 +477,15 @@ public String usage(final boolean printCommon, final boolean printHidden) {
return sb.toString();
}

private boolean propagateParsedValues(final OptionSet parsedArguments) {
private boolean propagateParsedValues(final OptionSet parsedArguments, final PrintStream messageStream) {
// named args first
for (final OptionSpec<?> optSpec : parsedArguments.asMap().keySet()) {
if (parsedArguments.has(optSpec)) {
final NamedArgumentDefinition namedArgumentDefinition = namedArgumentsDefinitionsByAlias.get(optSpec.options().get(0));
// Note that these values can be preprocessed tag surrogates
namedArgumentDefinition.setArgumentValues(
this,
messageStream,
optSpec.values(parsedArguments)
.stream()
.map(Object::toString)
Expand All @@ -503,7 +504,7 @@ private boolean propagateParsedValues(final OptionSet parsedArguments) {
"Positional arguments were provided '%s' but no positional argument is defined for this tool.",
stringValues.stream().collect(Collectors.joining("{", ",","}"))));
}
positionalArgumentDefinition.setArgumentValues(this, stringValues);
positionalArgumentDefinition.setArgumentValues(this, messageStream, stringValues);
}

validateArgumentValues();
Expand Down Expand Up @@ -625,6 +626,7 @@ private List<NamedArgumentDefinition> validatePluginArgumentValues() {
*/
public List<String> expandFromExpansionFile(
final ArgumentDefinition argumentDefinition,
final PrintStream messageStream,
final String stringValue,
final List<String> originalValuesForPreservation) {
List<String> expandedValues = new ArrayList<>();
Expand All @@ -633,7 +635,7 @@ public List<String> expandFromExpansionFile(
// but 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));
expandedValues.addAll(loadCollectionListFile(stringValue, messageStream));
argumentDefinition.setOriginalCommandLineValues(originalValuesForPreservation);
} else {
expandedValues.add(stringValue);
Expand All @@ -648,13 +650,25 @@ public List<String> expandFromExpansionFile(
* @param collectionListFile a text file containing list values
* @return false if a fatal error occurred
*/
private static List<String> loadCollectionListFile(final String collectionListFile) {
private static List<String> loadCollectionListFile(
final String collectionListFile,
final PrintStream messageStream) {
try (BufferedReader reader = new BufferedReader(new FileReader(collectionListFile))){
return reader.lines()
final List<String> filteredStrings = reader.lines()
.map(String::trim)
.filter(line -> !line.isEmpty())
.filter(line -> !line.startsWith(ARGUMENT_FILE_COMMENT))
.collect(Collectors.toList());
final List<String> suspiciousString = filteredStrings.stream().filter(s -> s.startsWith("@")).limit(1).collect(Collectors.toList());
if (!suspiciousString.isEmpty()) {
// looks suspiciously like a sequence dictionary...
messageStream.println(String.format(
"WARNING: the file %s has a file extension that causes it to be expanded by the argument parser into multiple argument values , " +
"but contains lines with leading '@' characters that may indicate this was unintentional (%s).",
collectionListFile,
suspiciousString));
}
return filteredStrings;
} catch (final IOException e) {
throw new CommandLineException("I/O error loading list file:" + collectionListFile, e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.apache.logging.log4j.Logger;
import org.broadinstitute.barclay.utils.Utils;

import java.io.PrintStream;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -283,12 +284,13 @@ public boolean isControlledByPlugin() {
@Override
public void setArgumentValues(
final CommandLineArgumentParser commandLineArgumentParser,
final PrintStream messageStream,
final List<String> preprocessedValues) // Note these might be tag surrogates
{
if (isCollection()) {
setCollectionValues(commandLineArgumentParser, preprocessedValues);
setCollectionValues(commandLineArgumentParser, messageStream, preprocessedValues);
} else {
setScalarValue(commandLineArgumentParser, preprocessedValues);
setScalarValue(commandLineArgumentParser, messageStream, preprocessedValues);
}
hasBeenSet = true;
}
Expand All @@ -298,6 +300,7 @@ public void setArgumentValues(
@SuppressWarnings({"rawtypes", "unchecked"})
private void setCollectionValues(
final CommandLineArgumentParser commandLineArgumentParser,
final PrintStream messageStream,
final List<String> preprocessedValues) // Note that some of these might be tag surrogates
{
final Collection c = (Collection) getArgumentValue();
Expand Down Expand Up @@ -330,6 +333,7 @@ private void setCollectionValues(
Collections.singletonList(normalizedSurrogatePair.getRight()) :
commandLineArgumentParser.expandFromExpansionFile(
this,
messageStream,
normalizedSurrogatePair.getRight(),
preprocessedValues);

Expand All @@ -350,6 +354,7 @@ private void setCollectionValues(
// one value, in which case we throw.
private void setScalarValue(
final CommandLineArgumentParser commandLineArgumentParser,
final PrintStream messageStream,
final List<String> originalValues) // Note that these might be tag surrogates
{
if (getHasBeenSet() || originalValues.size() > 1) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.broadinstitute.barclay.utils.Utils;

import java.io.PrintStream;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.List;
Expand Down Expand Up @@ -64,11 +65,16 @@ public String getCommandLineDisplayString() {
@SuppressWarnings("unchecked")
public void setArgumentValues(
final CommandLineArgumentParser commandLineArgumentParser,
final PrintStream messageStream,
final List<String> stringValues)
{
final List<String> expandedValues = stringValues
.stream()
.flatMap(s -> commandLineArgumentParser.expandFromExpansionFile(this, s, stringValues).stream())
.flatMap(s -> commandLineArgumentParser.expandFromExpansionFile(
this,
messageStream,
s,
stringValues).stream())
.collect(Collectors.toList());
for (final String stringValue : expandedValues) {
final Object value = constructFromString(stringValue, POSITIONAL_ARGUMENTS_NAME);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class PositionalArgumentsDefinitionUnitTest {
Expand All @@ -22,7 +21,7 @@ class MinElements {
final PositionalArgumentDefinition def =
new PositionalArgumentDefinition(field.getAnnotation(PositionalArguments.class), o, field);
final CommandLineArgumentParser clp = new CommandLineArgumentParser(o);
def.setArgumentValues(clp, Arrays.asList(new String[] { "arg1"}));
def.setArgumentValues(clp, System.out, Arrays.asList(new String[] { "arg1"}));

// we only validate minimum number of arguments on validation, after we've seen all of the values
def.validateValues(clp);
Expand All @@ -41,7 +40,7 @@ class MaxElements {
final CommandLineArgumentParser clp = new CommandLineArgumentParser(o);

// exceeding the maximum number of arguments is validated when args are added
def.setArgumentValues(clp, Arrays.asList(new String[] { "arg1", "arg2", "arg3"}));
def.setArgumentValues(clp, System.out, Arrays.asList(new String[] { "arg1", "arg2", "arg3"}));
}

@Test(expectedExceptions = CommandLineException.CommandLineParserInternalException.class)
Expand Down Expand Up @@ -85,7 +84,7 @@ class MinAndMaxElements {
final Field field = getFieldForFieldName(o, "stringArg");
final PositionalArgumentDefinition def =
new PositionalArgumentDefinition(field.getAnnotation(PositionalArguments.class), o, field);
def.setArgumentValues(new CommandLineArgumentParser(o), Arrays.asList(args));
def.setArgumentValues(new CommandLineArgumentParser(o), System.out, Arrays.asList(args));
Assert.assertEquals(def.getCommandLineDisplayString(), expecteDisplayString);
}

Expand Down

0 comments on commit 2441209

Please sign in to comment.