mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 19:14:38 +02:00
8063145: ToolBox should support extracting classes from a JavaFileManager/Location
Reviewed-by: ksrini
This commit is contained in:
parent
3f3f44af47
commit
de2b97f133
2 changed files with 194 additions and 64 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -26,7 +26,8 @@
|
||||||
* @bug 6508981
|
* @bug 6508981
|
||||||
* @summary cleanup file separator handling in JavacFileManager
|
* @summary cleanup file separator handling in JavacFileManager
|
||||||
* (This test is specifically to test the new impl of inferBinaryName)
|
* (This test is specifically to test the new impl of inferBinaryName)
|
||||||
* @build p.A
|
* @library /tools/lib
|
||||||
|
* @build ToolBox p.A
|
||||||
* @run main TestInferBinaryName
|
* @run main TestInferBinaryName
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -61,52 +62,76 @@ public class TestInferBinaryName {
|
||||||
//System.err.println(System.getProperties());
|
//System.err.println(System.getProperties());
|
||||||
testDirectory();
|
testDirectory();
|
||||||
testSymbolArchive();
|
testSymbolArchive();
|
||||||
testZipArchive();
|
|
||||||
testZipFileIndexArchive();
|
File testJar = createJar();
|
||||||
testZipFileIndexArchive2();
|
|
||||||
|
testZipArchive(testJar);
|
||||||
|
testZipFileIndexArchive(testJar);
|
||||||
|
testZipFileIndexArchive2(testJar);
|
||||||
if (errors > 0)
|
if (errors > 0)
|
||||||
throw new Exception(errors + " error found");
|
throw new Exception(errors + " error found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File createJar() throws IOException {
|
||||||
|
File f = new File("test.jar");
|
||||||
|
try (JavaFileManager fm = new JavacFileManager(new Context(), false, null)) {
|
||||||
|
ToolBox tb = new ToolBox();
|
||||||
|
tb.new JarTask(f.getPath())
|
||||||
|
.files(fm, StandardLocation.PLATFORM_CLASS_PATH, "java.lang.*")
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
void testDirectory() throws IOException {
|
void testDirectory() throws IOException {
|
||||||
String testClassName = "p.A";
|
String testClassName = "p.A";
|
||||||
JavaFileManager fm =
|
List<File> testClasses = Arrays.asList(new File(System.getProperty("test.classes")));
|
||||||
getFileManager("test.classes", USE_SYMBOL_FILE, USE_ZIP_FILE_INDEX);
|
try (JavaFileManager fm =
|
||||||
|
getFileManager(testClasses, USE_SYMBOL_FILE, USE_ZIP_FILE_INDEX)) {
|
||||||
test("testDirectory",
|
test("testDirectory",
|
||||||
fm, testClassName, "com.sun.tools.javac.file.RegularFileObject");
|
fm, testClassName, "com.sun.tools.javac.file.RegularFileObject");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void testSymbolArchive() throws IOException {
|
void testSymbolArchive() throws IOException {
|
||||||
String testClassName = "java.lang.String";
|
String testClassName = "java.lang.String";
|
||||||
JavaFileManager fm =
|
List<File> path = getPath(System.getProperty("sun.boot.class.path"));
|
||||||
getFileManager("sun.boot.class.path", USE_SYMBOL_FILE, DONT_USE_ZIP_FILE_INDEX);
|
try (JavaFileManager fm =
|
||||||
|
getFileManager(path, USE_SYMBOL_FILE, DONT_USE_ZIP_FILE_INDEX)) {
|
||||||
test("testSymbolArchive",
|
test("testSymbolArchive",
|
||||||
fm, testClassName, "com.sun.tools.javac.file.SymbolArchive$SymbolFileObject");
|
fm, testClassName, "com.sun.tools.javac.file.SymbolArchive$SymbolFileObject");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void testZipArchive() throws IOException {
|
void testZipArchive(File testJar) throws IOException {
|
||||||
String testClassName = "java.lang.String";
|
String testClassName = "java.lang.String";
|
||||||
JavaFileManager fm =
|
List<File> path = Arrays.asList(testJar);
|
||||||
getFileManager("sun.boot.class.path", IGNORE_SYMBOL_FILE, DONT_USE_ZIP_FILE_INDEX);
|
try (JavaFileManager fm =
|
||||||
|
getFileManager(path, IGNORE_SYMBOL_FILE, DONT_USE_ZIP_FILE_INDEX)) {
|
||||||
test("testZipArchive",
|
test("testZipArchive",
|
||||||
fm, testClassName, "com.sun.tools.javac.file.ZipArchive$ZipFileObject");
|
fm, testClassName, "com.sun.tools.javac.file.ZipArchive$ZipFileObject");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void testZipFileIndexArchive() throws IOException {
|
void testZipFileIndexArchive(File testJar) throws IOException {
|
||||||
String testClassName = "java.lang.String";
|
String testClassName = "java.lang.String";
|
||||||
JavaFileManager fm =
|
List<File> path = Arrays.asList(testJar);
|
||||||
getFileManager("sun.boot.class.path", USE_SYMBOL_FILE, USE_ZIP_FILE_INDEX);
|
try (JavaFileManager fm =
|
||||||
|
getFileManager(path, USE_SYMBOL_FILE, USE_ZIP_FILE_INDEX)) {
|
||||||
test("testZipFileIndexArchive",
|
test("testZipFileIndexArchive",
|
||||||
fm, testClassName, "com.sun.tools.javac.file.ZipFileIndexArchive$ZipFileIndexFileObject");
|
fm, testClassName, "com.sun.tools.javac.file.ZipFileIndexArchive$ZipFileIndexFileObject");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void testZipFileIndexArchive2() throws IOException {
|
void testZipFileIndexArchive2(File testJar) throws IOException {
|
||||||
String testClassName = "java.lang.String";
|
String testClassName = "java.lang.String";
|
||||||
JavaFileManager fm =
|
List<File> path = Arrays.asList(testJar);
|
||||||
getFileManager("sun.boot.class.path", IGNORE_SYMBOL_FILE, USE_ZIP_FILE_INDEX);
|
try (JavaFileManager fm =
|
||||||
|
getFileManager(path, IGNORE_SYMBOL_FILE, USE_ZIP_FILE_INDEX)) {
|
||||||
test("testZipFileIndexArchive2",
|
test("testZipFileIndexArchive2",
|
||||||
fm, testClassName, "com.sun.tools.javac.file.ZipFileIndexArchive$ZipFileIndexFileObject");
|
fm, testClassName, "com.sun.tools.javac.file.ZipFileIndexArchive$ZipFileIndexFileObject");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param testName for debugging
|
* @param testName for debugging
|
||||||
|
@ -133,7 +158,7 @@ public class TestInferBinaryName {
|
||||||
System.err.println("OK");
|
System.err.println("OK");
|
||||||
}
|
}
|
||||||
|
|
||||||
JavaFileManager getFileManager(String classpathProperty,
|
JavaFileManager getFileManager(List<File> path,
|
||||||
boolean symFileKind,
|
boolean symFileKind,
|
||||||
boolean zipFileIndexKind)
|
boolean zipFileIndexKind)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
@ -145,7 +170,6 @@ public class TestInferBinaryName {
|
||||||
if (symFileKind == IGNORE_SYMBOL_FILE)
|
if (symFileKind == IGNORE_SYMBOL_FILE)
|
||||||
options.put("ignore.symbol.file", "true");
|
options.put("ignore.symbol.file", "true");
|
||||||
JavacFileManager fm = new JavacFileManager(ctx, false, null);
|
JavacFileManager fm = new JavacFileManager(ctx, false, null);
|
||||||
List<File> path = getPath(System.getProperty(classpathProperty));
|
|
||||||
fm.setLocation(CLASS_PATH, path);
|
fm.setLocation(CLASS_PATH, path);
|
||||||
return fm;
|
return fm;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
@ -28,6 +29,7 @@ import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FilterOutputStream;
|
import java.io.FilterOutputStream;
|
||||||
import java.io.FilterWriter;
|
import java.io.FilterWriter;
|
||||||
|
import java.io.IOError;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
@ -49,12 +51,15 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ListIterator;
|
import java.util.ListIterator;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.jar.Attributes;
|
import java.util.jar.Attributes;
|
||||||
import java.util.jar.JarEntry;
|
import java.util.jar.JarEntry;
|
||||||
import java.util.jar.JarOutputStream;
|
import java.util.jar.JarOutputStream;
|
||||||
|
@ -64,18 +69,20 @@ import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import java.util.stream.StreamSupport;
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
import javax.tools.FileObject;
|
import javax.tools.FileObject;
|
||||||
import javax.tools.ForwardingJavaFileManager;
|
import javax.tools.ForwardingJavaFileManager;
|
||||||
import javax.tools.JavaCompiler;
|
import javax.tools.JavaCompiler;
|
||||||
import javax.tools.JavaFileManager;
|
import javax.tools.JavaFileManager;
|
||||||
import javax.tools.JavaFileObject;
|
import javax.tools.JavaFileObject;
|
||||||
|
import javax.tools.JavaFileObject.Kind;
|
||||||
|
import javax.tools.JavaFileManager.Location;
|
||||||
import javax.tools.SimpleJavaFileObject;
|
import javax.tools.SimpleJavaFileObject;
|
||||||
import javax.tools.StandardJavaFileManager;
|
import javax.tools.StandardJavaFileManager;
|
||||||
import javax.tools.StandardLocation;
|
import javax.tools.StandardLocation;
|
||||||
|
|
||||||
import com.sun.tools.javac.api.JavacTaskImpl;
|
import com.sun.tools.javac.api.JavacTaskImpl;
|
||||||
import com.sun.tools.javac.api.JavacTool;
|
import com.sun.tools.javac.api.JavacTool;
|
||||||
import java.io.IOError;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility methods and classes for writing jtreg tests for
|
* Utility methods and classes for writing jtreg tests for
|
||||||
|
@ -1308,6 +1315,7 @@ public class ToolBox {
|
||||||
private String mainClass;
|
private String mainClass;
|
||||||
private Path baseDir;
|
private Path baseDir;
|
||||||
private List<Path> paths;
|
private List<Path> paths;
|
||||||
|
private Set<FileObject> fileObjects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a task to write jar files, using API mode.
|
* Creates a task to write jar files, using API mode.
|
||||||
|
@ -1315,6 +1323,7 @@ public class ToolBox {
|
||||||
public JarTask() {
|
public JarTask() {
|
||||||
super(Mode.API);
|
super(Mode.API);
|
||||||
paths = Collections.emptyList();
|
paths = Collections.emptyList();
|
||||||
|
fileObjects = new LinkedHashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1391,6 +1400,53 @@ public class ToolBox {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a set of file objects to be written into the jar file, by copying them
|
||||||
|
* from a Location in a JavaFileManager.
|
||||||
|
* The file objects to be written are specified by a series of paths;
|
||||||
|
* each path can be in one of the following forms:
|
||||||
|
* <ul>
|
||||||
|
* <li>The name of a class. For example, java.lang.Object.
|
||||||
|
* In this case, the corresponding .class file will be written to the jar file.
|
||||||
|
* <li>the name of a package followed by {@code .*}. For example, {@code java.lang.*}.
|
||||||
|
* In this case, all the class files in the specified package will be written to
|
||||||
|
* the jar file.
|
||||||
|
* <li>the name of a package followed by {@code .**}. For example, {@code java.lang.**}.
|
||||||
|
* In this case, all the class files in the specified package, and any subpackages
|
||||||
|
* will be written to the jar file.
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param fm the file manager in which to find the file objects
|
||||||
|
* @param l the location in which to find the file objects
|
||||||
|
* @param paths the paths specifying the file objects to be copied
|
||||||
|
* @return this task object
|
||||||
|
* @throws IOException if errors occur while determining the set of file objects
|
||||||
|
*/
|
||||||
|
public JarTask files(JavaFileManager fm, Location l, String... paths)
|
||||||
|
throws IOException {
|
||||||
|
for (String p : paths) {
|
||||||
|
if (p.endsWith(".**"))
|
||||||
|
addPackage(fm, l, p.substring(0, p.length() - 3), true);
|
||||||
|
else if (p.endsWith(".*"))
|
||||||
|
addPackage(fm, l, p.substring(0, p.length() - 2), false);
|
||||||
|
else
|
||||||
|
addFile(fm, l, p);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addPackage(JavaFileManager fm, Location l, String pkg, boolean recurse)
|
||||||
|
throws IOException {
|
||||||
|
for (JavaFileObject fo : fm.list(l, pkg, EnumSet.allOf(JavaFileObject.Kind.class), recurse)) {
|
||||||
|
fileObjects.add(fo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addFile(JavaFileManager fm, Location l, String path) throws IOException {
|
||||||
|
JavaFileObject fo = fm.getJavaFileForInput(l, path, Kind.CLASS);
|
||||||
|
fileObjects.add(fo);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides limited jar command-like functionality.
|
* Provides limited jar command-like functionality.
|
||||||
* The supported commands are:
|
* The supported commands are:
|
||||||
|
@ -1464,42 +1520,19 @@ public class ToolBox {
|
||||||
StreamOutput sysOut = new StreamOutput(System.out, System::setOut);
|
StreamOutput sysOut = new StreamOutput(System.out, System::setOut);
|
||||||
StreamOutput sysErr = new StreamOutput(System.err, System::setErr);
|
StreamOutput sysErr = new StreamOutput(System.err, System::setErr);
|
||||||
|
|
||||||
int rc;
|
|
||||||
Map<OutputKind, String> outputMap = new HashMap<>();
|
Map<OutputKind, String> outputMap = new HashMap<>();
|
||||||
|
|
||||||
try (OutputStream os = Files.newOutputStream(jar);
|
try (OutputStream os = Files.newOutputStream(jar);
|
||||||
JarOutputStream jos = openJar(os, m)) {
|
JarOutputStream jos = openJar(os, m)) {
|
||||||
Path base = (baseDir == null) ? currDir : baseDir;
|
writeFiles(jos);
|
||||||
for (Path path: paths) {
|
writeFileObjects(jos);
|
||||||
Files.walkFileTree(base.resolve(path), new SimpleFileVisitor<Path>() {
|
|
||||||
@Override
|
|
||||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
|
|
||||||
try {
|
|
||||||
String p = base.relativize(file)
|
|
||||||
.normalize()
|
|
||||||
.toString()
|
|
||||||
.replace(File.separatorChar, '/');
|
|
||||||
JarEntry e = new JarEntry(p);
|
|
||||||
jos.putNextEntry(e);
|
|
||||||
jos.write(Files.readAllBytes(file));
|
|
||||||
jos.closeEntry();
|
|
||||||
return FileVisitResult.CONTINUE;
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.err.println("Error adding " + file + " to jar file: " + e);
|
error("Exception while opening " + jar, e);
|
||||||
return FileVisitResult.TERMINATE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
rc = 0;
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.err.println("Error opening " + jar + ": " + e);
|
|
||||||
rc = 1;
|
|
||||||
} finally {
|
} finally {
|
||||||
outputMap.put(OutputKind.STDOUT, sysOut.close());
|
outputMap.put(OutputKind.STDOUT, sysOut.close());
|
||||||
outputMap.put(OutputKind.STDERR, sysErr.close());
|
outputMap.put(OutputKind.STDERR, sysErr.close());
|
||||||
}
|
}
|
||||||
return checkExit(new Result(this, rc, outputMap));
|
return checkExit(new Result(this, (errors == 0) ? 0 : 1, outputMap));
|
||||||
}
|
}
|
||||||
|
|
||||||
private JarOutputStream openJar(OutputStream os, Manifest m) throws IOException {
|
private JarOutputStream openJar(OutputStream os, Manifest m) throws IOException {
|
||||||
|
@ -1512,6 +1545,79 @@ public class ToolBox {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void writeFiles(JarOutputStream jos) throws IOException {
|
||||||
|
Path base = (baseDir == null) ? currDir : baseDir;
|
||||||
|
for (Path path : paths) {
|
||||||
|
Files.walkFileTree(base.resolve(path), new SimpleFileVisitor<Path>() {
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
|
||||||
|
try {
|
||||||
|
String p = base.relativize(file)
|
||||||
|
.normalize()
|
||||||
|
.toString()
|
||||||
|
.replace(File.separatorChar, '/');
|
||||||
|
JarEntry e = new JarEntry(p);
|
||||||
|
jos.putNextEntry(e);
|
||||||
|
try {
|
||||||
|
jos.write(Files.readAllBytes(file));
|
||||||
|
} finally {
|
||||||
|
jos.closeEntry();
|
||||||
|
}
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
} catch (IOException e) {
|
||||||
|
error("Exception while adding " + file + " to jar file", e);
|
||||||
|
return FileVisitResult.TERMINATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeFileObjects(JarOutputStream jos) throws IOException {
|
||||||
|
for (FileObject fo : fileObjects) {
|
||||||
|
String p = guessPath(fo);
|
||||||
|
JarEntry e = new JarEntry(p);
|
||||||
|
jos.putNextEntry(e);
|
||||||
|
try {
|
||||||
|
byte[] buf = new byte[1024];
|
||||||
|
try (BufferedInputStream in = new BufferedInputStream(fo.openInputStream())) {
|
||||||
|
int n;
|
||||||
|
while ((n = in.read(buf)) > 0)
|
||||||
|
jos.write(buf, 0, n);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
error("Exception while adding " + fo.getName() + " to jar file", ex);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
jos.closeEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A jar: URL is of the form jar:URL!/entry where URL is a URL for the .jar file itself.
|
||||||
|
* In Symbol files (i.e. ct.sym) the underlying entry is prefixed META-INF/sym/<base>.
|
||||||
|
*/
|
||||||
|
private final Pattern jarEntry = Pattern.compile(".*!/(?:META-INF/sym/[^/]+/)?(.*)");
|
||||||
|
|
||||||
|
private String guessPath(FileObject fo) {
|
||||||
|
URI u = fo.toUri();
|
||||||
|
switch (u.getScheme()) {
|
||||||
|
case "jar":
|
||||||
|
Matcher m = jarEntry.matcher(u.getSchemeSpecificPart());
|
||||||
|
if (m.matches()) {
|
||||||
|
return m.group(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException(fo.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void error(String message, Throwable t) {
|
||||||
|
out.println("Error: " + message + ": " + t);
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue