--- /dev/null 2019-11-13 18:19:03.000000000 -0500 +++ new/src/jdk.incubator.jpackage/windows/classes/jdk/incubator/jpackage/internal/WixTool.java 2019-11-13 18:18:59.598322000 -0500 @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2019, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.incubator.jpackage.internal; + +import java.io.IOException; +import java.nio.file.*; +import java.text.MessageFormat; +import java.util.*; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * WiX tool. + */ +public enum WixTool { + Candle, Light; + + static final class ToolInfo { + ToolInfo(Path path, String version) { + this.path = path; + this.version = new DottedVersion(version); + } + + final Path path; + final DottedVersion version; + } + + static Map toolset() throws ConfigException { + Map toolset = new HashMap<>(); + for (var tool : values()) { + toolset.put(tool, tool.find()); + } + return toolset; + } + + ToolInfo find() throws ConfigException { + final Path toolFileName = IOUtils.addSuffix( + Path.of(name().toLowerCase()), ".exe"); + + String[] version = new String[1]; + ConfigException reason = createToolValidator(toolFileName, version).get(); + if (version[0] != null) { + if (reason == null) { + // Found in PATH. + return new ToolInfo(toolFileName, version[0]); + } + + // Found in PATH, but something went wrong. + throw reason; + } + + for (var dir : findWixInstallDirs()) { + Path path = dir.resolve(toolFileName); + if (path.toFile().exists()) { + reason = createToolValidator(path, version).get(); + if (reason != null) { + throw reason; + } + return new ToolInfo(path, version[0]); + } + } + + throw reason; + } + + private static Supplier createToolValidator(Path toolPath, + String[] versionCtnr) { + return new ToolValidator(toolPath) + .setCommandLine("/?") + .setMinimalVersion(MINIMAL_VERSION) + .setToolNotFoundErrorHandler( + (name, ex) -> new ConfigException( + I18N.getString("error.no-wix-tools"), + I18N.getString("error.no-wix-tools.advice"))) + .setToolOldVersionErrorHandler( + (name, version) -> new ConfigException( + MessageFormat.format(I18N.getString( + "message.wrong-tool-version"), name, + version, MINIMAL_VERSION), + I18N.getString("error.no-wix-tools.advice"))) + .setVersionParser(output -> { + versionCtnr[0] = ""; + String firstLineOfOutput = output.findFirst().orElse(""); + int separatorIdx = firstLineOfOutput.lastIndexOf(' '); + if (separatorIdx == -1) { + return null; + } + versionCtnr[0] = firstLineOfOutput.substring(separatorIdx + 1); + return versionCtnr[0]; + })::validate; + } + + private final static DottedVersion MINIMAL_VERSION = DottedVersion.lazy("3.0"); + + static Path getSystemDir(String envVar, String knownDir) { + return Optional + .ofNullable(getEnvVariableAsPath(envVar)) + .orElseGet(() -> Optional + .ofNullable(getEnvVariableAsPath("SystemDrive")) + .orElseGet(() -> Path.of("C:")).resolve(knownDir)); + } + + private static Path getEnvVariableAsPath(String envVar) { + String path = System.getenv(envVar); + if (path != null) { + try { + return Path.of(path); + } catch (InvalidPathException ex) { + Log.error(MessageFormat.format(I18N.getString( + "error.invalid-envvar"), envVar)); + } + } + return null; + } + + private static List findWixInstallDirs() { + PathMatcher wixInstallDirMatcher = FileSystems.getDefault().getPathMatcher( + "glob:WiX Toolset v*"); + + Path programFiles = getSystemDir("ProgramFiles", "\\Program Files"); + Path programFilesX86 = getSystemDir("ProgramFiles(x86)", + "\\Program Files (x86)"); + + // Returns list of WiX install directories ordered by WiX version number. + // Newer versions go first. + return Stream.of(programFiles, programFilesX86).map(path -> { + List result; + try (var paths = Files.walk(path, 1)) { + result = paths.collect(Collectors.toList()); + } catch (IOException ex) { + Log.verbose(ex); + result = Collections.emptyList(); + } + return result; + }).flatMap(List::stream) + .filter(path -> wixInstallDirMatcher.matches(path.getFileName())) + .sorted(Comparator.comparing(Path::getFileName).reversed()) + .map(path -> path.resolve("bin")) + .collect(Collectors.toList()); + } +}