< prev index next >
jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java
Print this page
*** 32,44 ****
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
- import java.io.UncheckedIOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.lang.module.ModuleDescriptor;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
--- 32,44 ----
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
+ import java.io.UncheckedIOException;
import java.io.Writer;
import java.lang.module.ModuleDescriptor;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
*** 60,77 ****
--- 60,85 ----
import jdk.tools.jlink.internal.BasicImageWriter;
import jdk.tools.jlink.internal.plugins.FileCopierPlugin.SymImageFile;
import jdk.tools.jlink.internal.ExecutableImage;
import jdk.tools.jlink.plugin.ResourcePool;
import jdk.tools.jlink.plugin.ResourcePoolEntry;
+ import jdk.tools.jlink.plugin.ResourcePoolEntry.Type;
import jdk.tools.jlink.plugin.ResourcePoolModule;
import jdk.tools.jlink.plugin.PluginException;
/**
*
* Default Image Builder. This builder creates the default runtime image layout.
*/
public final class DefaultImageBuilder implements ImageBuilder {
+ // Top-level directory names in a modular runtime image
+ public static final String BIN_DIRNAME = "bin";
+ public static final String CONF_DIRNAME = "conf";
+ public static final String INCLUDE_DIRNAME = "include";
+ public static final String LIB_DIRNAME = "lib";
+ public static final String LEGAL_DIRNAME = "legal";
+ public static final String MAN_DIRNAME = "man";
/**
* The default java executable Image.
*/
static final class DefaultExecutableImage implements ExecutableImage {
*** 168,178 ****
public void storeFiles(ResourcePool files) {
try {
// populate release properties up-front. targetOsName
// field is assigned from there and used elsewhere.
Properties release = releaseProperties(files);
! Path bin = root.resolve("bin");
// check any duplicated resource files
Map<Path, Set<String>> duplicates = new HashMap<>();
files.entries()
.filter(f -> f.type() != ResourcePoolEntry.Type.CLASS_OR_RESOURCE)
--- 176,186 ----
public void storeFiles(ResourcePool files) {
try {
// populate release properties up-front. targetOsName
// field is assigned from there and used elsewhere.
Properties release = releaseProperties(files);
! Path bin = root.resolve(BIN_DIRNAME);
// check any duplicated resource files
Map<Path, Set<String>> duplicates = new HashMap<>();
files.entries()
.filter(f -> f.type() != ResourcePoolEntry.Type.CLASS_OR_RESOURCE)
*** 220,236 ****
return attrs.isRegularFile() && !path.toString().endsWith(".diz");
}).forEach(this::setExecutable);
}
// jspawnhelper is in lib or lib/<arch>
! Path lib = root.resolve("lib");
if (Files.isDirectory(lib)) {
Files.find(lib, 2, (path, attrs) -> {
return path.getFileName().toString().equals("jspawnhelper")
|| path.getFileName().toString().equals("jexec");
}).forEach(this::setExecutable);
}
}
// If native files are stripped completely, <root>/bin dir won't exist!
// So, don't bother generating launcher scripts.
if (Files.isDirectory(bin)) {
--- 228,252 ----
return attrs.isRegularFile() && !path.toString().endsWith(".diz");
}).forEach(this::setExecutable);
}
// jspawnhelper is in lib or lib/<arch>
! Path lib = root.resolve(LIB_DIRNAME);
if (Files.isDirectory(lib)) {
Files.find(lib, 2, (path, attrs) -> {
return path.getFileName().toString().equals("jspawnhelper")
|| path.getFileName().toString().equals("jexec");
}).forEach(this::setExecutable);
}
+
+ // read-only legal notices/license files
+ Path legal = root.resolve(LEGAL_DIRNAME);
+ if (Files.isDirectory(legal)) {
+ Files.find(legal, 2, (path, attrs) -> {
+ return attrs.isRegularFile();
+ }).forEach(this::setReadOnly);
+ }
}
// If native files are stripped completely, <root>/bin dir won't exist!
// So, don't bother generating launcher scripts.
if (Files.isDirectory(bin)) {
*** 329,339 ****
.supportedFileAttributeViews().contains("posix")) {
setExecutable(cmd);
}
// generate .bat file for Windows
if (isWindows()) {
! Path bat = root.resolve("bin").resolve(module + ".bat");
sb = new StringBuilder();
sb.append("@echo off")
.append("\r\n");
sb.append("set JLINK_VM_OPTIONS=")
.append("\r\n");
--- 345,355 ----
.supportedFileAttributeViews().contains("posix")) {
setExecutable(cmd);
}
// generate .bat file for Windows
if (isWindows()) {
! Path bat = root.resolve(BIN_DIRNAME).resolve(module + ".bat");
sb = new StringBuilder();
sb.append("@echo off")
.append("\r\n");
sb.append("set JLINK_VM_OPTIONS=")
.append("\r\n");
*** 373,382 ****
--- 389,399 ----
if (entry.type() == ResourcePoolEntry.Type.CLASS_OR_RESOURCE)
throw new IllegalArgumentException("invalid type: " + entry);
String module = "/" + entry.moduleName() + "/";
String filename = entry.path().substring(module.length());
+
// Remove radical native|config|...
return filename.substring(filename.indexOf('/') + 1);
}
/**
*** 386,412 ****
switch (entry.type()) {
case NATIVE_LIB:
String filename = entryToFileName(entry);
return Paths.get(nativeDir(filename), filename);
case NATIVE_CMD:
! return Paths.get("bin", entryToFileName(entry));
case CONFIG:
! return Paths.get("conf", entryToFileName(entry));
case HEADER_FILE:
! return Paths.get("include", entryToFileName(entry));
case MAN_PAGE:
! return Paths.get("man", entryToFileName(entry));
case TOP:
return Paths.get(entryToFileName(entry));
case OTHER:
return Paths.get("other", entryToFileName(entry));
default:
throw new IllegalArgumentException("invalid type: " + entry);
}
}
private void accept(ResourcePoolEntry file) throws IOException {
try (InputStream in = file.content()) {
switch (file.type()) {
case NATIVE_LIB:
Path dest = root.resolve(entryToImagePath(file));
writeEntry(in, dest);
--- 403,435 ----
switch (entry.type()) {
case NATIVE_LIB:
String filename = entryToFileName(entry);
return Paths.get(nativeDir(filename), filename);
case NATIVE_CMD:
! return Paths.get(BIN_DIRNAME, entryToFileName(entry));
case CONFIG:
! return Paths.get(CONF_DIRNAME, entryToFileName(entry));
case HEADER_FILE:
! return Paths.get(INCLUDE_DIRNAME, entryToFileName(entry));
case MAN_PAGE:
! return Paths.get(MAN_DIRNAME, entryToFileName(entry));
! case LEGAL_NOTICE:
! return Paths.get(LEGAL_DIRNAME, entryToFileName(entry));
case TOP:
return Paths.get(entryToFileName(entry));
case OTHER:
return Paths.get("other", entryToFileName(entry));
default:
throw new IllegalArgumentException("invalid type: " + entry);
}
}
private void accept(ResourcePoolEntry file) throws IOException {
+ if (file.linkedTarget() != null && file.type() != Type.LEGAL_NOTICE) {
+ throw new UnsupportedOperationException("symbolic link not implemented: " + file);
+ }
+
try (InputStream in = file.content()) {
switch (file.type()) {
case NATIVE_LIB:
Path dest = root.resolve(entryToImagePath(file));
writeEntry(in, dest);
*** 415,432 ****
Path p = root.resolve(entryToImagePath(file));
writeEntry(in, p);
p.toFile().setExecutable(true);
break;
case CONFIG:
- writeEntry(in, root.resolve(entryToImagePath(file)));
- break;
case HEADER_FILE:
- writeEntry(in, root.resolve(entryToImagePath(file)));
- break;
case MAN_PAGE:
writeEntry(in, root.resolve(entryToImagePath(file)));
break;
case TOP:
break;
case OTHER:
String filename = entryToFileName(file);
if (file instanceof SymImageFile) {
--- 438,461 ----
Path p = root.resolve(entryToImagePath(file));
writeEntry(in, p);
p.toFile().setExecutable(true);
break;
case CONFIG:
case HEADER_FILE:
case MAN_PAGE:
writeEntry(in, root.resolve(entryToImagePath(file)));
break;
+ case LEGAL_NOTICE:
+ Path source = entryToImagePath(file);
+ if (file.linkedTarget() == null) {
+ writeEntry(in, root.resolve(source));
+ } else {
+ Path target = entryToImagePath(file.linkedTarget());
+ Path relPath = source.getParent().relativize(target);
+ writeSymLinkEntry(root.resolve(source), relPath);
+ }
+ break;
case TOP:
break;
case OTHER:
String filename = entryToFileName(file);
if (file instanceof SymImageFile) {
*** 459,478 ****
Objects.requireNonNull(target);
Files.createDirectories(Objects.requireNonNull(dstFile.getParent()));
Files.createLink(dstFile, target);
}
private String nativeDir(String filename) {
if (isWindows()) {
if (filename.endsWith(".dll") || filename.endsWith(".diz")
|| filename.endsWith(".pdb") || filename.endsWith(".map")) {
! return "bin";
} else {
! return "lib";
}
} else {
! return "lib";
}
}
private boolean isWindows() {
return targetOsName.startsWith("Windows");
--- 488,527 ----
Objects.requireNonNull(target);
Files.createDirectories(Objects.requireNonNull(dstFile.getParent()));
Files.createLink(dstFile, target);
}
+ /*
+ * Create a symbolic link to the given target if the target platform
+ * supports symbolic link; otherwise, it will create a tiny file
+ * to contain the path to the target.
+ */
+ private void writeSymLinkEntry(Path dstFile, Path target) throws IOException {
+ Objects.requireNonNull(dstFile);
+ Objects.requireNonNull(target);
+ Files.createDirectories(Objects.requireNonNull(dstFile.getParent()));
+ if (!isWindows() && root.getFileSystem()
+ .supportedFileAttributeViews()
+ .contains("posix")) {
+ Files.createSymbolicLink(dstFile, target);
+ } else {
+ try (BufferedWriter writer = Files.newBufferedWriter(dstFile)) {
+ writer.write(String.format("Please see %s%n", target.toString()));
+ }
+ }
+ }
+
private String nativeDir(String filename) {
if (isWindows()) {
if (filename.endsWith(".dll") || filename.endsWith(".diz")
|| filename.endsWith(".pdb") || filename.endsWith(".map")) {
! return BIN_DIRNAME;
} else {
! return LIB_DIRNAME;
}
} else {
! return LIB_DIRNAME;
}
}
private boolean isWindows() {
return targetOsName.startsWith("Windows");
*** 491,500 ****
--- 540,564 ----
} catch (IOException ioe) {
throw new UncheckedIOException(ioe);
}
}
+ /**
+ * chmod ugo-w file
+ */
+ private void setReadOnly(Path file) {
+ try {
+ Set<PosixFilePermission> perms = Files.getPosixFilePermissions(file);
+ perms.remove(PosixFilePermission.OWNER_WRITE);
+ perms.remove(PosixFilePermission.GROUP_WRITE);
+ perms.remove(PosixFilePermission.OTHERS_WRITE);
+ Files.setPosixFilePermissions(file, perms);
+ } catch (IOException ioe) {
+ throw new UncheckedIOException(ioe);
+ }
+ }
+
private static void createUtf8File(File file, String content) throws IOException {
try (OutputStream fout = new FileOutputStream(file);
Writer output = new OutputStreamWriter(fout, "UTF-8")) {
output.write(content);
}
*** 507,517 ****
// This is experimental, we should get rid-off the scripts in a near future
private static void patchScripts(ExecutableImage img, List<String> args) throws IOException {
Objects.requireNonNull(args);
if (!args.isEmpty()) {
! Files.find(img.getHome().resolve("bin"), 2, (path, attrs) -> {
return img.getModules().contains(path.getFileName().toString());
}).forEach((p) -> {
try {
String pattern = "JLINK_VM_OPTIONS=";
byte[] content = Files.readAllBytes(p);
--- 571,581 ----
// This is experimental, we should get rid-off the scripts in a near future
private static void patchScripts(ExecutableImage img, List<String> args) throws IOException {
Objects.requireNonNull(args);
if (!args.isEmpty()) {
! Files.find(img.getHome().resolve(BIN_DIRNAME), 2, (path, attrs) -> {
return img.getModules().contains(path.getFileName().toString());
}).forEach((p) -> {
try {
String pattern = "JLINK_VM_OPTIONS=";
byte[] content = Files.readAllBytes(p);
*** 539,549 ****
});
}
}
public static ExecutableImage getExecutableImage(Path root) {
! Path binDir = root.resolve("bin");
if (Files.exists(binDir.resolve("java")) ||
Files.exists(binDir.resolve("java.exe"))) {
return new DefaultExecutableImage(root, retrieveModules(root));
}
return null;
--- 603,613 ----
});
}
}
public static ExecutableImage getExecutableImage(Path root) {
! Path binDir = root.resolve(BIN_DIRNAME);
if (Files.exists(binDir.resolve("java")) ||
Files.exists(binDir.resolve("java.exe"))) {
return new DefaultExecutableImage(root, retrieveModules(root));
}
return null;
< prev index next >