diff options
4 files changed, 57 insertions, 5 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ManifestMergerActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/ManifestMergerActionBuilder.java index 0f0c682ffb..1203a2faab 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/ManifestMergerActionBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/ManifestMergerActionBuilder.java @@ -140,7 +140,9 @@ public class ManifestMergerActionBuilder { // list-type and list-of-list-type flags that use such problematic separators in favor of // multi-value flags (to remove one level of listing) and by changing all list separators to a // platform-safe character (= comma). - this.spawnActionBuilder.alwaysUseParameterFile(ParameterFileType.UNQUOTED); + spawnActionBuilder.alwaysUseParameterFile(ParameterFileType.SHELL_QUOTED); + } else { + spawnActionBuilder.useParameterFile(ParameterFileType.SHELL_QUOTED); } ruleContext.registerAction( diff --git a/src/main/java/com/google/devtools/common/options/ParamsFilePreProcessor.java b/src/main/java/com/google/devtools/common/options/ParamsFilePreProcessor.java index 30b67ed55e..791265ae1b 100644 --- a/src/main/java/com/google/devtools/common/options/ParamsFilePreProcessor.java +++ b/src/main/java/com/google/devtools/common/options/ParamsFilePreProcessor.java @@ -68,7 +68,7 @@ public class ParamsFilePreProcessor implements ArgsPreProcessor { while (iterator.hasNext()) { char next = iterator.next(); if (Character.isWhitespace(next) && !iterator.isInQuote() && !iterator.isEscaped()) { - newArgs.add(arg.toString()); + newArgs.add(unescape(arg.toString())); arg = new StringBuilder(); } else { arg.append(next); @@ -92,6 +92,14 @@ public class ParamsFilePreProcessor implements ArgsPreProcessor { return args; } + private String unescape(String arg) { + if (arg.startsWith("'") && arg.endsWith("'")) { + String unescaped = arg.replace("'\\''", "'"); + return unescaped.substring(1, unescaped.length() - 1); + } + return arg; + } + // Doesn't implement iterator to avoid autoboxing and to throw exceptions. static class CharIterator { @@ -145,7 +153,7 @@ public class ParamsFilePreProcessor implements ArgsPreProcessor { throw new NoSuchElementException(); } char current = (char) reader.read(); - + // check for \r\n line endings. If found, drop the \r for normalized parsing. if (current == '\r' && peek() == '\n') { current = (char) reader.read(); diff --git a/src/test/java/com/google/devtools/common/options/OptionsParserTest.java b/src/test/java/com/google/devtools/common/options/OptionsParserTest.java index f8a0d5effe..726af7a5d6 100644 --- a/src/test/java/com/google/devtools/common/options/OptionsParserTest.java +++ b/src/test/java/com/google/devtools/common/options/OptionsParserTest.java @@ -397,6 +397,46 @@ public class OptionsParserTest { } @Test + public void parseWithParamsFileSingleQuotesUnescaping() + throws OptionsParsingException, IOException { + Path params = Files.createTempDirectory("foo").resolve("params"); + Files.write( + params, + ImmutableList.of("--foo", "'fuzzy '\\''foo'", "--bar", "17"), + StandardCharsets.UTF_8, + StandardOpenOption.CREATE); + + OptionsParser parser = newOptionsParser(ExampleFoo.class, ExampleBaz.class); + parser.enableParamsFileSupport(FileSystems.getDefault()); + parser.parse("@" + params); + ExampleFoo foo = parser.getOptions(ExampleFoo.class); + assertThat(foo.foo).isEqualTo("fuzzy 'foo"); + assertThat(foo.bar).isEqualTo(17); + ExampleBaz baz = parser.getOptions(ExampleBaz.class); + assertThat(baz.baz).isEqualTo("defaultBaz"); + } + + @Test + public void parseWithParamsFilePartiallyQuotedNoUnescaping() + throws OptionsParsingException, IOException { + Path params = Files.createTempDirectory("foo").resolve("params"); + Files.write( + params, + ImmutableList.of("--foo", "'fuzzy 'foo", "--bar", "17"), + StandardCharsets.UTF_8, + StandardOpenOption.CREATE); + + OptionsParser parser = newOptionsParser(ExampleFoo.class, ExampleBaz.class); + parser.enableParamsFileSupport(FileSystems.getDefault()); + parser.parse("@" + params); + ExampleFoo foo = parser.getOptions(ExampleFoo.class); + assertThat(foo.foo).isEqualTo("'fuzzy 'foo"); + assertThat(foo.bar).isEqualTo(17); + ExampleBaz baz = parser.getOptions(ExampleBaz.class); + assertThat(baz.baz).isEqualTo("defaultBaz"); + } + + @Test public void parseWithParamsFileUnmatchedQuote() throws IOException { Path params = Files.createTempDirectory("foo").resolve("params"); Files.write( @@ -445,7 +485,7 @@ public class OptionsParserTest { assertThat(foo.foo).isEqualTo("hello\\\nworld"); assertThat(foo.nodoc).isEqualTo("\"hello\nworld\""); ExampleBaz baz = parser.getOptions(ExampleBaz.class); - assertThat(baz.baz).isEqualTo("'hello\nworld'"); + assertThat(baz.baz).isEqualTo("hello\nworld"); } @Test @@ -463,7 +503,7 @@ public class OptionsParserTest { parser.enableParamsFileSupport(FileSystems.getDefault()); parser.parse("@" + params); ExampleBaz baz = parser.getOptions(ExampleBaz.class); - assertThat(baz.baz).isEqualTo("'hello\nworld'"); + assertThat(baz.baz).isEqualTo("hello\nworld"); ExampleFoo foo = parser.getOptions(ExampleFoo.class); assertThat(foo.foo).isEqualTo("hello\\\nworld"); assertThat(foo.nodoc).isEqualTo("\"hello\nworld\""); diff --git a/src/tools/android/java/com/google/devtools/build/android/ManifestMergerAction.java b/src/tools/android/java/com/google/devtools/build/android/ManifestMergerAction.java index 5f0681e8df..43ef880af8 100644 --- a/src/tools/android/java/com/google/devtools/build/android/ManifestMergerAction.java +++ b/src/tools/android/java/com/google/devtools/build/android/ManifestMergerAction.java @@ -29,6 +29,7 @@ import com.google.devtools.common.options.OptionEffectTag; import com.google.devtools.common.options.OptionsBase; import com.google.devtools.common.options.OptionsParser; import java.io.IOException; +import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; @@ -184,6 +185,7 @@ public class ManifestMergerAction { public static void main(String[] args) throws Exception { OptionsParser optionsParser = OptionsParser.newOptionsParser(Options.class); + optionsParser.enableParamsFileSupport(FileSystems.getDefault()); optionsParser.parseAndExitUponError(args); options = optionsParser.getOptions(Options.class); |