< prev index next >

src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java

Print this page

        

*** 44,70 **** --- 44,73 ---- import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.nio.file.attribute.PosixFilePermission; + import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Properties; import java.util.Set; + import java.util.stream.Stream; import static java.util.stream.Collectors.*; 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.ResourcePoolModule; + import jdk.tools.jlink.plugin.ResourcePoolModuleView; import jdk.tools.jlink.plugin.PluginException; /** * * Default Image Builder. This builder creates the default runtime image layout.
*** 139,173 **** this.root = root; this.mdir = root.resolve("lib"); Files.createDirectories(mdir); } ! private void storeFiles(Set<String> modules, Properties release) throws IOException { if (release != null) { addModules(release, modules); File r = new File(root.toFile(), "release"); try (FileOutputStream fo = new FileOutputStream(r)) { release.store(fo, null); } } } ! private void addModules(Properties props, Set<String> modules) throws IOException { StringBuilder builder = new StringBuilder(); int i = 0; for (String m : modules) { builder.append(m); ! if (i < modules.size() - 1) { ! builder.append(","); } i++; } props.setProperty("MODULES", quote(builder.toString())); } @Override ! 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"); --- 142,231 ---- this.root = root; this.mdir = root.resolve("lib"); Files.createDirectories(mdir); } ! private void storeFiles(List<String> modules, Properties release) throws IOException { if (release != null) { addModules(release, modules); File r = new File(root.toFile(), "release"); try (FileOutputStream fo = new FileOutputStream(r)) { release.store(fo, null); } } } ! private void addModules(Properties props, List<String> modules) throws IOException { ! int size = modules.size(); StringBuilder builder = new StringBuilder(); int i = 0; for (String m : modules) { builder.append(m); ! if (i < size - 1) { ! builder.append(' '); } i++; } props.setProperty("MODULES", quote(builder.toString())); } + // utility class to (topological) sort the module names + static class ModuleNamesSorter { + // don't create me! + private ModuleNamesSorter() {} + + // return a stream of dependent module names of the given module name + private static Stream<String> dependencies(String modName, ResourcePoolModuleView modView) { + Optional<ResourcePoolModule> mod = modView.findModule(modName); + if (mod.isPresent()) { + return mod.get().descriptor().requires().stream().map(ModuleDescriptor.Requires::name); + } else { + throw new RuntimeException("Missing module: " + modName); + } + } + + // states for module visit + private static enum State { + VISITING, VISITED; + } + + // topological sort helper + private static void tsort(String modName, Map<String, State> state, + ResourcePoolModuleView modView, List<String> ret) { + state.put(modName, State.VISITING); + dependencies(modName, modView).forEach(depModName -> { + State st = state.get(depModName); + if (st == null) { + tsort(depModName, state, modView, ret); + } else if (st == State.VISITING) { + throw new RuntimeException("Cyclic dependency: " + depModName); + } + assert st == State.VISITED; + }); + state.put(modName, State.VISITED); + ret.add(modName); + } + + // entry point to sort module names by topological sort + static List<String> sort(Set<String> rootMods, ResourcePoolModuleView modView) { + Map<String, State> state = new HashMap<>(); + List<String> ret = new ArrayList<>(); + for (String rootMod : rootMods) { + State st = state.get(rootMod); + if (st == null) { + tsort(rootMod, state, modView, ret); + } else if (st == State.VISITING) { + throw new RuntimeException("Cyclic dependency: " + rootMod); + } + assert st == State.VISITED; + } + return ret; + } + } + @Override ! public void storeFiles(Set<String> rootModules, 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");
*** 207,217 **** if (!m.packages().isEmpty()) { modules.add(m.name()); } }); ! storeFiles(modules, release); if (root.getFileSystem().supportedFileAttributeViews() .contains("posix")) { // launchers in the bin directory need execute permission. // On Windows, "bin" also subdirectories containing jvm.dll. --- 265,276 ---- if (!m.packages().isEmpty()) { modules.add(m.name()); } }); ! storeFiles(ModuleNamesSorter.sort( ! rootModules.isEmpty()? modules : rootModules, files.moduleView()), release); if (root.getFileSystem().supportedFileAttributeViews() .contains("posix")) { // launchers in the bin directory need execute permission. // On Windows, "bin" also subdirectories containing jvm.dll.
< prev index next >