--- old/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java 2017-03-22 17:16:28.000000000 -0700 +++ new/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java 2017-03-22 17:16:28.000000000 -0700 @@ -46,6 +46,7 @@ import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.Set; +import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.tools.jlink.internal.plugins.ExcludeJmodSectionPlugin; @@ -101,8 +102,15 @@ final boolean hidden; final String name; final String shortname; + final boolean terminalOption; - public Option(boolean hasArg, Processing processing, boolean hidden, String name, String shortname) { + public Option(boolean hasArg, + Processing processing, + boolean hidden, + String name, + String shortname, + boolean isTerminal) + { if (!name.startsWith("--")) { throw new RuntimeException("option name missing --, " + name); } @@ -115,24 +123,33 @@ this.hidden = hidden; this.name = name; this.shortname = shortname; + this.terminalOption = isTerminal; + } + + public Option(boolean hasArg, Processing processing, String name, String shortname, boolean isTerminal) { + this(hasArg, processing, false, name, shortname, isTerminal); } public Option(boolean hasArg, Processing processing, String name, String shortname) { - this(hasArg, processing, false, name, shortname); + this(hasArg, processing, false, name, shortname, false); } public Option(boolean hasArg, Processing processing, boolean hidden, String name) { - this(hasArg, processing, hidden, name, ""); + this(hasArg, processing, hidden, name, "", false); } public Option(boolean hasArg, Processing processing, String name) { - this(hasArg, processing, false, name, ""); + this(hasArg, processing, false, name, "", false); } public boolean isHidden() { return hidden; } + public boolean isTerminal() { + return terminalOption; + } + public boolean matches(String opt) { return opt.equals(name) || opt.equals(shortname) || @@ -179,12 +196,12 @@ private static class PluginOption extends Option { public PluginOption(boolean hasArg, Processing processing, boolean hidden, String name, String shortname) { - super(hasArg, processing, hidden, name, shortname); + super(hasArg, processing, hidden, name, shortname, false); } public PluginOption(boolean hasArg, Processing processing, boolean hidden, String name) { - super(hasArg, processing, hidden, name, ""); + super(hasArg, processing, hidden, name, "", false); } public String resourcePrefix() { @@ -498,21 +515,13 @@ return null; } - // used by jimage. Return unhandled arguments like "create", "describe". + /** + * Handles all options. This method stops processing the argument + * at the first non-option argument i.e. not starts with `-`, or + * at the first terminal option and returns the remaining arguments, + * if any. + */ public List handleOptions(T task, String[] args) throws BadArgs { - return handleOptions(task, args, true); - } - - // used by jlink. No unhandled arguments like "create", "describe". - void handleOptionsNoUnhandled(T task, String[] args) throws BadArgs { - handleOptions(task, args, false); - } - - // shared code that handles options for both jlink and jimage. jimage uses arguments like - // "create", "describe" etc. as "task names". Those arguments are unhandled here and returned - // as "unhandled arguments list". jlink does not want such arguments. "collectUnhandled" flag - // tells whether to allow for unhandled arguments or not. - private List handleOptions(T task, String[] args, boolean collectUnhandled) throws BadArgs { // findbugs warning, copy instead of keeping a reference. command = Arrays.copyOf(args, args.length); @@ -521,7 +530,6 @@ // Unit tests can call Task multiple time in same JVM. pluginOptions = new PluginsHelper(null); - List rest = collectUnhandled? new ArrayList<>() : null; // process options for (int i = 0; i < args.length; i++) { if (args[i].startsWith("-")) { @@ -531,7 +539,6 @@ if (option == null) { pluginOption = pluginOptions.getOption(name); if (pluginOption == null) { - throw new BadArgs("err.unknown.option", name). showUsage(true); } @@ -556,20 +563,23 @@ pluginOption.process(pluginOptions, name, param); } else { option.process(task, name, param); + if (option.isTerminal()) { + return ++i < args.length + ? Stream.of(Arrays.copyOfRange(args, i, args.length)) + .collect(Collectors.toList()) + : Collections.emptyList(); + + } } if (opt.ignoreRest()) { i = args.length; } } else { - if (collectUnhandled) { - rest.add(args[i]); - } else { - throw new BadArgs("err.orphan.argument", args[i]). - showUsage(true); - } + return Stream.of(Arrays.copyOfRange(args, i, args.length)) + .collect(Collectors.toList()); } } - return rest; + return Collections.emptyList(); } private Option getOption(String name) {