--- old/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java 2017-01-11 15:23:20.000000000 -0800 +++ new/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java 2017-01-11 15:23:20.000000000 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,6 @@ import java.lang.module.ModuleDescriptor.Requires; import java.lang.module.ModuleDescriptor.Version; import java.lang.module.ResolutionException; -import java.lang.module.ResolvedModule; import java.net.URI; import java.nio.file.FileSystems; import java.nio.file.FileVisitOption; @@ -58,13 +57,10 @@ import java.nio.file.StandardCopyOption; import java.nio.file.attribute.BasicFileAttributes; import java.text.MessageFormat; -import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; -import java.util.Deque; -import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; @@ -101,6 +97,7 @@ import jdk.internal.joptsimple.ValueConverter; import jdk.internal.loader.ResourceHelper; import jdk.internal.module.ModuleHashes; +import jdk.internal.module.ModuleHashesBuilder; import jdk.internal.module.ModuleInfo; import jdk.internal.module.ModuleInfoExtender; import jdk.internal.module.ModulePath; @@ -789,33 +786,37 @@ * Compute and record hashes */ private class Hasher { - final ModuleFinder moduleFinder; + final ModuleHashesBuilder hashesBuilder; final Map moduleNameToPath; final Set modules; - final Configuration configuration; final boolean dryrun = options.dryrun; Hasher(ModuleFinder finder) { - this.moduleFinder = finder; // Determine the modules that matches the pattern {@code modulesToHash} - this.modules = moduleFinder.findAll().stream() + this.modules = finder.findAll().stream() .map(mref -> mref.descriptor().name()) .filter(mn -> options.modulesToHash.matcher(mn).find()) .collect(Collectors.toSet()); // a map from a module name to Path of the packaged module - this.moduleNameToPath = moduleFinder.findAll().stream() + this.moduleNameToPath = finder.findAll().stream() .map(mref -> mref.descriptor().name()) - .collect(Collectors.toMap(Function.identity(), mn -> moduleToPath(mn))); + .filter(modules::contains) + .collect(Collectors.toMap(Function.identity(), mn -> moduleToPath(finder, mn))); // get a resolved module graph Configuration config = null; try { config = Configuration.empty() - .resolveRequires(ModuleFinder.ofSystem(), moduleFinder, modules); + .resolveRequires(ModuleFinder.ofSystem(), finder, modules); } catch (ResolutionException e) { warning("warn.module.resolution.fail", e.getMessage()); } - this.configuration = config; + + // ModuleHashesBuilder is constructed with the moduleNameToPath arguments + // so that creating java.base.jmod will compute the hash from this + // explicit path rather than the location from the resolved module + this.hashesBuilder = config != null + ? new ModuleHashesBuilder(config, moduleNameToPath) : null; } /** @@ -829,67 +830,30 @@ * to record the hashes. */ boolean run() { - if (configuration == null) + if (hashesBuilder == null) return false; - // transposed graph containing the the packaged modules and - // its transitive dependences matching --hash-modules - Map> graph = new HashMap<>(); - for (String root : modules) { - Deque deque = new ArrayDeque<>(); - deque.add(root); - Set visited = new HashSet<>(); - while (!deque.isEmpty()) { - String mn = deque.pop(); - if (!visited.contains(mn)) { - visited.add(mn); - - if (modules.contains(mn)) - graph.computeIfAbsent(mn, _k -> new HashSet<>()); - - ResolvedModule resolvedModule = configuration.findModule(mn).get(); - for (ResolvedModule dm : resolvedModule.reads()) { - String name = dm.name(); - if (!visited.contains(name)) { - deque.push(name); - } - - // reverse edge - if (modules.contains(name) && modules.contains(mn)) { - graph.computeIfAbsent(name, _k -> new HashSet<>()).add(mn); - } - } - } - } - } - - if (dryrun) + if (dryrun) { out.println("Dry run:"); + } - // each node in a transposed graph is a matching packaged module - // in which the hash of the modules that depend upon it is recorded - graph.entrySet().stream() - .filter(e -> !e.getValue().isEmpty()) - .forEach(e -> { - String mn = e.getKey(); - Map modulesForHash = e.getValue().stream() - .collect(Collectors.toMap(Function.identity(), - moduleNameToPath::get)); - ModuleHashes hashes = ModuleHashes.generate(modulesForHash, "SHA-256"); - if (dryrun) { - out.format("%s%n", mn); - hashes.names().stream() - .sorted() - .forEach(name -> out.format(" hashes %s %s %s%n", - name, hashes.algorithm(), hashes.hashFor(name))); - } else { - try { - updateModuleInfo(mn, hashes); - } catch (IOException ex) { - throw new UncheckedIOException(ex); - } + hashesBuilder.computeHashes(modules).entrySet().forEach(e -> { + String mn = e.getKey(); + ModuleHashes hashes = e.getValue(); + if (dryrun) { + out.format("%s%n", mn); + hashes.names().stream() + .sorted() + .forEach(name -> out.format(" hashes %s %s %s%n", + name, hashes.algorithm(), toHex(hashes.hashFor(name)))); + } else { + try { + updateModuleInfo(mn, hashes); + } catch (IOException ex) { + throw new UncheckedIOException(ex); } - }); + } + }); return true; } @@ -900,81 +864,10 @@ * module directly or indirectly. */ ModuleHashes computeHashes(String name) { - if (configuration == null) + if (hashesBuilder == null) return null; - // the transposed graph includes all modules in the resolved graph - Map> graph = transpose(); - - // find the modules that transitively depend upon the specified name - Deque deque = new ArrayDeque<>(); - deque.add(name); - Set mods = visitNodes(graph, deque); - - // filter modules matching the pattern specified --hash-modules - // as well as itself as the jmod file is being generated - Map modulesForHash = mods.stream() - .filter(mn -> !mn.equals(name) && modules.contains(mn)) - .collect(Collectors.toMap(Function.identity(), moduleNameToPath::get)); - - if (modulesForHash.isEmpty()) - return null; - - return ModuleHashes.generate(modulesForHash, "SHA-256"); - } - - /** - * Returns all nodes traversed from the given roots. - */ - private Set visitNodes(Map> graph, - Deque roots) { - Set visited = new HashSet<>(); - while (!roots.isEmpty()) { - String mn = roots.pop(); - if (!visited.contains(mn)) { - visited.add(mn); - // the given roots may not be part of the graph - if (graph.containsKey(mn)) { - for (String dm : graph.get(mn)) { - if (!visited.contains(dm)) { - roots.push(dm); - } - } - } - } - } - return visited; - } - - /** - * Returns a transposed graph from the resolved module graph. - */ - private Map> transpose() { - Map> transposedGraph = new HashMap<>(); - Deque deque = new ArrayDeque<>(modules); - - Set visited = new HashSet<>(); - while (!deque.isEmpty()) { - String mn = deque.pop(); - if (!visited.contains(mn)) { - visited.add(mn); - - transposedGraph.computeIfAbsent(mn, _k -> new HashSet<>()); - - ResolvedModule resolvedModule = configuration.findModule(mn).get(); - for (ResolvedModule dm : resolvedModule.reads()) { - String name = dm.name(); - if (!visited.contains(name)) { - deque.push(name); - } - - // reverse edge - transposedGraph.computeIfAbsent(name, _k -> new HashSet<>()) - .add(mn); - } - } - } - return transposedGraph; + return hashesBuilder.computeHashes(Set.of(name)).get(name); } /** @@ -1074,7 +967,7 @@ } } - private Path moduleToPath(String name) { + private Path moduleToPath(ModuleFinder moduleFinder, String name) { ModuleReference mref = moduleFinder.find(name).orElseThrow( () -> new InternalError("Selected module " + name + " not on module path"));