< 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 >