8159206: All jlink or jmod tests failing
Reviewed-by: alanb, mchung
This commit is contained in:
parent
c1c5618ddd
commit
f98b4f5aea
@ -45,7 +45,7 @@ final class JrtUtils {
|
||||
private static boolean isGlobMeta(char c) {
|
||||
return globMetaChars.indexOf(c) != -1;
|
||||
}
|
||||
private static final char EOL = 0; //TBD
|
||||
private static final char EOL = 0;
|
||||
private static char next(String glob, int i) {
|
||||
if (i < glob.length()) {
|
||||
return glob.charAt(i);
|
||||
|
@ -28,79 +28,87 @@ import java.lang.reflect.Module;
|
||||
import java.net.URI;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.PathMatcher;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import jdk.tools.jlink.plugin.Plugin;
|
||||
import jdk.tools.jlink.plugin.Plugin.Category;
|
||||
|
||||
public class Utils {
|
||||
|
||||
private Utils() {}
|
||||
|
||||
// jrt-fs file system
|
||||
private static FileSystem JRT_FILE_SYSTEM;
|
||||
|
||||
// current module
|
||||
private static final Module THIS_MODULE = Utils.class.getModule();
|
||||
|
||||
public static final Function<String, String[]> listParser = (argument) -> {
|
||||
String[] arguments = null;
|
||||
if (argument != null) {
|
||||
arguments = argument.split(",");
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
arguments[i] = arguments[i].trim();
|
||||
}
|
||||
}
|
||||
return arguments;
|
||||
};
|
||||
|
||||
public static boolean isPostProcessor(Plugin.Category category) {
|
||||
return category.equals(Plugin.Category.VERIFIER)
|
||||
|| category.equals(Plugin.Category.PROCESSOR)
|
||||
|| category.equals(Plugin.Category.PACKAGER);
|
||||
public static List<String> parseList(String arguments) {
|
||||
return Arrays.stream(arguments.split(","))
|
||||
.map((p) -> p.trim())
|
||||
.filter((p) -> !p.isEmpty())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static boolean isPreProcessor(Plugin.Category category) {
|
||||
return category.equals(Plugin.Category.COMPRESSOR)
|
||||
|| category.equals(Plugin.Category.FILTER)
|
||||
|| category.equals(Plugin.Category.MODULEINFO_TRANSFORMER)
|
||||
|| category.equals(Plugin.Category.SORTER)
|
||||
|| category.equals(Plugin.Category.TRANSFORMER)
|
||||
|| category.equals(Plugin.Category.METAINFO_ADDER);
|
||||
public static boolean isPostProcessor(Category category) {
|
||||
return category.equals(Category.VERIFIER)
|
||||
|| category.equals(Category.PROCESSOR)
|
||||
|| category.equals(Category.PACKAGER);
|
||||
}
|
||||
|
||||
public static boolean isPostProcessor(Plugin prov) {
|
||||
if (prov.getType() != null) {
|
||||
for (Plugin.Category pt : prov.getType()) {
|
||||
if (pt instanceof Plugin.Category) {
|
||||
return isPostProcessor(pt);
|
||||
}
|
||||
}
|
||||
public static boolean isPreProcessor(Category category) {
|
||||
return category.equals(Category.COMPRESSOR)
|
||||
|| category.equals(Category.FILTER)
|
||||
|| category.equals(Category.MODULEINFO_TRANSFORMER)
|
||||
|| category.equals(Category.SORTER)
|
||||
|| category.equals(Category.TRANSFORMER)
|
||||
|| category.equals(Category.METAINFO_ADDER);
|
||||
}
|
||||
|
||||
public static boolean isPostProcessor(Plugin provider) {
|
||||
Set<Category> types = provider.getType();
|
||||
Objects.requireNonNull(types);
|
||||
for (Category pt : types) {
|
||||
return isPostProcessor(pt);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isPreProcessor(Plugin prov) {
|
||||
if (prov.getType() != null) {
|
||||
for (Plugin.Category pt : prov.getType()) {
|
||||
if (pt instanceof Plugin.Category) {
|
||||
return isPreProcessor(pt);
|
||||
}
|
||||
}
|
||||
public static boolean isPreProcessor(Plugin provider) {
|
||||
Set<Category> types = provider.getType();
|
||||
Objects.requireNonNull(types);
|
||||
for (Category pt : types) {
|
||||
return isPreProcessor(pt);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Plugin.Category getCategory(Plugin provider) {
|
||||
if (provider.getType() != null) {
|
||||
for (Plugin.Category t : provider.getType()) {
|
||||
if (t instanceof Plugin.Category) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
public static Category getCategory(Plugin provider) {
|
||||
Set<Category> types = provider.getType();
|
||||
Objects.requireNonNull(types);
|
||||
for (Category t : types) {
|
||||
return t;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<Plugin> getPreProcessors(List<Plugin> plugins) {
|
||||
List<Plugin> res = new ArrayList<>();
|
||||
for (Plugin p : plugins) {
|
||||
if (isPreProcessor(p)) {
|
||||
res.add(p);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public static List<Plugin> getPostProcessors(List<Plugin> plugins) {
|
||||
List<Plugin> res = new ArrayList<>();
|
||||
for (Plugin p : plugins) {
|
||||
@ -133,16 +141,6 @@ public class Utils {
|
||||
return res;
|
||||
}
|
||||
|
||||
public static List<Plugin> getPreProcessors(List<Plugin> plugins) {
|
||||
List<Plugin> res = new ArrayList<>();
|
||||
for (Plugin p : plugins) {
|
||||
if (isPreProcessor(p)) {
|
||||
res.add(p);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public static boolean isFunctional(Plugin prov) {
|
||||
return prov.getState().contains(Plugin.State.FUNCTIONAL);
|
||||
}
|
||||
@ -161,7 +159,11 @@ public class Utils {
|
||||
}
|
||||
|
||||
public static FileSystem jrtFileSystem() {
|
||||
return FileSystems.getFileSystem(URI.create("jrt:/"));
|
||||
if (JRT_FILE_SYSTEM == null) {
|
||||
JRT_FILE_SYSTEM = FileSystems.getFileSystem(URI.create("jrt:/"));
|
||||
}
|
||||
|
||||
return JRT_FILE_SYSTEM;
|
||||
}
|
||||
|
||||
public static PathMatcher getPathMatcher(FileSystem fs, String pattern) {
|
||||
@ -172,7 +174,11 @@ public class Utils {
|
||||
return fs.getPathMatcher(pattern);
|
||||
}
|
||||
|
||||
public static PathMatcher getPathMatcher(String pattern) {
|
||||
public static PathMatcher getJRTFSPathMatcher(String pattern) {
|
||||
return getPathMatcher(jrtFileSystem(), pattern);
|
||||
}
|
||||
|
||||
public static Path getJRTFSPath(String first, String... more) {
|
||||
return jrtFileSystem().getPath(first, more);
|
||||
}
|
||||
}
|
||||
|
@ -24,8 +24,6 @@
|
||||
*/
|
||||
package jdk.tools.jlink.internal.plugins;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
@ -37,7 +35,6 @@ import jdk.tools.jlink.plugin.TransformerPlugin;
|
||||
import jdk.tools.jlink.internal.ImagePluginStack;
|
||||
import jdk.tools.jlink.internal.ResourcePrevisitor;
|
||||
import jdk.tools.jlink.internal.StringTable;
|
||||
import jdk.tools.jlink.internal.Utils;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -103,33 +100,26 @@ public final class DefaultCompressPlugin implements TransformerPlugin, ResourceP
|
||||
|
||||
@Override
|
||||
public void configure(Map<String, String> config) {
|
||||
try {
|
||||
String filter = config.get(FILTER);
|
||||
String[] patterns = filter == null ? null
|
||||
: Utils.listParser.apply(filter);
|
||||
ResourceFilter resFilter = new ResourceFilter(patterns);
|
||||
String level = config.get(NAME);
|
||||
if (level != null) {
|
||||
switch (level) {
|
||||
case LEVEL_0:
|
||||
ss = new StringSharingPlugin(resFilter);
|
||||
break;
|
||||
case LEVEL_1:
|
||||
zip = new ZipPlugin(resFilter);
|
||||
break;
|
||||
case LEVEL_2:
|
||||
ss = new StringSharingPlugin(resFilter);
|
||||
zip = new ZipPlugin(resFilter);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid compression level " + level);
|
||||
}
|
||||
} else {
|
||||
ss = new StringSharingPlugin(resFilter);
|
||||
zip = new ZipPlugin(resFilter);
|
||||
ResourceFilter resFilter = ResourceFilter.includeFilter(config.get(FILTER));
|
||||
String level = config.get(NAME);
|
||||
if (level != null) {
|
||||
switch (level) {
|
||||
case LEVEL_0:
|
||||
ss = new StringSharingPlugin(resFilter);
|
||||
break;
|
||||
case LEVEL_1:
|
||||
zip = new ZipPlugin(resFilter);
|
||||
break;
|
||||
case LEVEL_2:
|
||||
ss = new StringSharingPlugin(resFilter);
|
||||
zip = new ZipPlugin(resFilter);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid compression level " + level);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
} else {
|
||||
ss = new StringSharingPlugin(resFilter);
|
||||
zip = new ZipPlugin(resFilter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,6 @@
|
||||
*/
|
||||
package jdk.tools.jlink.internal.plugins;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
@ -84,11 +83,6 @@ public final class ExcludeFilesPlugin implements TransformerPlugin {
|
||||
|
||||
@Override
|
||||
public void configure(Map<String, String> config) {
|
||||
try {
|
||||
String value = config.get(NAME);
|
||||
predicate = new ResourceFilter(Utils.listParser.apply(value), true);
|
||||
} catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
predicate = ResourceFilter.excludeFilter(config.get(NAME));
|
||||
}
|
||||
}
|
||||
|
@ -24,17 +24,14 @@
|
||||
*/
|
||||
package jdk.tools.jlink.internal.plugins;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import jdk.tools.jlink.plugin.PluginException;
|
||||
import jdk.tools.jlink.plugin.TransformerPlugin;
|
||||
import jdk.tools.jlink.plugin.ModuleEntry;
|
||||
import jdk.tools.jlink.plugin.ModulePool;
|
||||
import jdk.tools.jlink.internal.Utils;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -84,11 +81,6 @@ public final class ExcludePlugin implements TransformerPlugin {
|
||||
|
||||
@Override
|
||||
public void configure(Map<String, String> config) {
|
||||
try {
|
||||
String val = config.get(NAME);
|
||||
predicate = new ResourceFilter(Utils.listParser.apply(val), true);
|
||||
} catch (IOException ex) {
|
||||
throw new PluginException(ex);
|
||||
}
|
||||
predicate = ResourceFilter.excludeFilter(config.get(NAME));
|
||||
}
|
||||
}
|
||||
|
@ -40,9 +40,7 @@ import java.util.TreeSet;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import jdk.tools.jlink.plugin.TransformerPlugin;
|
||||
import jdk.tools.jlink.plugin.ModuleEntry;
|
||||
import jdk.tools.jlink.plugin.ModulePool;
|
||||
import jdk.tools.jlink.internal.Utils;
|
||||
import jdk.tools.jlink.plugin.ModuleEntry;
|
||||
import jdk.tools.jlink.plugin.PluginException;
|
||||
|
||||
@ -184,38 +182,34 @@ public final class ExcludeVMPlugin implements TransformerPlugin {
|
||||
|
||||
@Override
|
||||
public void configure(Map<String, String> config) {
|
||||
try {
|
||||
String value = config.get(NAME);
|
||||
String exclude = "";
|
||||
switch (value) {
|
||||
case ALL: {
|
||||
// no filter.
|
||||
keepAll = true;
|
||||
break;
|
||||
}
|
||||
case CLIENT: {
|
||||
target = Jvm.CLIENT;
|
||||
exclude = "/java.base/native*server/*,/java.base/native*minimal/*";
|
||||
break;
|
||||
}
|
||||
case SERVER: {
|
||||
target = Jvm.SERVER;
|
||||
exclude = "/java.base/native*client/*,/java.base/native*minimal/*";
|
||||
break;
|
||||
}
|
||||
case MINIMAL: {
|
||||
target = Jvm.MINIMAL;
|
||||
exclude = "/java.base/native*server/*,/java.base/native*client/*";
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new IllegalArgumentException("Unknown exclude VM option: " + value);
|
||||
}
|
||||
String value = config.get(NAME);
|
||||
String exclude = "";
|
||||
switch (value) {
|
||||
case ALL: {
|
||||
// no filter.
|
||||
keepAll = true;
|
||||
break;
|
||||
}
|
||||
case CLIENT: {
|
||||
target = Jvm.CLIENT;
|
||||
exclude = "/java.base/native**server/**,/java.base/native**minimal/**";
|
||||
break;
|
||||
}
|
||||
case SERVER: {
|
||||
target = Jvm.SERVER;
|
||||
exclude = "/java.base/native**client/**,/java.base/native**minimal/**";
|
||||
break;
|
||||
}
|
||||
case MINIMAL: {
|
||||
target = Jvm.MINIMAL;
|
||||
exclude = "/java.base/native**server/**,/java.base/native**client/**";
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new IllegalArgumentException("Unknown exclude VM option: " + value);
|
||||
}
|
||||
predicate = new ResourceFilter(Utils.listParser.apply(exclude), true);
|
||||
} catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
predicate = ResourceFilter.excludeFilter(exclude);
|
||||
}
|
||||
|
||||
private ModuleEntry handleJvmCfgFile(ModuleEntry orig,
|
||||
|
@ -196,14 +196,13 @@ public class FileCopierPlugin implements TransformerPlugin {
|
||||
|
||||
@Override
|
||||
public void configure(Map<String, String> config) {
|
||||
String val = config.get(NAME);
|
||||
String[] argument = Utils.listParser.apply(val);
|
||||
if (argument == null || argument.length == 0) {
|
||||
List<String> arguments = Utils.parseList(config.get(NAME));
|
||||
if (arguments.isEmpty()) {
|
||||
throw new RuntimeException("Invalid argument for " + NAME);
|
||||
}
|
||||
|
||||
String javahome = System.getProperty("java.home");
|
||||
for (String a : argument) {
|
||||
for (String a : arguments) {
|
||||
int i = a.indexOf("=");
|
||||
CopiedFile cf = new CopiedFile();
|
||||
if (i == -1) {
|
||||
|
@ -25,8 +25,6 @@
|
||||
package jdk.tools.jlink.internal.plugins;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
@ -44,7 +42,6 @@ import java.util.stream.Stream;
|
||||
import jdk.internal.org.objectweb.asm.ClassReader;
|
||||
import jdk.tools.jlink.internal.ResourcePrevisitor;
|
||||
import jdk.tools.jlink.internal.StringTable;
|
||||
import jdk.tools.jlink.internal.Utils;
|
||||
import jdk.tools.jlink.plugin.LinkModule;
|
||||
import jdk.tools.jlink.plugin.ModuleEntry;
|
||||
import jdk.tools.jlink.plugin.PluginException;
|
||||
@ -209,14 +206,10 @@ public final class IncludeLocalesPlugin implements TransformerPlugin, ResourcePr
|
||||
String.format(PluginsResourceBundle.getMessage(NAME + ".nomatchinglocales"), userParam));
|
||||
}
|
||||
|
||||
try {
|
||||
String value = META_FILES + filtered.stream()
|
||||
.map(s -> includeLocaleFilePatterns(s))
|
||||
.collect(Collectors.joining(","));
|
||||
predicate = new ResourceFilter(Utils.listParser.apply(value), false);
|
||||
} catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
String value = META_FILES + filtered.stream()
|
||||
.map(s -> includeLocaleFilePatterns(s))
|
||||
.collect(Collectors.joining(","));
|
||||
predicate = ResourceFilter.includeFilter(value);
|
||||
}
|
||||
|
||||
private String includeLocaleFilePatterns(String tag) {
|
||||
|
@ -167,8 +167,7 @@ public final class OrderResourcesPlugin implements TransformerPlugin {
|
||||
|
||||
@Override
|
||||
public void configure(Map<String, String> config) {
|
||||
String val = config.get(NAME);
|
||||
String[] patterns = Utils.listParser.apply(val);
|
||||
List<String> patterns = Utils.parseList(config.get(NAME));
|
||||
int ordinal = 0;
|
||||
|
||||
for (String pattern : patterns) {
|
||||
|
@ -97,10 +97,9 @@ public final class ReleaseInfoPlugin implements TransformerPlugin {
|
||||
|
||||
case "del": {
|
||||
// --release-info del:keys=openjdk,java_version
|
||||
String[] keys = Utils.listParser.apply(config.get(KEYS));
|
||||
for (String k : keys) {
|
||||
Utils.parseList(config.get(KEYS)).stream().forEach((k) -> {
|
||||
release.remove(k);
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -26,12 +26,13 @@ package jdk.tools.jlink.internal.plugins;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
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.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
import jdk.tools.jlink.internal.Utils;
|
||||
import jdk.tools.jlink.plugin.PluginException;
|
||||
@ -41,17 +42,14 @@ import jdk.tools.jlink.plugin.PluginException;
|
||||
* Filter resource resources using path matcher.
|
||||
*/
|
||||
public class ResourceFilter implements Predicate<String> {
|
||||
private static final FileSystem JRT_FILE_SYSTEM = Utils.jrtFileSystem();
|
||||
private final static List<String> EMPTY_LIST = Collections.emptyList();
|
||||
|
||||
final boolean negate;
|
||||
final List<PathMatcher> matchers;
|
||||
private final List<PathMatcher> matchers;
|
||||
private final boolean include;
|
||||
private final boolean otherwise;
|
||||
|
||||
public ResourceFilter(String[] patterns) throws IOException {
|
||||
this(patterns, false);
|
||||
}
|
||||
|
||||
public ResourceFilter(String[] patterns, boolean negate) throws IOException {
|
||||
this.negate = negate;
|
||||
private ResourceFilter(List<String> patterns, boolean exclude) {
|
||||
Objects.requireNonNull(patterns);
|
||||
this.matchers = new ArrayList<>();
|
||||
|
||||
for (String pattern : patterns) {
|
||||
@ -67,28 +65,59 @@ public class ResourceFilter implements Predicate<String> {
|
||||
throw new PluginException(ex);
|
||||
}
|
||||
|
||||
for (String line : lines) {
|
||||
PathMatcher matcher = Utils.getPathMatcher(JRT_FILE_SYSTEM, line);
|
||||
matchers.add(matcher);
|
||||
}
|
||||
lines.stream().forEach((line) -> {
|
||||
matchers.add(Utils.getJRTFSPathMatcher(line.trim()));
|
||||
});
|
||||
} else {
|
||||
System.err.println("warning - the filter file " + file +
|
||||
" is empty or not present.");
|
||||
}
|
||||
} else {
|
||||
PathMatcher matcher = Utils.getPathMatcher(JRT_FILE_SYSTEM, pattern);
|
||||
matchers.add(matcher);
|
||||
matchers.add(Utils.getJRTFSPathMatcher(pattern));
|
||||
}
|
||||
}
|
||||
|
||||
this.include = !exclude;
|
||||
this.otherwise = exclude || this.matchers.isEmpty();
|
||||
}
|
||||
|
||||
public static ResourceFilter includeFilter(List<String> patterns) {
|
||||
Objects.requireNonNull(patterns);
|
||||
return new ResourceFilter(patterns, false);
|
||||
}
|
||||
|
||||
public static ResourceFilter includeFilter(String patterns) {
|
||||
if (patterns == null) {
|
||||
return includeFilter(EMPTY_LIST);
|
||||
}
|
||||
|
||||
return includeFilter(Utils.parseList(patterns));
|
||||
}
|
||||
|
||||
public static ResourceFilter excludeFilter(List<String> patterns) {
|
||||
Objects.requireNonNull(patterns);
|
||||
return new ResourceFilter(patterns, true);
|
||||
}
|
||||
|
||||
public static ResourceFilter excludeFilter(String patterns) {
|
||||
if (patterns == null) {
|
||||
return excludeFilter(EMPTY_LIST);
|
||||
}
|
||||
|
||||
return excludeFilter(Utils.parseList(patterns));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(String name) {
|
||||
Path path = JRT_FILE_SYSTEM.getPath(name);
|
||||
Objects.requireNonNull(name);
|
||||
Path path = Utils.getJRTFSPath(name);
|
||||
|
||||
for (PathMatcher matcher : matchers) {
|
||||
if (matcher.matches(path)) {
|
||||
return !negate;
|
||||
return include;
|
||||
}
|
||||
}
|
||||
|
||||
return negate;
|
||||
return otherwise;
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +63,6 @@ import jdk.tools.jlink.plugin.ModuleEntry;
|
||||
import jdk.tools.jlink.plugin.ModulePool;
|
||||
import jdk.tools.jlink.internal.ResourcePrevisitor;
|
||||
import jdk.tools.jlink.internal.StringTable;
|
||||
import jdk.tools.jlink.internal.Utils;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -335,12 +334,8 @@ public class StringSharingPlugin implements TransformerPlugin, ResourcePrevisito
|
||||
|
||||
private Predicate<String> predicate;
|
||||
|
||||
public StringSharingPlugin() throws IOException {
|
||||
this(new String[0]);
|
||||
}
|
||||
|
||||
StringSharingPlugin(String[] patterns) throws IOException {
|
||||
this(new ResourceFilter(patterns));
|
||||
public StringSharingPlugin() {
|
||||
this((path) -> true);
|
||||
}
|
||||
|
||||
StringSharingPlugin(Predicate<String> predicate) {
|
||||
@ -396,12 +391,7 @@ public class StringSharingPlugin implements TransformerPlugin, ResourcePrevisito
|
||||
|
||||
@Override
|
||||
public void configure(Map<String, String> config) {
|
||||
try {
|
||||
String val = config.get(NAME);
|
||||
predicate = new ResourceFilter(Utils.listParser.apply(val));
|
||||
} catch (IOException ex) {
|
||||
throw new PluginException(ex);
|
||||
}
|
||||
predicate = ResourceFilter.includeFilter(config.get(NAME));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -25,8 +25,7 @@
|
||||
package jdk.tools.jlink.internal.plugins;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
@ -42,15 +41,15 @@ import jdk.tools.jlink.plugin.TransformerPlugin;
|
||||
* Strip debug attributes plugin
|
||||
*/
|
||||
public final class StripDebugPlugin implements TransformerPlugin {
|
||||
private static final String[] PATTERNS = {"*.diz"};
|
||||
public static final String NAME = "strip-debug";
|
||||
private final Predicate<String> predicate;
|
||||
|
||||
public StripDebugPlugin() {
|
||||
try {
|
||||
predicate = new ResourceFilter(PATTERNS);
|
||||
} catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
this((path) -> false);
|
||||
}
|
||||
|
||||
StripDebugPlugin(Predicate<String> predicate) {
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -27,18 +27,17 @@ package jdk.tools.jlink.internal.plugins;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.zip.Deflater;
|
||||
import jdk.tools.jlink.plugin.PluginException;
|
||||
import jdk.tools.jlink.internal.ModulePoolImpl;
|
||||
import jdk.tools.jlink.plugin.ModuleEntry;
|
||||
import jdk.tools.jlink.plugin.ModulePool;
|
||||
import jdk.tools.jlink.plugin.TransformerPlugin;
|
||||
import jdk.tools.jlink.internal.Utils;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -53,8 +52,8 @@ public final class ZipPlugin implements TransformerPlugin {
|
||||
|
||||
}
|
||||
|
||||
ZipPlugin(String[] patterns) throws IOException {
|
||||
this(new ResourceFilter(patterns));
|
||||
ZipPlugin(String[] patterns) {
|
||||
this(ResourceFilter.includeFilter(Arrays.asList(patterns)));
|
||||
}
|
||||
|
||||
ZipPlugin(Predicate<String> predicate) {
|
||||
@ -90,12 +89,7 @@ public final class ZipPlugin implements TransformerPlugin {
|
||||
|
||||
@Override
|
||||
public void configure(Map<String, String> config) {
|
||||
try {
|
||||
String val = config.get(NAME);
|
||||
predicate = new ResourceFilter(Utils.listParser.apply(val));
|
||||
} catch (IOException ex) {
|
||||
throw new PluginException(ex);
|
||||
}
|
||||
predicate = ResourceFilter.includeFilter(config.get(NAME));
|
||||
}
|
||||
|
||||
static byte[] compress(byte[] bytesIn) {
|
||||
|
@ -103,6 +103,7 @@ import jdk.internal.module.ConfigurableModuleFinder;
|
||||
import jdk.internal.module.ConfigurableModuleFinder.Phase;
|
||||
import jdk.internal.module.ModuleHashes;
|
||||
import jdk.internal.module.ModuleInfoExtender;
|
||||
import jdk.tools.jlink.internal.Utils;
|
||||
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
@ -1091,13 +1092,7 @@ public class JmodTask {
|
||||
@Override
|
||||
public PathMatcher convert(String pattern) {
|
||||
try {
|
||||
if (!pattern.startsWith("glob:") &&
|
||||
!pattern.startsWith("regex:")) {
|
||||
pattern = "glob:" + pattern;
|
||||
}
|
||||
|
||||
return FileSystems.getDefault()
|
||||
.getPathMatcher("glob:" + pattern);
|
||||
return Utils.getPathMatcher(FileSystems.getDefault(), pattern);
|
||||
} catch (PatternSyntaxException e) {
|
||||
throw new CommandException("err.bad.pattern", pattern);
|
||||
}
|
||||
|
@ -393,28 +393,6 @@ com/sun/jndi/ldap/DeadSSLLdapTimeoutTest.java 8141370 linux-i5
|
||||
|
||||
tools/jlink/plugins/IncludeLocalesPluginTest.java 8158272 generic-all
|
||||
|
||||
tools/jlink/basic/BasicTest.java 8159206 generic-all
|
||||
|
||||
tools/jlink/IntegrationTest.java 8159206 generic-all
|
||||
|
||||
tools/jlink/JLinkOptimTest.java 8159206 generic-all
|
||||
|
||||
tools/jlink/JLinkTest.java 8159206 generic-all
|
||||
|
||||
tools/jlink/plugins/CompressorPluginTest.java 8159206 generic-all
|
||||
|
||||
tools/jlink/plugins/ExcludeFilesPluginTest.java 8159206 generic-all
|
||||
|
||||
tools/jlink/plugins/ExcludePluginTest.java 8159206 generic-all
|
||||
|
||||
tools/jlink/plugins/ExcludeVMPluginTest.java 8159206 generic-all
|
||||
|
||||
tools/jlink/plugins/OrderResourcesPluginTest.java 8159206 generic-all
|
||||
|
||||
tools/jlink/plugins/ResourceFilterTest.java 8159206 generic-all
|
||||
|
||||
tools/jlink/plugins/StringSharingPluginTest.java 8159206 generic-all
|
||||
|
||||
tools/jmod/JmodTest.java 8159206 generic-all
|
||||
tools/jlink/JLinkOptimTest.java 8159264 generic-all
|
||||
|
||||
############################################################################
|
||||
|
@ -332,17 +332,6 @@ public class JLinkOptimTest {
|
||||
helper.checkImage(imageDir, "optim1", null, null);
|
||||
}
|
||||
|
||||
/*{
|
||||
Path dir = Paths.get("dir.log");
|
||||
Files.createDirectory(dir);
|
||||
String[] userOptions = {"--class-optim=all:log=" + dir.toString()};
|
||||
helper.generateDefaultImage(userOptions, "optim1")
|
||||
.assertFailure("java.io.FileNotFoundException: dir.log (Is a directory)");
|
||||
}*/
|
||||
/*{
|
||||
String[] userOptions = {"--class-optim", "UNKNOWN"};
|
||||
helper.generateDefaultImage(userOptions, "optim1").assertFailure("Unknown optimization");
|
||||
}*/
|
||||
{
|
||||
String[] userOptions = {"--class-optim=forName-folding:log=./class-optim-log.txt"};
|
||||
Path imageDir = helper.generateDefaultImage(userOptions, "optim1").assertSuccess();
|
||||
|
@ -103,13 +103,12 @@ public class CompressorPluginTest {
|
||||
|
||||
// compress == ZIP + String sharing + filter
|
||||
options.setProperty(DefaultCompressPlugin.FILTER,
|
||||
"*Exception.class,^*IOException.class");
|
||||
"**Exception.class");
|
||||
checkCompress(classes, new DefaultCompressPlugin(), options,
|
||||
new ResourceDecompressorFactory[]{
|
||||
new ZipDecompressorFactory(),
|
||||
new StringSharingDecompressorFactory()
|
||||
}, Collections.singletonList(".*Exception.class"),
|
||||
Collections.singletonList(".*IOException.class"));
|
||||
}, Collections.singletonList(".*Exception.class"));
|
||||
|
||||
// compress level 1 == ZIP
|
||||
Properties options1 = new Properties();
|
||||
@ -123,13 +122,12 @@ public class CompressorPluginTest {
|
||||
|
||||
// compress level 1 == ZIP
|
||||
options1.setProperty(DefaultCompressPlugin.FILTER,
|
||||
"*Exception.class,^*IOException.class");
|
||||
"**Exception.class");
|
||||
checkCompress(classes, new DefaultCompressPlugin(),
|
||||
options1,
|
||||
new ResourceDecompressorFactory[]{
|
||||
new ZipDecompressorFactory()
|
||||
}, Collections.singletonList(".*Exception.class"),
|
||||
Collections.singletonList(".*IOException.class"));
|
||||
}, Collections.singletonList(".*Exception.class"));
|
||||
|
||||
// compress level 2 == ZIP + String sharing
|
||||
Properties options2 = new Properties();
|
||||
@ -144,14 +142,13 @@ public class CompressorPluginTest {
|
||||
|
||||
// compress level 2 == ZIP + String sharing + filter
|
||||
options2.setProperty(DefaultCompressPlugin.FILTER,
|
||||
"*Exception.class,^*IOException.class");
|
||||
"**Exception.class");
|
||||
checkCompress(classes, new DefaultCompressPlugin(),
|
||||
options2,
|
||||
new ResourceDecompressorFactory[]{
|
||||
new ZipDecompressorFactory(),
|
||||
new StringSharingDecompressorFactory()
|
||||
}, Collections.singletonList(".*Exception.class"),
|
||||
Collections.singletonList(".*IOException.class"));
|
||||
}, Collections.singletonList(".*Exception.class"));
|
||||
|
||||
// compress level 0 == String sharing
|
||||
Properties options0 = new Properties();
|
||||
@ -164,13 +161,12 @@ public class CompressorPluginTest {
|
||||
|
||||
// compress level 0 == String sharing + filter
|
||||
options0.setProperty(DefaultCompressPlugin.FILTER,
|
||||
"*Exception.class,^*IOException.class");
|
||||
"**Exception.class");
|
||||
checkCompress(classes, new DefaultCompressPlugin(),
|
||||
options0,
|
||||
new ResourceDecompressorFactory[]{
|
||||
new StringSharingDecompressorFactory()
|
||||
}, Collections.singletonList(".*Exception.class"),
|
||||
Collections.singletonList(".*IOException.class"));
|
||||
}, Collections.singletonList(".*Exception.class"));
|
||||
}
|
||||
|
||||
private ModulePool gatherResources(Path module) throws Exception {
|
||||
@ -226,23 +222,19 @@ public class CompressorPluginTest {
|
||||
private void checkCompress(ModulePool resources, Plugin prov,
|
||||
Properties config,
|
||||
ResourceDecompressorFactory[] factories) throws Exception {
|
||||
checkCompress(resources, prov, config, factories, Collections.emptyList(), Collections.emptyList());
|
||||
checkCompress(resources, prov, config, factories, Collections.emptyList());
|
||||
}
|
||||
|
||||
private void checkCompress(ModulePool resources, Plugin prov,
|
||||
Properties config,
|
||||
ResourceDecompressorFactory[] factories,
|
||||
List<String> includes,
|
||||
List<String> excludes) throws Exception {
|
||||
List<String> includes) throws Exception {
|
||||
long[] original = new long[1];
|
||||
long[] compressed = new long[1];
|
||||
resources.entries().forEach(resource -> {
|
||||
List<Pattern> includesPatterns = includes.stream()
|
||||
.map(Pattern::compile)
|
||||
.collect(Collectors.toList());
|
||||
List<Pattern> excludesPatterns = excludes.stream()
|
||||
.map(Pattern::compile)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Map<String, String> props = new HashMap<>();
|
||||
if (config != null) {
|
||||
@ -267,10 +259,10 @@ public class CompressorPluginTest {
|
||||
}
|
||||
});
|
||||
inputResources.add(resource);
|
||||
ModulePool compressedResources = applyCompressor(prov, inputResources, resource, includesPatterns, excludesPatterns);
|
||||
ModulePool compressedResources = applyCompressor(prov, inputResources, resource, includesPatterns);
|
||||
original[0] += resource.getLength();
|
||||
compressed[0] += compressedResources.findEntry(resource.getPath()).get().getLength();
|
||||
applyDecompressors(factories, inputResources, compressedResources, strings, includesPatterns, excludesPatterns);
|
||||
applyDecompressors(factories, inputResources, compressedResources, strings, includesPatterns);
|
||||
});
|
||||
String compressors = Stream.of(factories)
|
||||
.map(Object::getClass)
|
||||
@ -286,8 +278,7 @@ public class CompressorPluginTest {
|
||||
private ModulePool applyCompressor(Plugin plugin,
|
||||
ModulePoolImpl inputResources,
|
||||
ModuleEntry res,
|
||||
List<Pattern> includesPatterns,
|
||||
List<Pattern> excludesPatterns) {
|
||||
List<Pattern> includesPatterns) {
|
||||
TransformerPlugin compressor = (TransformerPlugin) plugin;
|
||||
ModulePool compressedModulePool = new ModulePoolImpl(ByteOrder.nativeOrder(), inputResources.getStringTable());
|
||||
compressor.visit(inputResources, compressedModulePool);
|
||||
@ -295,7 +286,7 @@ public class CompressorPluginTest {
|
||||
ModuleEntry compressed = compressedModulePool.findEntry(path).get();
|
||||
CompressedResourceHeader header
|
||||
= CompressedResourceHeader.readFromResource(ByteOrder.nativeOrder(), compressed.getBytes());
|
||||
if (isIncluded(includesPatterns, excludesPatterns, path)) {
|
||||
if (isIncluded(includesPatterns, path)) {
|
||||
if (header == null) {
|
||||
throw new AssertionError("Path should be compressed: " + path);
|
||||
}
|
||||
@ -317,14 +308,13 @@ public class CompressorPluginTest {
|
||||
ModulePool inputResources,
|
||||
ModulePool compressedResources,
|
||||
Map<Integer, String> strings,
|
||||
List<Pattern> includesPatterns,
|
||||
List<Pattern> excludesPatterns) {
|
||||
List<Pattern> includesPatterns) {
|
||||
compressedResources.entries().forEach(compressed -> {
|
||||
CompressedResourceHeader header = CompressedResourceHeader.readFromResource(
|
||||
ByteOrder.nativeOrder(), compressed.getBytes());
|
||||
String path = compressed.getPath();
|
||||
ModuleEntry orig = inputResources.findEntry(path).get();
|
||||
if (!isIncluded(includesPatterns, excludesPatterns, path)) {
|
||||
if (!isIncluded(includesPatterns, path)) {
|
||||
return;
|
||||
}
|
||||
byte[] decompressed = compressed.getBytes();
|
||||
@ -352,9 +342,8 @@ public class CompressorPluginTest {
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isIncluded(List<Pattern> includesPatterns, List<Pattern> excludesPatterns, String path) {
|
||||
return !excludesPatterns.stream().anyMatch((pattern) -> pattern.matcher(path).matches())
|
||||
&& (includesPatterns.isEmpty()
|
||||
|| includesPatterns.stream().anyMatch((pattern) -> pattern.matcher(path).matches()));
|
||||
private boolean isIncluded(List<Pattern> includesPatterns, String path) {
|
||||
return includesPatterns.isEmpty() ||
|
||||
includesPatterns.stream().anyMatch((pattern) -> pattern.matcher(path).matches());
|
||||
}
|
||||
}
|
||||
|
@ -48,23 +48,23 @@ public class ExcludeFilesPluginTest {
|
||||
}
|
||||
|
||||
public void test() throws Exception {
|
||||
checkFiles("*.jcov", "num/toto.jcov", "", true);
|
||||
checkFiles("*.jcov", "/toto.jcov", "", true);
|
||||
checkFiles("*.jcov", "toto.jcov/tutu/tata", "", false);
|
||||
checkFiles("**.jcov", "num/toto.jcov", "", true);
|
||||
checkFiles("**.jcov", "/toto.jcov", "", true);
|
||||
checkFiles("**.jcov", "toto.jcov/tutu/tata", "", false);
|
||||
checkFiles("/java.base/*.jcov", "toto.jcov", "java.base", true);
|
||||
checkFiles("/java.base/toto.jcov", "iti.jcov", "t/java.base", false);
|
||||
checkFiles("/java.base/*/toto.jcov", "toto.jcov", "java.base", false);
|
||||
checkFiles("/java.base/*/toto.jcov", "tutu/toto.jcov", "java.base", true);
|
||||
checkFiles("*/java.base/*/toto.jcov", "java.base/tutu/toto.jcov", "/tutu", true);
|
||||
checkFiles("**/java.base/*/toto.jcov", "java.base/tutu/toto.jcov", "/tutu", true);
|
||||
|
||||
checkFiles("/*$*.properties", "tutu/Toto$Titi.properties", "java.base", true);
|
||||
checkFiles("*$*.properties", "tutu/Toto$Titi.properties", "java.base", true);
|
||||
checkFiles("/**$*.properties", "tutu/Toto$Titi.properties", "java.base", true);
|
||||
checkFiles("**$*.properties", "tutu/Toto$Titi.properties", "java.base", true);
|
||||
|
||||
// Excluded files list in a file
|
||||
File order = new File("files.exc");
|
||||
order.createNewFile();
|
||||
Files.write(order.toPath(), "*.jcov".getBytes());
|
||||
checkFiles(order.getAbsolutePath(), "/num/toto.jcov", "", true);
|
||||
Files.write(order.toPath(), "**.jcov".getBytes());
|
||||
checkFiles("@" + order.getAbsolutePath(), "/num/toto.jcov", "", true);
|
||||
}
|
||||
|
||||
public void checkFiles(String s, String sample, String module, boolean exclude) throws Exception {
|
||||
|
@ -47,27 +47,27 @@ public class ExcludePluginTest {
|
||||
}
|
||||
|
||||
public void test() throws Exception {
|
||||
check("*.jcov", "/num/toto.jcov", true);
|
||||
check("*.jcov", "//toto.jcov", true);
|
||||
check("*.jcov", "/toto.jcov/tutu/tata", false);
|
||||
check("**.jcov", "/num/toto.jcov", true);
|
||||
check("**.jcov", "//toto.jcov", true);
|
||||
check("**.jcov", "/toto.jcov/tutu/tata", false);
|
||||
check("/java.base/*.jcov", "/java.base/toto.jcov", true);
|
||||
check("/java.base/toto.jcov", "t/java.base/iti.jcov", false);
|
||||
check("/java.base/*/toto.jcov", "/java.base/toto.jcov", false);
|
||||
check("/java.base/*/toto.jcov", "/java.base/tutu/toto.jcov", true);
|
||||
check("*/java.base/*/toto.jcov", "/tutu/java.base/tutu/toto.jcov", true);
|
||||
check("*/META-INF/*", "/META-INF/services/ MyProvider ", false);
|
||||
check("*/META-INF/*", "/META-INF/services/MyProvider", false);
|
||||
check("*/META-INF", " /META-INF/services/MyProvider", false);
|
||||
check("*/META-INF/*", "/java.base//META-INF/services/MyProvider", true);
|
||||
check("**/java.base/*/toto.jcov", "/tutu/java.base/tutu/toto.jcov", true);
|
||||
check("/META-INF/**", "/META-INF/services/ MyProvider ", true);
|
||||
check("/META-INF/**", "/META-INF/services/MyProvider", true);
|
||||
check("**/META-INF", " /META-INF/services/MyProvider", false);
|
||||
check("**/META-INF/**", "/java.base//META-INF/services/MyProvider", true);
|
||||
check("/java.base/*/Toto$Titi.class", "/java.base/tutu/Toto$Titi.class", true);
|
||||
check("/*$*.class", "/java.base/tutu/Toto$Titi.class", true);
|
||||
check("*$*.class", "/java.base/tutu/Toto$Titi.class", true);
|
||||
check("/**$**.class", "/java.base/tutu/Toto$Titi.class", true);
|
||||
check("**$**.class", "/java.base/tutu/Toto$Titi.class", true);
|
||||
|
||||
// Excluded resource list in a file
|
||||
File order = new File("resources.exc");
|
||||
order.createNewFile();
|
||||
Files.write(order.toPath(), "*.jcov".getBytes());
|
||||
check(order.getAbsolutePath(), "/num/toto.jcov", true);
|
||||
Files.write(order.toPath(), "**.jcov".getBytes());
|
||||
check("@" + order.getAbsolutePath(), "/num/toto.jcov", true);
|
||||
}
|
||||
|
||||
public void check(String s, String sample, boolean exclude) throws Exception {
|
||||
|
@ -92,7 +92,7 @@ public class OrderResourcesPluginTest {
|
||||
{
|
||||
ModulePool out = new ModulePoolImpl();
|
||||
Map<String, String> config = new HashMap<>();
|
||||
config.put(OrderResourcesPlugin.NAME, "/zazou/*,*/module-info.class");
|
||||
config.put(OrderResourcesPlugin.NAME, "/zazou/**,**/module-info.class");
|
||||
TransformerPlugin p = new OrderResourcesPlugin();
|
||||
p.configure(config);
|
||||
p.visit(resources, out);
|
||||
|
@ -24,13 +24,13 @@
|
||||
/*
|
||||
* @test
|
||||
* @summary Test ResourceFilter class
|
||||
* @author Jean-Francois Denise
|
||||
* @modules jdk.jlink/jdk.tools.jlink.internal.plugins
|
||||
* @run main ResourceFilterTest
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Arrays;
|
||||
import jdk.tools.jlink.internal.plugins.ResourceFilter;
|
||||
|
||||
public class ResourceFilterTest {
|
||||
@ -41,14 +41,16 @@ public class ResourceFilterTest {
|
||||
|
||||
public void test() throws Exception {
|
||||
String[] samples = {"toto.jcov", "/module/META-INF/services/MyProvider"};
|
||||
String[] patterns = {"*.jcov", "*/META-INF/*"};
|
||||
ResourceFilter rf = new ResourceFilter(patterns);
|
||||
String[] patterns = {"*.jcov", "**/META-INF/**",
|
||||
"glob:*.jcov", "glob:**/META-INF/**",
|
||||
"regex:.*\\.jcov", "regex:.*/META-INF/.*"};
|
||||
ResourceFilter rf = ResourceFilter.includeFilter(Arrays.asList(patterns));
|
||||
for (String s : samples) {
|
||||
if (!rf.test(s)) {
|
||||
throw new Exception("Sample " + s + "not accepted");
|
||||
}
|
||||
}
|
||||
ResourceFilter rf2 = new ResourceFilter(patterns, true);
|
||||
ResourceFilter rf2 = ResourceFilter.excludeFilter(Arrays.asList(patterns));
|
||||
for (String s : samples) {
|
||||
if (rf2.test(s)) {
|
||||
throw new Exception("Sample " + s + " accepted");
|
||||
@ -64,14 +66,14 @@ public class ResourceFilterTest {
|
||||
}
|
||||
Files.write(resources.toPath(), builder.toString().getBytes());
|
||||
|
||||
String[] input = {resources.getAbsolutePath()};
|
||||
ResourceFilter rf3 = new ResourceFilter(input);
|
||||
String[] input = {"@" + resources.getAbsolutePath()};
|
||||
ResourceFilter rf3 = ResourceFilter.includeFilter(Arrays.asList(input));
|
||||
for (String s : samples) {
|
||||
if (!rf3.test(s)) {
|
||||
throw new Exception("Sample " + s + "not accepted");
|
||||
}
|
||||
}
|
||||
ResourceFilter rf4 = new ResourceFilter(input, true);
|
||||
ResourceFilter rf4 = ResourceFilter.excludeFilter(Arrays.asList(input));
|
||||
for (String s : samples) {
|
||||
if (rf4.test(s)) {
|
||||
throw new Exception("Sample " + s + " accepted");
|
||||
|
Loading…
Reference in New Issue
Block a user