--- /dev/null 2019-11-20 11:02:07.000000000 -0500 +++ new/src/jdk.incubator.jpackage/windows/classes/jdk/incubator/jpackage/internal/WinExeBundler.java 2019-11-20 11:02:05.237599200 -0500 @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2017, 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.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.MessageFormat; +import java.util.*; + +public class WinExeBundler extends AbstractBundler { + + static { + System.loadLibrary("jpackage"); + } + + private static final ResourceBundle I18N = ResourceBundle.getBundle( + "jdk.incubator.jpackage.internal.resources.WinResources"); + + public static final BundlerParamInfo APP_BUNDLER + = new WindowsBundlerParam<>( + "win.app.bundler", + WinAppBundler.class, + params -> new WinAppBundler(), + null); + + public static final BundlerParamInfo EXE_IMAGE_DIR + = new WindowsBundlerParam<>( + "win.exe.imageDir", + File.class, + params -> { + File imagesRoot = IMAGES_ROOT.fetchFrom(params); + if (!imagesRoot.exists()) { + imagesRoot.mkdirs(); + } + return new File(imagesRoot, "win-exe.image"); + }, + (s, p) -> null); + + private final static String EXE_WRAPPER_NAME = "msiwrapper.exe"; + + @Override + public String getName() { + return getString("exe.bundler.name"); + } + + @Override + public String getID() { + return "exe"; + } + + @Override + public String getBundleType() { + return "INSTALLER"; + } + + @Override + public File execute(Map params, + File outputParentDir) throws PackagerException { + return bundle(params, outputParentDir); + } + + @Override + public boolean supported(boolean platformInstaller) { + return msiBundler.supported(platformInstaller); + } + + @Override + public boolean isDefault() { + return true; + } + + @Override + public boolean validate(Map params) + throws ConfigException { + return msiBundler.validate(params); + } + + public File bundle(Map params, File outdir) + throws PackagerException { + + IOUtils.writableOutputDir(outdir.toPath()); + + File exeImageDir = EXE_IMAGE_DIR.fetchFrom(params); + + // Write msi to temporary directory. + File msi = msiBundler.bundle(params, exeImageDir); + + try { + new ScriptRunner() + .setDirectory(msi.toPath().getParent()) + .setResourceCategoryId("resource.post-msi-script") + .setScriptNameSuffix("post-msi") + .setEnvironmentVariable("JpMsiFile", msi.getAbsolutePath().toString()) + .run(params); + + return buildEXE(msi, outdir); + } catch (IOException ex) { + Log.verbose(ex); + throw new PackagerException(ex); + } + } + + private File buildEXE(File msi, File outdir) + throws IOException { + + Log.verbose(MessageFormat.format( + getString("message.outputting-to-location"), + outdir.getAbsolutePath())); + + // Copy template msi wrapper next to msi file + String exePath = msi.getAbsolutePath(); + exePath = exePath.substring(0, exePath.lastIndexOf('.')) + ".exe"; + try (InputStream is = OverridableResource.readDefault(EXE_WRAPPER_NAME)) { + Files.copy(is, Path.of(exePath)); + } + // Embed msi in msi wrapper exe. + embedMSI(exePath, msi.getAbsolutePath()); + + Path dstExePath = Paths.get(outdir.getAbsolutePath(), + Path.of(exePath).getFileName().toString()); + Files.deleteIfExists(dstExePath); + + Files.copy(Path.of(exePath), dstExePath); + + Log.verbose(MessageFormat.format( + getString("message.output-location"), + outdir.getAbsolutePath())); + + return dstExePath.toFile(); + } + + private static String getString(String key) + throws MissingResourceException { + return I18N.getString(key); + } + + private final WinMsiBundler msiBundler = new WinMsiBundler(); + + private static native int embedMSI(String exePath, String msiPath); +}