--- a/src/jdk.packager/macosx/classes/jdk/packager/internal/mac/MacDmgBundler.java Fri Nov 02 11:34:56 2018 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,576 +0,0 @@
-/*
- * Copyright (c) 2012, 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.packager.internal.mac;
-
-import jdk.packager.internal.*;
-import jdk.packager.internal.IOUtils;
-import jdk.packager.internal.resources.mac.MacResources;
-import jdk.packager.internal.Arguments;
-
-import java.io.*;
-import java.nio.file.Files;
-import java.text.MessageFormat;
-import java.util.*;
-
-import static jdk.packager.internal.StandardBundlerParam.*;
-
-public class MacDmgBundler extends MacBaseInstallerBundler {
-
- private static final ResourceBundle I18N =
- ResourceBundle.getBundle(
- "jdk.packager.internal.resources.mac.MacDmgBundler");
-
- static final String DEFAULT_BACKGROUND_IMAGE="background_dmg.png";
- static final String DEFAULT_DMG_SETUP_SCRIPT="DMGsetup.scpt";
- static final String TEMPLATE_BUNDLE_ICON = "GenericApp.icns";
-
- static final String DEFAULT_LICENSE_PLIST="lic_template.plist";
-
- public static final BundlerParamInfo<String> INSTALLER_SUFFIX =
- new StandardBundlerParam<> (
- I18N.getString("param.installer-suffix.name"),
- I18N.getString("param.installer-suffix.description"),
- "mac.dmg.installerName.suffix",
- String.class,
- params -> "",
- (s, p) -> s);
-
- public MacDmgBundler() {
- super();
- baseResourceLoader = MacResources.class;
- }
-
- public File bundle(Map<String, ? super Object> params, File outdir) {
- Log.info(MessageFormat.format(I18N.getString("message.building-dmg"),
- 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 = APP_IMAGE_BUILD_ROOT.fetchFrom(params);
- try {
- appImageDir.mkdirs();
-
- if (prepareAppBundle(params, true) != null &&
- prepareConfigFiles(params)) {
- File configScript = getConfig_Script(params);
- if (configScript.exists()) {
- Log.info(MessageFormat.format(
- I18N.getString("message.running-script"),
- configScript.getAbsolutePath()));
- IOUtils.run("bash", configScript, false);
- }
-
- return buildDMG(params, outdir);
- }
- 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()) {
- IOUtils.deleteRecursive(appImageDir);
- } else if (appImageDir != null) {
- Log.info(MessageFormat.format(I18N.getString(
- "message.intermediate-image-location"),
- appImageDir.getAbsolutePath()));
- }
-
- //cleanup
- cleanupConfigFiles(params);
- } catch (IOException ex) {
- Log.debug(ex);
- //noinspection ReturnInsideFinallyBlock
- return null;
- }
- }
- }
-
- //remove
- protected void cleanupConfigFiles(Map<String, ? super Object> params) {
- if (getConfig_VolumeBackground(params) != null) {
- getConfig_VolumeBackground(params).delete();
- }
- if (getConfig_VolumeIcon(params) != null) {
- getConfig_VolumeIcon(params).delete();
- }
- if (getConfig_VolumeScript(params) != null) {
- getConfig_VolumeScript(params).delete();
- }
- if (getConfig_Script(params) != null) {
- getConfig_Script(params).delete();
- }
- if (getConfig_LicenseFile(params) != null) {
- getConfig_LicenseFile(params).delete();
- }
- APP_BUNDLER.fetchFrom(params).cleanupConfigFiles(params);
- }
-
- private static final String hdiutil = "/usr/bin/hdiutil";
-
- private void prepareDMGSetupScript(String volumeName,
- Map<String, ? super Object> p) throws IOException {
- File dmgSetup = getConfig_VolumeScript(p);
- Log.verbose(MessageFormat.format(
- I18N.getString("message.preparing-dmg-setup"),
- dmgSetup.getAbsolutePath()));
-
- //prepare config for exe
- Map<String, String> data = new HashMap<>();
- data.put("DEPLOY_ACTUAL_VOLUME_NAME", volumeName);
- data.put("DEPLOY_APPLICATION_NAME", APP_NAME.fetchFrom(p));
-
- data.put("DEPLOY_INSTALL_LOCATION", "(path to desktop folder)");
- data.put("DEPLOY_INSTALL_NAME", "Desktop");
-
- Writer w = new BufferedWriter(new FileWriter(dmgSetup));
- w.write(preprocessTextResource(
- MacAppBundler.MAC_BUNDLER_PREFIX + dmgSetup.getName(),
- I18N.getString("resource.dmg-setup-script"),
- DEFAULT_DMG_SETUP_SCRIPT, data, VERBOSE.fetchFrom(p),
- DROP_IN_RESOURCES_ROOT.fetchFrom(p)));
- w.close();
- }
-
- private File getConfig_VolumeScript(Map<String, ? super Object> params) {
- return new File(CONFIG_ROOT.fetchFrom(params),
- APP_NAME.fetchFrom(params) + "-dmg-setup.scpt");
- }
-
- private File getConfig_VolumeBackground(
- Map<String, ? super Object> params) {
- return new File(CONFIG_ROOT.fetchFrom(params),
- APP_NAME.fetchFrom(params) + "-background.png");
- }
-
- private File getConfig_VolumeIcon(Map<String, ? super Object> params) {
- return new File(CONFIG_ROOT.fetchFrom(params),
- APP_NAME.fetchFrom(params) + "-volume.icns");
- }
-
- private File getConfig_LicenseFile(Map<String, ? super Object> params) {
- return new File(CONFIG_ROOT.fetchFrom(params),
- APP_NAME.fetchFrom(params) + "-license.plist");
- }
-
- private void prepareLicense(Map<String, ? super Object> params) {
- try {
- 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;
- }
- }
-
- if (licFile == null) {
- // this is NPE protection,
- // validate should have already caught it's absence
- Log.error("Licence file is null");
- return;
- }
-
- byte[] licenseContentOriginal = Files.readAllBytes(licFile.toPath());
- String licenseInBase64 =
- Base64.getEncoder().encodeToString(licenseContentOriginal);
-
- Map<String, String> data = new HashMap<>();
- data.put("APPLICATION_LICENSE_TEXT", licenseInBase64);
-
- Writer w = new BufferedWriter(
- new FileWriter(getConfig_LicenseFile(params)));
- w.write(preprocessTextResource(
- MacAppBundler.MAC_BUNDLER_PREFIX
- + getConfig_LicenseFile(params).getName(),
- I18N.getString("resource.license-setup"),
- DEFAULT_LICENSE_PLIST, data, VERBOSE.fetchFrom(params),
- DROP_IN_RESOURCES_ROOT.fetchFrom(params)));
- w.close();
-
- } catch (IOException ex) {
- Log.verbose(ex);
- }
- }
-
- private boolean prepareConfigFiles(Map<String, ? super Object> params)
- throws IOException {
- File bgTarget = getConfig_VolumeBackground(params);
- fetchResource(MacAppBundler.MAC_BUNDLER_PREFIX + bgTarget.getName(),
- I18N.getString("resource.dmg-background"),
- DEFAULT_BACKGROUND_IMAGE,
- bgTarget,
- VERBOSE.fetchFrom(params),
- DROP_IN_RESOURCES_ROOT.fetchFrom(params));
-
- File iconTarget = getConfig_VolumeIcon(params);
- if (MacAppBundler.ICON_ICNS.fetchFrom(params) == null ||
- !MacAppBundler.ICON_ICNS.fetchFrom(params).exists()) {
- fetchResource(
- MacAppBundler.MAC_BUNDLER_PREFIX + iconTarget.getName(),
- I18N.getString("resource.volume-icon"),
- TEMPLATE_BUNDLE_ICON,
- iconTarget,
- VERBOSE.fetchFrom(params),
- DROP_IN_RESOURCES_ROOT.fetchFrom(params));
- } else {
- fetchResource(
- MacAppBundler.MAC_BUNDLER_PREFIX + iconTarget.getName(),
- I18N.getString("resource.volume-icon"),
- MacAppBundler.ICON_ICNS.fetchFrom(params),
- iconTarget,
- VERBOSE.fetchFrom(params),
- DROP_IN_RESOURCES_ROOT.fetchFrom(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));
-
- prepareLicense(params);
-
- // In theory we need to extract name from results of attach command
- // However, this will be a problem for customization as name will
- // possibly change every time and developer will not be able to fix it
- // As we are using tmp dir chance we get "different" name are low =>
- // Use fixed name we used for bundle
- prepareDMGSetupScript(APP_NAME.fetchFrom(params), 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");
- }
-
- // Location of SetFile utility may be different depending on MacOS version
- // We look for several known places and if none of them work will
- // try ot find it
- private String findSetFileUtility() {
- String typicalPaths[] = {"/Developer/Tools/SetFile",
- "/usr/bin/SetFile", "/Developer/usr/bin/SetFile"};
-
- for (String path: typicalPaths) {
- File f = new File(path);
- if (f.exists() && f.canExecute()) {
- return path;
- }
- }
-
- // generic find attempt
- try {
- ProcessBuilder pb = new ProcessBuilder("xcrun", "-find", "SetFile");
- Process p = pb.start();
- InputStreamReader isr = new InputStreamReader(p.getInputStream());
- BufferedReader br = new BufferedReader(isr);
- String lineRead = br.readLine();
- if (lineRead != null) {
- File f = new File(lineRead);
- if (f.exists() && f.canExecute()) {
- return f.getAbsolutePath();
- }
- }
- } catch (IOException ignored) {}
-
- return null;
- }
-
- private File buildDMG(
- Map<String, ? super Object> p, File outdir)
- throws IOException {
- File imagesRoot = IMAGES_ROOT.fetchFrom(p);
- if (!imagesRoot.exists()) imagesRoot.mkdirs();
-
- File protoDMG = new File(imagesRoot, APP_NAME.fetchFrom(p) +"-tmp.dmg");
- File finalDMG = new File(outdir, INSTALLER_NAME.fetchFrom(p)
- + INSTALLER_SUFFIX.fetchFrom(p)
- + ".dmg");
-
- File srcFolder = APP_IMAGE_BUILD_ROOT.fetchFrom(p);
- File predefinedImage = StandardBundlerParam.getPredefinedAppImage(p);
- if (predefinedImage != null) {
- srcFolder = predefinedImage;
- }
-
- Log.verbose(MessageFormat.format(I18N.getString(
- "message.creating-dmg-file"), finalDMG.getAbsolutePath()));
-
- protoDMG.delete();
- if (finalDMG.exists() && !finalDMG.delete()) {
- throw new IOException(MessageFormat.format(I18N.getString(
- "message.dmg-cannot-be-overwritten"),
- finalDMG.getAbsolutePath()));
- }
-
- protoDMG.getParentFile().mkdirs();
- finalDMG.getParentFile().mkdirs();
-
- String hdiUtilVerbosityFlag = Log.isDebug() ? "-verbose" : "-quiet";
-
- // create temp image
- ProcessBuilder pb = new ProcessBuilder(
- hdiutil,
- "create",
- hdiUtilVerbosityFlag,
- "-srcfolder", srcFolder.getAbsolutePath(),
- "-volname", APP_NAME.fetchFrom(p),
- "-ov", protoDMG.getAbsolutePath(),
- "-fs", "HFS+",
- "-format", "UDRW");
- IOUtils.exec(pb, false);
-
- // mount temp image
- pb = new ProcessBuilder(
- hdiutil,
- "attach",
- protoDMG.getAbsolutePath(),
- hdiUtilVerbosityFlag,
- "-mountroot", imagesRoot.getAbsolutePath());
- IOUtils.exec(pb, false);
-
- File mountedRoot =
- new File(imagesRoot.getAbsolutePath(), APP_NAME.fetchFrom(p));
-
- // volume icon
- File volumeIconFile = new File(mountedRoot, ".VolumeIcon.icns");
- IOUtils.copyFile(getConfig_VolumeIcon(p),
- volumeIconFile);
-
- pb = new ProcessBuilder("osascript",
- getConfig_VolumeScript(p).getAbsolutePath());
- IOUtils.exec(pb, false);
-
- // Indicate that we want a custom icon
- // NB: attributes of the root directory are ignored
- // when creating the volume
- // Therefore we have to do this after we mount image
- String setFileUtility = findSetFileUtility();
- if (setFileUtility != null) {
- //can not find utility => keep going without icon
- try {
- volumeIconFile.setWritable(true);
- // The "creator" attribute on a file is a legacy attribute
- // but it seems Finder excepts these bytes to be
- // "icnC" for the volume icon
- // http://endrift.com/blog/2010/06/14/dmg-files-volume-icons-cli
- // (might not work on Mac 10.13 with old XCode)
- pb = new ProcessBuilder(
- setFileUtility,
- "-c", "icnC",
- volumeIconFile.getAbsolutePath());
- IOUtils.exec(pb, false);
- volumeIconFile.setReadOnly();
-
- pb = new ProcessBuilder(
- setFileUtility,
- "-a", "C",
- mountedRoot.getAbsolutePath());
- IOUtils.exec(pb, false);
- } catch (IOException ex) {
- Log.info(ex.getMessage());
- Log.verbose(
- "Cannot enable custom icon using SetFile utility");
- }
- } else {
- Log.verbose(
- "Skip enabling custom icon as SetFile utility is not found");
- }
-
- // Detach the temporary image
- pb = new ProcessBuilder(
- hdiutil,
- "detach",
- hdiUtilVerbosityFlag,
- mountedRoot.getAbsolutePath());
- IOUtils.exec(pb, false);
-
- // Compress it to a new image
- pb = new ProcessBuilder(
- hdiutil,
- "convert",
- protoDMG.getAbsolutePath(),
- hdiUtilVerbosityFlag,
- "-format", "UDZO",
- "-o", finalDMG.getAbsolutePath());
- IOUtils.exec(pb, false);
-
- //add license if needed
- if (getConfig_LicenseFile(p).exists()) {
- //hdiutil unflatten your_image_file.dmg
- pb = new ProcessBuilder(
- hdiutil,
- "unflatten",
- finalDMG.getAbsolutePath()
- );
- IOUtils.exec(pb, false);
-
- //add license
- pb = new ProcessBuilder(
- hdiutil,
- "udifrez",
- finalDMG.getAbsolutePath(),
- "-xml",
- getConfig_LicenseFile(p).getAbsolutePath()
- );
- IOUtils.exec(pb, false);
-
- //hdiutil flatten your_image_file.dmg
- pb = new ProcessBuilder(
- hdiutil,
- "flatten",
- finalDMG.getAbsolutePath()
- );
- IOUtils.exec(pb, false);
-
- }
-
- //Delete the temporary image
- protoDMG.delete();
-
- Log.info(MessageFormat.format(I18N.getString(
- "message.output-to-location"),
- APP_NAME.fetchFrom(p), finalDMG.getAbsolutePath()));
-
- return finalDMG;
- }
-
-
- //////////////////////////////////////////////////////////////////////////
- // 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 "dmg";
- }
-
- @Override
- public Collection<BundlerParamInfo<?>> getBundleParameters() {
- Collection<BundlerParamInfo<?>> results = new LinkedHashSet<>();
- results.addAll(MacAppBundler.getAppBundleParameters());
- results.addAll(getDMGBundleParameters());
- return results;
- }
-
- public Collection<BundlerParamInfo<?>> getDMGBundleParameters() {
- Collection<BundlerParamInfo<?>> results = new LinkedHashSet<>();
-
- results.addAll(MacAppBundler.getAppBundleParameters());
- results.addAll(Arrays.asList(
- INSTALLER_SUFFIX,
- LICENSE_FILE
- ));
-
- 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));
- }
- }
- }
-
- 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;
- }
-}