diff --git a/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/ArgumentsParser.java b/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/ArgumentsParser.java index 539b80877..f4986366b 100644 --- a/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/ArgumentsParser.java +++ b/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/ArgumentsParser.java @@ -71,7 +71,7 @@ List parse(String args) { return new ArrayList<>(arguments); } - private static void addArgument(StringBuilder argumentBuilder, List arguments) { + static void addArgument(StringBuilder argumentBuilder, List arguments) { if (argumentBuilder.length() > 0) { String argument = argumentBuilder.toString(); addArgument(argument, arguments); @@ -79,7 +79,7 @@ private static void addArgument(StringBuilder argumentBuilder, List argu } } - private static void addArgument(String argument, List arguments) { + static void addArgument(String argument, List arguments) { if (!arguments.contains(argument)) { arguments.add(argument); } diff --git a/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/YarnArgumentParser.java b/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/YarnArgumentParser.java new file mode 100644 index 000000000..815751899 --- /dev/null +++ b/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/YarnArgumentParser.java @@ -0,0 +1,74 @@ +package com.github.eirslett.maven.plugins.frontend.lib; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +class YarnArgumentsParser { + + private final List additionalArguments; + + YarnArgumentsParser() { + this(Collections.emptyList()); + } + + YarnArgumentsParser(List additionalArguments) { + this.additionalArguments = additionalArguments; + } + + /** + * Parses a given string of arguments, splitting it by characters that are whitespaces according to {@link Character#isWhitespace(char)}. + *

+ * This method respects quoted arguments. Meaning that whitespaces appearing phrases that are enclosed by an opening + * single or double quote and a closing single or double quote or the end of the string will not be considered. + *

+ * All characters excluding whitespaces considered for splitting stay in place. + *

+ * Examples: + * "foo bar" will be split to ["foo", "bar"] + * "foo \"bar foobar\"" will be split to ["foo", "\"bar foobar\""] + * "foo 'bar" will be split to ["foo", "'bar"] + * + * @param args a string of arguments + * @return an mutable copy of the list of all arguments + */ + List parse(String args) { + if (args == null || "null".equals(args) || args.isEmpty()) { + return Collections.emptyList(); + } + + final List arguments = new LinkedList<>(); + + for (String argument : this.additionalArguments) { + ArgumentsParser.addArgument(argument, arguments); + } + + final StringBuilder argumentBuilder = new StringBuilder(); + Character quote = null; + + for (int i = 0, l = args.length(); i < l; i++) { + char c = args.charAt(i); + + if (Character.isWhitespace(c) && quote == null) { + ArgumentsParser.addArgument(argumentBuilder, arguments); + continue; + } else if (c == '"' || c == '\'') { + // explicit boxing allows us to use object caching of the Character class + Character currentQuote = Character.valueOf(c); + if (quote == null) { + quote = currentQuote; + } else if (quote.equals(currentQuote)){ + quote = null; + } // else + // we ignore the case when a quoted argument contains the other kind of quote + } + + argumentBuilder.append(c); + } + + ArgumentsParser.addArgument(argumentBuilder, arguments); + + return new ArrayList<>(arguments); + } +} diff --git a/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/YarnTaskExecutor.java b/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/YarnTaskExecutor.java index 87d826a05..02a9327f0 100644 --- a/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/YarnTaskExecutor.java +++ b/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/YarnTaskExecutor.java @@ -20,7 +20,7 @@ abstract class YarnTaskExecutor { private final String taskName; - private final ArgumentsParser argumentsParser; + private final YarnArgumentsParser argumentsParser; private final YarnExecutorConfig config; @@ -42,7 +42,7 @@ public YarnTaskExecutor(YarnExecutorConfig config, String taskName, String taskL logger = LoggerFactory.getLogger(getClass()); this.config = config; this.taskName = taskName; - this.argumentsParser = new ArgumentsParser(additionalArguments); + this.argumentsParser = new YarnArgumentsParser(additionalArguments); } private static String getTaskNameFromLocation(String taskLocation) {