--- a/src/jdk.jpackager/macosx/classes/jdk/jpackager/internal/mac/MacPkgBundler.java Wed Nov 21 13:53:17 2018 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,612 +0,0 @@
-/*
- * Copyright (c) 2014, 2018, 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.jpackager.internal.mac;
-
-import jdk.jpackager.internal.BundlerParamInfo;
-import jdk.jpackager.internal.StandardBundlerParam;
-import jdk.jpackager.internal.Log;
-import jdk.jpackager.internal.ConfigException;
-import jdk.jpackager.internal.IOUtils;
-import jdk.jpackager.internal.Platform;
-import jdk.jpackager.internal.RelativeFileSet;
-import jdk.jpackager.internal.UnsupportedPlatformException;
-import jdk.jpackager.internal.resources.mac.MacResources;
-import jdk.jpackager.internal.builders.mac.MacAppImageBuilder;
-import jdk.jpackager.internal.Arguments;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.io.Writer;
-import java.net.URLEncoder;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.ResourceBundle;
-
-import static jdk.jpackager.internal.StandardBundlerParam.*;
-import static
- jdk.jpackager.internal.mac.MacBaseInstallerBundler.SIGNING_KEYCHAIN;
-import static
- jdk.jpackager.internal.mac.MacBaseInstallerBundler.SIGNING_KEY_USER;
-
-public class MacPkgBundler extends MacBaseInstallerBundler {
-
- private static final ResourceBundle I18N = ResourceBundle.getBundle(
- "jdk.jpackager.internal.resources.mac.MacPkgBundler");
-
- public final static String MAC_BUNDLER_PREFIX =
- BUNDLER_PREFIX + "macosx" + File.separator;
-
- private static final String DEFAULT_BACKGROUND_IMAGE = "background_pkg.png";
-
- private static final String TEMPLATE_PREINSTALL_SCRIPT =
- "preinstall.template";
- private static final String TEMPLATE_POSTINSTALL_SCRIPT =
- "postinstall.template";
-
- private static final BundlerParamInfo<File> PACKAGES_ROOT =
- new StandardBundlerParam<>(
- I18N.getString("param.packages-root.name"),
- I18N.getString("param.packages-root.description"),
- "mac.pkg.packagesRoot",
- File.class,
- params -> {
- File packagesRoot =
- new File(BUILD_ROOT.fetchFrom(params), "packages");
- packagesRoot.mkdirs();
- return packagesRoot;
- },
- (s, p) -> new File(s));
-
-
- protected final BundlerParamInfo<File> SCRIPTS_DIR =
- new StandardBundlerParam<>(
- I18N.getString("param.scripts-dir.name"),
- I18N.getString("param.scripts-dir.description"),
- "mac.pkg.scriptsDir",
- File.class,
- params -> {
- File scriptsDir =
- new File(CONFIG_ROOT.fetchFrom(params), "scripts");
- scriptsDir.mkdirs();
- return scriptsDir;
- },
- (s, p) -> new File(s));
-
- public static final
- BundlerParamInfo<String> DEVELOPER_ID_INSTALLER_SIGNING_KEY =
- new StandardBundlerParam<>(
- I18N.getString("param.signing-key-developer-id-installer.name"),
- I18N.getString(
- "param.signing-key-developer-id-installer.description"),
- "mac.signing-key-developer-id-installer",
- String.class,
- params -> {
- String result = MacBaseInstallerBundler.findKey(
- "Developer ID Installer: "
- + SIGNING_KEY_USER.fetchFrom(params),
- SIGNING_KEYCHAIN.fetchFrom(params),
- VERBOSE.fetchFrom(params));
- if (result != null) {
- MacCertificate certificate = new MacCertificate(
- result, VERBOSE.fetchFrom(params));
-
- if (!certificate.isValid()) {
- Log.error(MessageFormat.format(
- I18N.getString("error.certificate.expired"),
- result));
- }
- }
-
- return result;
- },
- (s, p) -> s);
-
- public static final BundlerParamInfo<String> MAC_INSTALL_DIR =
- new StandardBundlerParam<>(
- I18N.getString("param.mac-install-dir.name"),
- I18N.getString("param.mac-install-dir.description"),
- "mac-install-dir",
- String.class,
- params -> {
- String dir = INSTALL_DIR.fetchFrom(params);
- return (dir != null) ? dir : "/Applications";
- },
- (s, p) -> s
- );
-
- public static final BundlerParamInfo<String> INSTALLER_SUFFIX =
- new StandardBundlerParam<> (
- I18N.getString("param.installer-suffix.name"),
- I18N.getString("param.installer-suffix.description"),
- "mac.pkg.installerName.suffix",
- String.class,
- params -> "",
- (s, p) -> s);
-
- public MacPkgBundler() {
- super();
- baseResourceLoader = MacResources.class;
- }
-
- public File bundle(Map<String, ? super Object> params, File outdir) {
- Log.verbose(MessageFormat.format(I18N.getString("message.building-pkg"),
- APP_NAME.fetchFrom(params)));
- if (!outdir.isDirectory() && !outdir.mkdirs()) {
- throw new RuntimeException(MessageFormat.format(
- I18N.getString("error.cannot-create-output-dir"),
- outdir.getAbsolutePath()));
- }
- if (!outdir.canWrite()) {
- throw new RuntimeException(MessageFormat.format(
- I18N.getString("error.cannot-write-to-output-dir"),
- outdir.getAbsolutePath()));
- }
-
- File appImageDir = null;
- try {
- appImageDir = prepareAppBundle(params, false);
-
- if (appImageDir != null && prepareConfigFiles(params)) {
-
- File configScript = getConfig_Script(params);
- if (configScript.exists()) {
- Log.verbose(MessageFormat.format(I18N.getString(
- "message.running-script"),
- configScript.getAbsolutePath()));
- IOUtils.run("bash", configScript, false);
- }
-
- return createPKG(params, outdir, appImageDir);
- }
- return null;
- } catch (IOException ex) {
- Log.verbose(ex);
- return null;
- } finally {
- try {
- if (appImageDir != null &&
- PREDEFINED_APP_IMAGE.fetchFrom(params) == null &&
- (PREDEFINED_RUNTIME_IMAGE.fetchFrom(params) == null ||
- !Arguments.CREATE_JRE_INSTALLER.fetchFrom(params)) &&
- !Log.isDebug() &&
- !Log.isVerbose()) {
- IOUtils.deleteRecursive(appImageDir);
- } else if (appImageDir != null) {
- Log.verbose(MessageFormat.format(I18N.getString(
- "message.intermediate-image-location"),
- appImageDir.getAbsolutePath()));
- }
-
- // cleanup
- cleanupConfigFiles(params);
- } catch (IOException ex) {
- Log.debug(ex);
- // noinspection ReturnInsideFinallyBlock
- return null;
- }
- }
- }
-
- private File getPackages_AppPackage(Map<String, ? super Object> params) {
- return new File(PACKAGES_ROOT.fetchFrom(params),
- APP_FS_NAME.fetchFrom(params) + "-app.pkg");
- }
-
- private File getPackages_DaemonPackage(Map<String, ? super Object> params) {
- return new File(PACKAGES_ROOT.fetchFrom(params),
- APP_FS_NAME.fetchFrom(params) + "-daemon.pkg");
- }
-
- private void cleanupPackagesFiles(Map<String, ? super Object> params) {
- if (Log.isDebug() || Log.isVerbose()) {
- return;
- }
-
- if (getPackages_AppPackage(params) != null) {
- getPackages_AppPackage(params).delete();
- }
- if (getPackages_DaemonPackage(params) != null) {
- getPackages_DaemonPackage(params).delete();
- }
- }
-
- private File getConfig_DistributionXMLFile(
- Map<String, ? super Object> params) {
- return new File(CONFIG_ROOT.fetchFrom(params), "distribution.dist");
- }
-
- private File getConfig_BackgroundImage(Map<String, ? super Object> params) {
- return new File(CONFIG_ROOT.fetchFrom(params),
- APP_NAME.fetchFrom(params) + "-background.png");
- }
-
- private File getScripts_PreinstallFile(Map<String, ? super Object> params) {
- return new File(SCRIPTS_DIR.fetchFrom(params), "preinstall");
- }
-
- private File getScripts_PostinstallFile(
- Map<String, ? super Object> params) {
- return new File(SCRIPTS_DIR.fetchFrom(params), "postinstall");
- }
-
- private void cleanupConfigFiles(Map<String, ? super Object> params) {
- if (Log.isDebug() || Log.isVerbose()) {
- return;
- }
-
- if (getConfig_DistributionXMLFile(params) != null) {
- getConfig_DistributionXMLFile(params).delete();
- }
- if (getConfig_BackgroundImage(params) != null) {
- getConfig_BackgroundImage(params).delete();
- }
- }
-
- private String getAppIdentifier(Map<String, ? super Object> params) {
- return IDENTIFIER.fetchFrom(params);
- }
-
- private String getDaemonIdentifier(Map<String, ? super Object> params) {
- return IDENTIFIER.fetchFrom(params) + ".daemon";
- }
-
- private void preparePackageScripts(Map<String, ? super Object> params)
- throws IOException {
- Log.verbose(I18N.getString("message.preparing-scripts"));
-
- Map<String, String> data = new HashMap<>();
-
- data.put("DEPLOY_DAEMON_IDENTIFIER", getDaemonIdentifier(params));
- data.put("DEPLOY_LAUNCHD_PLIST_FILE",
- IDENTIFIER.fetchFrom(params).toLowerCase() + ".launchd.plist");
-
- Writer w = new BufferedWriter(
- new FileWriter(getScripts_PreinstallFile(params)));
- String content = preprocessTextResource(MAC_BUNDLER_PREFIX
- + getScripts_PreinstallFile(params).getName(),
- I18N.getString("resource.pkg-preinstall-script"),
- TEMPLATE_PREINSTALL_SCRIPT,
- data,
- VERBOSE.fetchFrom(params),
- DROP_IN_RESOURCES_ROOT.fetchFrom(params));
- w.write(content);
- w.close();
- getScripts_PreinstallFile(params).setExecutable(true, false);
-
- w = new BufferedWriter(
- new FileWriter(getScripts_PostinstallFile(params)));
- content = preprocessTextResource(MAC_BUNDLER_PREFIX
- + getScripts_PostinstallFile(params).getName(),
- I18N.getString("resource.pkg-postinstall-script"),
- TEMPLATE_POSTINSTALL_SCRIPT,
- data,
- VERBOSE.fetchFrom(params),
- DROP_IN_RESOURCES_ROOT.fetchFrom(params));
- w.write(content);
- w.close();
- getScripts_PostinstallFile(params).setExecutable(true, false);
- }
-
- private void prepareDistributionXMLFile(Map<String, ? super Object> params)
- throws IOException {
- File f = getConfig_DistributionXMLFile(params);
-
- Log.verbose(MessageFormat.format(I18N.getString(
- "message.preparing-distribution-dist"), f.getAbsolutePath()));
-
- PrintStream out = new PrintStream(f);
-
- out.println(
- "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>");
- out.println("<installer-gui-script minSpecVersion=\"1\">");
-
- out.println("<title>" + APP_NAME.fetchFrom(params) + "</title>");
- out.println("<background" + " file=\""
- + getConfig_BackgroundImage(params).getName()
- + "\""
- + " mime-type=\"image/png\""
- + " alignment=\"bottomleft\" "
- + " scaling=\"none\""
- + "/>");
-
- if (!LICENSE_FILE.fetchFrom(params).isEmpty()) {
- File licFile = null;
-
- List<String> licFiles = LICENSE_FILE.fetchFrom(params);
- if (licFiles.isEmpty()) {
- return;
- }
- String licFileStr = licFiles.get(0);
-
- for (RelativeFileSet rfs : APP_RESOURCES_LIST.fetchFrom(params)) {
- if (rfs.contains(licFileStr)) {
- licFile = new File(rfs.getBaseDirectory(), licFileStr);
- break;
- }
- }
-
- // this is NPE protection, validate should have caught it's absence
- // so we don't complain or throw an error
- if (licFile != null) {
- out.println("<license"
- + " file=\"" + licFile.getAbsolutePath() + "\""
- + " mime-type=\"text/rtf\""
- + "/>");
- }
- }
-
- /*
- * Note that the content of the distribution file
- * below is generated by productbuild --synthesize
- */
-
- String appId = getAppIdentifier(params);
- String daemonId = getDaemonIdentifier(params);
-
- out.println("<pkg-ref id=\"" + appId + "\"/>");
-
- out.println("<options customize=\"never\" require-scripts=\"false\"/>");
- out.println("<choices-outline>");
- out.println(" <line choice=\"default\">");
- out.println(" <line choice=\"" + appId + "\"/>");
- out.println(" </line>");
- out.println("</choices-outline>");
- out.println("<choice id=\"default\"/>");
- out.println("<choice id=\"" + appId + "\" visible=\"false\">");
- out.println(" <pkg-ref id=\"" + appId + "\"/>");
- out.println("</choice>");
- out.println("<pkg-ref id=\"" + appId + "\" version=\""
- + VERSION.fetchFrom(params) + "\" onConclusion=\"none\">"
- + URLEncoder.encode(getPackages_AppPackage(params).getName(),
- "UTF-8") + "</pkg-ref>");
-
- out.println("</installer-gui-script>");
-
- out.close();
- }
-
- private boolean prepareConfigFiles(Map<String, ? super Object> params)
- throws IOException {
- File imageTarget = getConfig_BackgroundImage(params);
- fetchResource(MacAppBundler.MAC_BUNDLER_PREFIX + imageTarget.getName(),
- I18N.getString("resource.pkg-background-image"),
- DEFAULT_BACKGROUND_IMAGE,
- imageTarget,
- VERBOSE.fetchFrom(params),
- DROP_IN_RESOURCES_ROOT.fetchFrom(params));
-
- prepareDistributionXMLFile(params);
-
- fetchResource(MacAppBundler.MAC_BUNDLER_PREFIX
- + getConfig_Script(params).getName(),
- I18N.getString("resource.post-install-script"),
- (String) null,
- getConfig_Script(params),
- VERBOSE.fetchFrom(params),
- DROP_IN_RESOURCES_ROOT.fetchFrom(params));
-
- return true;
- }
-
- // name of post-image script
- private File getConfig_Script(Map<String, ? super Object> params) {
- return new File(CONFIG_ROOT.fetchFrom(params),
- APP_NAME.fetchFrom(params) + "-post-image.sh");
- }
-
- private File createPKG(Map<String, ? super Object> params,
- File outdir, File appLocation) {
- // generic find attempt
- try {
- File appPKG = getPackages_AppPackage(params);
-
- // build application package
- ProcessBuilder pb = new ProcessBuilder("pkgbuild",
- "--component",
- appLocation.toString(),
- "--install-location",
- MAC_INSTALL_DIR.fetchFrom(params),
- appPKG.getAbsolutePath());
- IOUtils.exec(pb, false);
-
- // build final package
- File finalPKG = new File(outdir, INSTALLER_NAME.fetchFrom(params)
- + INSTALLER_SUFFIX.fetchFrom(params)
- + ".pkg");
- outdir.mkdirs();
-
- List<String> commandLine = new ArrayList<>();
- commandLine.add("productbuild");
-
- commandLine.add("--resources");
- commandLine.add(CONFIG_ROOT.fetchFrom(params).getAbsolutePath());
-
- // maybe sign
- if (Optional.ofNullable(MacAppImageBuilder.
- SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.TRUE)) {
- if (Platform.getMajorVersion() > 10 ||
- (Platform.getMajorVersion() == 10 &&
- Platform.getMinorVersion() >= 12)) {
- // we need this for OS X 10.12+
- Log.verbose(I18N.getString("message.signing.pkg"));
- }
-
- String signingIdentity =
- DEVELOPER_ID_INSTALLER_SIGNING_KEY.fetchFrom(params);
- if (signingIdentity != null) {
- commandLine.add("--sign");
- commandLine.add(signingIdentity);
- }
-
- String keychainName = SIGNING_KEYCHAIN.fetchFrom(params);
- if (keychainName != null && !keychainName.isEmpty()) {
- commandLine.add("--keychain");
- commandLine.add(keychainName);
- }
- }
-
- commandLine.add("--distribution");
- commandLine.add(
- getConfig_DistributionXMLFile(params).getAbsolutePath());
- commandLine.add("--package-path");
- commandLine.add(PACKAGES_ROOT.fetchFrom(params).getAbsolutePath());
-
- commandLine.add(finalPKG.getAbsolutePath());
-
- pb = new ProcessBuilder(commandLine);
- IOUtils.exec(pb, false);
-
- return finalPKG;
- } catch (Exception ignored) {
- Log.verbose(ignored);
- return null;
- } finally {
- cleanupPackagesFiles(params);
- cleanupConfigFiles(params);
- }
- }
-
- //////////////////////////////////////////////////////////////////////////
- // Implement Bundler
- //////////////////////////////////////////////////////////////////////////
-
- @Override
- public String getName() {
- return I18N.getString("bundler.name");
- }
-
- @Override
- public String getDescription() {
- return I18N.getString("bundler.description");
- }
-
- @Override
- public String getID() {
- return "pkg";
- }
-
- @Override
- public Collection<BundlerParamInfo<?>> getBundleParameters() {
- Collection<BundlerParamInfo<?>> results = new LinkedHashSet<>();
- results.addAll(MacAppBundler.getAppBundleParameters());
- results.addAll(getPKGBundleParameters());
- return results;
- }
-
- public Collection<BundlerParamInfo<?>> getPKGBundleParameters() {
- Collection<BundlerParamInfo<?>> results = new LinkedHashSet<>();
-
- results.addAll(MacAppBundler.getAppBundleParameters());
- results.addAll(Arrays.asList(
- DEVELOPER_ID_INSTALLER_SIGNING_KEY,
- // IDENTIFIER,
- INSTALLER_SUFFIX,
- LICENSE_FILE,
- // SERVICE_HINT,
- SIGNING_KEYCHAIN));
-
- return results;
- }
-
- @Override
- public boolean validate(Map<String, ? super Object> params)
- throws UnsupportedPlatformException, ConfigException {
- try {
- if (params == null) throw new ConfigException(
- I18N.getString("error.parameters-null"),
- I18N.getString("error.parameters-null.advice"));
-
- // run basic validation to ensure requirements are met
- // we are not interested in return code, only possible exception
- validateAppImageAndBundeler(params);
-
- // validate license file, if used, exists in the proper place
- if (params.containsKey(LICENSE_FILE.getID())) {
- List<RelativeFileSet> appResourcesList =
- APP_RESOURCES_LIST.fetchFrom(params);
- for (String license : LICENSE_FILE.fetchFrom(params)) {
- boolean found = false;
- for (RelativeFileSet appResources : appResourcesList) {
- found = found || appResources.contains(license);
- }
- if (!found) {
- throw new ConfigException(
- I18N.getString("error.license-missing"),
- MessageFormat.format(
- I18N.getString("error.license-missing.advice"),
- license));
- }
- }
- }
-
- // reject explicitly set sign to true and no valid signature key
- if (Optional.ofNullable(MacAppImageBuilder.
- SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.FALSE)) {
- String signingIdentity =
- DEVELOPER_ID_INSTALLER_SIGNING_KEY.fetchFrom(params);
- if (signingIdentity == null) {
- throw new ConfigException(
- I18N.getString("error.explicit-sign-no-cert"),
- I18N.getString(
- "error.explicit-sign-no-cert.advice"));
- }
- }
-
- // hdiutil is always available so there's no need
- // to test for availability.
-
- return true;
- } catch (RuntimeException re) {
- if (re.getCause() instanceof ConfigException) {
- throw (ConfigException) re.getCause();
- } else {
- throw new ConfigException(re);
- }
- }
- }
-
- @Override
- public File execute(
- Map<String, ? super Object> params, File outputParentDir) {
- return bundle(params, outputParentDir);
- }
-
- @Override
- public boolean supported() {
- return Platform.getPlatform() == Platform.MAC;
- }
-
-}