8158402: jlink: should use regex for all pattern operations (--order-resources or --exclude-resources)
Reviewed-by: sundar, alanb
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java Thu Jun 09 11:39:42 2016 -0300
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java Thu Jun 09 11:39:42 2016 -0300
@@ -28,7 +28,9 @@
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
+import java.nio.file.FileSystem;
import java.nio.file.Files;
+import java.nio.file.PathMatcher;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
@@ -43,9 +45,10 @@
import static jdk.tools.jlink.internal.TaskHelper.JIMAGE_BUNDLE;
import jdk.tools.jlink.internal.TaskHelper.Option;
import jdk.tools.jlink.internal.TaskHelper.OptionsHelper;
+import jdk.tools.jlink.internal.Utils;
class JImageTask {
- static final Option<?>[] recognizedOptions = {
+ private static final Option<?>[] RECOGNIZED_OPTIONS = {
new Option<JImageTask>(true, (task, option, arg) -> {
task.options.directory = arg;
}, "--dir"),
@@ -70,15 +73,16 @@
task.options.version = true;
}, "--version")
};
- private static final TaskHelper taskHelper
+ private static final TaskHelper TASK_HELPER
= new TaskHelper(JIMAGE_BUNDLE);
- private static final OptionsHelper<JImageTask> optionsHelper
- = taskHelper.newOptionsHelper(JImageTask.class, recognizedOptions);
+ private static final OptionsHelper<JImageTask> OPTION_HELPER
+ = TASK_HELPER.newOptionsHelper(JImageTask.class, RECOGNIZED_OPTIONS);
private static final String PROGNAME = "jimage";
+ private static final FileSystem JRT_FILE_SYSTEM = Utils.jrtFileSystem();
private final OptionsValues options;
private final List<Predicate<String>> filterPredicates;
- private PrintWriter log = null;
+ private PrintWriter log;
JImageTask() {
this.options = new OptionsValues();
@@ -88,7 +92,7 @@
void setLog(PrintWriter out) {
log = out;
- taskHelper.setLog(log);
+ TASK_HELPER.setLog(log);
}
static class OptionsValues {
@@ -160,32 +164,32 @@
}
if (args.length == 0) {
- log.println(taskHelper.getMessage("main.usage.summary", PROGNAME));
+ log.println(TASK_HELPER.getMessage("main.usage.summary", PROGNAME));
return EXIT_ABNORMAL;
}
try {
- List<String> unhandled = optionsHelper.handleOptions(this, args);
+ List<String> unhandled = OPTION_HELPER.handleOptions(this, args);
if(!unhandled.isEmpty()) {
try {
options.task = Enum.valueOf(Task.class, unhandled.get(0).toUpperCase());
} catch (IllegalArgumentException ex) {
- throw taskHelper.newBadArgs("err.not.a.task", unhandled.get(0));
+ throw TASK_HELPER.newBadArgs("err.not.a.task", unhandled.get(0));
}
for(int i = 1; i < unhandled.size(); i++) {
options.jimages.add(new File(unhandled.get(i)));
}
} else if (!options.help && !options.version && !options.fullVersion) {
- throw taskHelper.newBadArgs("err.invalid.task", "<unspecified>");
+ throw TASK_HELPER.newBadArgs("err.invalid.task", "<unspecified>");
}
if (options.help) {
if (unhandled.isEmpty()) {
- log.println(taskHelper.getMessage("main.usage", PROGNAME));
+ log.println(TASK_HELPER.getMessage("main.usage", PROGNAME));
- for (Option<?> o : recognizedOptions) {
+ for (Option<?> o : RECOGNIZED_OPTIONS) {
String name = o.aliases()[0];
if (name.startsWith("--")) {
@@ -194,21 +198,21 @@
name = name.substring(1);
}
- log.println(taskHelper.getMessage("main.opt." + name));
+ log.println(TASK_HELPER.getMessage("main.opt." + name));
}
} else {
try {
- log.println(taskHelper.getMessage("main.usage." +
+ log.println(TASK_HELPER.getMessage("main.usage." +
options.task.toString().toLowerCase()));
} catch (MissingResourceException ex) {
- throw taskHelper.newBadArgs("err.not.a.task", unhandled.get(0));
+ throw TASK_HELPER.newBadArgs("err.not.a.task", unhandled.get(0));
}
}
return EXIT_OK;
}
if (options.version || options.fullVersion) {
- taskHelper.showVersion(options.fullVersion);
+ TASK_HELPER.showVersion(options.fullVersion);
if (unhandled.isEmpty()) {
return EXIT_OK;
@@ -219,10 +223,10 @@
return run() ? EXIT_OK : EXIT_ERROR;
} catch (BadArgs e) {
- taskHelper.reportError(e.key, e.args);
+ TASK_HELPER.reportError(e.key, e.args);
if (e.showUsage) {
- log.println(taskHelper.getMessage("main.usage.summary", PROGNAME));
+ log.println(TASK_HELPER.getMessage("main.usage.summary", PROGNAME));
}
return EXIT_CMDERR;
@@ -241,25 +245,9 @@
}
for (String filter : filters.split(",")) {
- boolean endsWith = filter.startsWith("*");
- boolean startsWith = filter.endsWith("*");
- Predicate<String> function;
-
- if (startsWith && endsWith) {
- final String string = filter.substring(1, filter.length() - 1);
- function = (path) -> path.contains(string);
- } else if (startsWith) {
- final String string = filter.substring(0, filter.length() - 1);
- function = (path) -> path.startsWith(string);
- } else if (endsWith) {
- final String string = filter.substring(1);
- function = (path) -> path.endsWith(string);
- } else {
- final String string = filter;
- function = (path) -> path.equals(string);
- }
-
- filterPredicates.add(function);
+ final PathMatcher matcher = Utils.getPathMatcher(JRT_FILE_SYSTEM, filter);
+ Predicate<String> predicate = (path) -> matcher.matches(JRT_FILE_SYSTEM.getPath(path));
+ filterPredicates.add(predicate);
}
}
@@ -290,11 +278,11 @@
if (parent.exists()) {
if (!parent.isDirectory()) {
- throw taskHelper.newBadArgs("err.cannot.create.dir",
+ throw TASK_HELPER.newBadArgs("err.cannot.create.dir",
parent.getAbsolutePath());
}
} else if (!parent.mkdirs()) {
- throw taskHelper.newBadArgs("err.cannot.create.dir",
+ throw TASK_HELPER.newBadArgs("err.cannot.create.dir",
parent.getAbsolutePath());
}
@@ -382,12 +370,12 @@
ModuleAction moduleAction,
ResourceAction resourceAction) throws IOException, BadArgs {
if (options.jimages.isEmpty()) {
- throw taskHelper.newBadArgs("err.no.jimage");
+ throw TASK_HELPER.newBadArgs("err.no.jimage");
}
for (File file : options.jimages) {
if (!file.exists() || !file.isFile()) {
- throw taskHelper.newBadArgs("err.not.a.jimage", file.getName());
+ throw TASK_HELPER.newBadArgs("err.not.a.jimage", file.getName());
}
try (BasicImageReader reader = BasicImageReader.open(file.toPath())) {
@@ -451,7 +439,7 @@
iterate(this::listTitle, null, this::verify);
break;
default:
- throw taskHelper.newBadArgs("err.invalid.task",
+ throw TASK_HELPER.newBadArgs("err.invalid.task",
options.task.name()).showUsage(true);
}
return true;
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Utils.java Thu Jun 09 11:39:42 2016 -0300
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Utils.java Thu Jun 09 11:39:42 2016 -0300
@@ -25,6 +25,10 @@
package jdk.tools.jlink.internal;
import java.lang.reflect.Module;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.PathMatcher;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
@@ -155,4 +159,20 @@
public static boolean isBuiltin(Plugin prov) {
return THIS_MODULE.equals(prov.getClass().getModule());
}
+
+ public static FileSystem jrtFileSystem() {
+ return FileSystems.getFileSystem(URI.create("jrt:/"));
+ }
+
+ public static PathMatcher getPathMatcher(FileSystem fs, String pattern) {
+ if (!pattern.startsWith("glob:") && !pattern.startsWith("regex:")) {
+ pattern = "glob:" + pattern;
+ }
+
+ return fs.getPathMatcher(pattern);
+ }
+
+ public static PathMatcher getPathMatcher(String pattern) {
+ return getPathMatcher(jrtFileSystem(), pattern);
+ }
}
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/OrderResourcesPlugin.java Thu Jun 09 11:39:42 2016 -0300
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/OrderResourcesPlugin.java Thu Jun 09 11:39:42 2016 -0300
@@ -26,7 +26,9 @@
import java.io.File;
import java.io.IOException;
+import java.nio.file.FileSystem;
import java.nio.file.Files;
+import java.nio.file.PathMatcher;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -47,6 +49,8 @@
*/
public final class OrderResourcesPlugin implements TransformerPlugin {
public static final String NAME = "order-resources";
+ private static final FileSystem JRT_FILE_SYSTEM = Utils.jrtFileSystem();
+
private final List<ToIntFunction<String>> filters;
private final Map<String, Integer> orderedPaths;
@@ -187,27 +191,11 @@
}
}
} else {
- boolean endsWith = pattern.startsWith("*");
- boolean startsWith = pattern.endsWith("*");
- ToIntFunction<String> function;
final int result = ordinal++;
-
- if (startsWith && endsWith) {
- final String string = pattern.substring(1, pattern.length() - 1);
- function = (path)-> path.contains(string) ? result : Integer.MAX_VALUE;
- } else if (startsWith) {
- final String string = pattern.substring(0, pattern.length() - 1);
- function = (path)-> path.startsWith(string) ? result : Integer.MAX_VALUE;
- } else if (endsWith) {
- final String string = pattern.substring(1);
- function = (path)-> path.endsWith(string) ? result : Integer.MAX_VALUE;
- } else {
- final String string = pattern;
- function = (path)-> path.equals(string) ? result : Integer.MAX_VALUE;
- }
-
+ final PathMatcher matcher = Utils.getPathMatcher(JRT_FILE_SYSTEM, pattern);
+ ToIntFunction<String> function = (path)-> matcher.matches(JRT_FILE_SYSTEM.getPath(path)) ? result : Integer.MAX_VALUE;
filters.add(function);
- }
+ }
}
}
}
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ResourceFilter.java Thu Jun 09 11:39:42 2016 -0300
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ResourceFilter.java Thu Jun 09 11:39:42 2016 -0300
@@ -24,113 +24,71 @@
*/
package jdk.tools.jlink.internal.plugins;
-import java.io.BufferedReader;
import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
+import java.nio.file.FileSystem;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
+import jdk.tools.jlink.internal.Utils;
+import jdk.tools.jlink.plugin.PluginException;
/**
*
- * Filter in or out a resource
+ * Filter resource resources using path matcher.
*/
public class ResourceFilter implements Predicate<String> {
+ private static final FileSystem JRT_FILE_SYSTEM = Utils.jrtFileSystem();
- private final Pattern inPatterns;
- private final Pattern outPatterns;
-
- static final String NEG = "^";
+ final boolean negate;
+ final List<PathMatcher> matchers;
public ResourceFilter(String[] patterns) throws IOException {
this(patterns, false);
}
- public ResourceFilter(String[] patterns, boolean negateAll) throws IOException {
+ public ResourceFilter(String[] patterns, boolean negate) throws IOException {
+ this.negate = negate;
+ this.matchers = new ArrayList<>();
+
+ for (String pattern : patterns) {
+ if (pattern.startsWith("@")) {
+ File file = new File(pattern.substring(1));
+
+ if (file.exists()) {
+ List<String> lines;
+
+ try {
+ lines = Files.readAllLines(file.toPath());
+ } catch (IOException ex) {
+ throw new PluginException(ex);
+ }
- // Get the patterns from a file
- if (patterns != null && patterns.length == 1) {
- String filePath = patterns[0];
- File f = new File(filePath);
- if (f.exists()) {
- List<String> pats;
- try (FileInputStream fis = new FileInputStream(f);
- InputStreamReader ins = new InputStreamReader(fis,
- StandardCharsets.UTF_8);
- BufferedReader reader = new BufferedReader(ins)) {
- pats = reader.lines().collect(Collectors.toList());
+ for (String line : lines) {
+ PathMatcher matcher = Utils.getPathMatcher(JRT_FILE_SYSTEM, line);
+ matchers.add(matcher);
+ }
}
- patterns = new String[pats.size()];
- pats.toArray(patterns);
+ } else {
+ PathMatcher matcher = Utils.getPathMatcher(JRT_FILE_SYSTEM, pattern);
+ matchers.add(matcher);
+ }
+ }
+ }
+
+ @Override
+ public boolean test(String name) {
+ Path path = JRT_FILE_SYSTEM.getPath(name);
+
+ for (PathMatcher matcher : matchers) {
+ if (matcher.matches(path)) {
+ return !negate;
}
}
- if (patterns != null && negateAll) {
- String[] excluded = new String[patterns.length];
- for (int i = 0; i < patterns.length; i++) {
- excluded[i] = ResourceFilter.NEG + patterns[i];
- }
- patterns = excluded;
- }
-
- StringBuilder inPatternsBuilder = new StringBuilder();
- StringBuilder outPatternsBuilder = new StringBuilder();
- if (patterns != null) {
- for (int i = 0; i < patterns.length; i++) {
- String p = patterns[i];
- p = p.replaceAll(" ", "");
- StringBuilder builder = p.startsWith(NEG)
- ? outPatternsBuilder : inPatternsBuilder;
- String pat = p.startsWith(NEG) ? p.substring(NEG.length()) : p;
- builder.append(escape(pat));
- if (i < patterns.length - 1) {
- builder.append("|");
- }
- }
- }
- this.inPatterns = inPatternsBuilder.length() == 0 ? null
- : Pattern.compile(inPatternsBuilder.toString());
- this.outPatterns = outPatternsBuilder.length() == 0 ? null
- : Pattern.compile(outPatternsBuilder.toString());
- }
-
- public static String escape(String s) {
- s = s.replaceAll(" ", "");
- s = s.replaceAll("\\$", Matcher.quoteReplacement("\\$"));
- s = s.replaceAll("\\.", Matcher.quoteReplacement("\\."));
- s = s.replaceAll("\\*", ".+");
- return s;
- }
-
- private boolean accept(String path) {
- if (outPatterns != null) {
- Matcher mout = outPatterns.matcher(path);
- if (mout.matches()) {
- //System.out.println("Excluding file " + resource.getPath());
- return false;
- }
- }
- boolean accepted = false;
- // If the inPatterns is null, means that all resources are accepted.
- if (inPatterns == null) {
- accepted = true;
- } else {
- Matcher m = inPatterns.matcher(path);
- if (m.matches()) {
- //System.out.println("Including file " + resource.getPath());
- accepted = true;
- }
- }
- return accepted;
- }
-
- @Override
- public boolean test(String path) {
- return accept(path);
+ return negate;
}
}
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java Thu Jun 09 11:39:42 2016 -0300
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java Thu Jun 09 11:39:42 2016 -0300
@@ -1072,6 +1072,10 @@
@Override
public Pattern convert(String value) {
try {
+ if (value.startsWith("regex:")) {
+ value = value.substring("regex:".length()).trim();
+ }
+
return Pattern.compile(value);
} catch (PatternSyntaxException e) {
throw new CommandException("err.bad.pattern", value);
@@ -1083,10 +1087,15 @@
@Override public String valuePattern() { return "pattern"; }
}
- static class GlobConverter implements ValueConverter<PathMatcher> {
+ static class PathMatcherConverter implements ValueConverter<PathMatcher> {
@Override
public PathMatcher convert(String pattern) {
try {
+ if (!pattern.startsWith("glob:") &&
+ !pattern.startsWith("regex:")) {
+ pattern = "glob:" + pattern;
+ }
+
return FileSystems.getDefault()
.getPathMatcher("glob:" + pattern);
} catch (PatternSyntaxException e) {
@@ -1194,7 +1203,7 @@
OptionSpec<PathMatcher> excludes
= parser.accepts("exclude", getMessage("main.opt.exclude"))
.withRequiredArg()
- .withValuesConvertedBy(new GlobConverter());
+ .withValuesConvertedBy(new PathMatcherConverter());
OptionSpec<Pattern> hashModules
= parser.accepts("hash-modules", getMessage("main.opt.hash-modules"))