< prev index next >

src/jdk.incubator.jpackage/macosx/classes/jdk/incubator/jpackage/internal/MacPkgBundler.java

Print this page

        

@@ -21,41 +21,30 @@
  * 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.jpackage.internal;
+package jdk.incubator.jpackage.internal;
 
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.io.PrintWriter;
-import java.io.Writer;
-import java.net.URLEncoder;
+import java.io.*;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 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.jpackage.internal.StandardBundlerParam.*;
-import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN;
-import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEY_USER;
+import java.util.*;
+
+import static jdk.incubator.jpackage.internal.StandardBundlerParam.*;
+import static jdk.incubator.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN;
+import static jdk.incubator.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEY_USER;
+import static jdk.incubator.jpackage.internal.MacAppImageBuilder.MAC_CF_BUNDLE_IDENTIFIER;
+import static jdk.incubator.jpackage.internal.OverridableResource.createResource;
 
 public class MacPkgBundler extends MacBaseInstallerBundler {
 
     private static final ResourceBundle I18N = ResourceBundle.getBundle(
-            "jdk.jpackage.internal.resources.MacResources");
+            "jdk.incubator.jpackage.internal.resources.MacResources");
 
     private static final String DEFAULT_BACKGROUND_IMAGE = "background_pkg.png";
 
     private static final String TEMPLATE_PREINSTALL_SCRIPT =
             "preinstall.template";

@@ -97,12 +86,11 @@
                             "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));
+                        MacCertificate certificate = new MacCertificate(result);
 
                         if (!certificate.isValid()) {
                             Log.error(MessageFormat.format(
                                     I18N.getString("error.certificate.expired"),
                                     result));

@@ -133,33 +121,24 @@
 
     public File bundle(Map<String, ? super Object> params,
             File outdir) throws PackagerException {
         Log.verbose(MessageFormat.format(I18N.getString("message.building-pkg"),
                 APP_NAME.fetchFrom(params)));
-        if (!outdir.isDirectory() && !outdir.mkdirs()) {
-            throw new PackagerException(
-                    "error.cannot-create-output-dir",
-                    outdir.getAbsolutePath());
-        }
-        if (!outdir.canWrite()) {
-            throw new PackagerException(
-                    "error.cannot-write-to-output-dir",
-                    outdir.getAbsolutePath());
-        }
 
-        File appImageDir = null;
+        IOUtils.writableOutputDir(outdir.toPath());
+
         try {
-            appImageDir = prepareAppBundle(params, false);
+            File appImageDir = prepareAppBundle(params);
 
             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);
+                    IOUtils.run("bash", configScript);
                 }
 
                 return createPKG(params, outdir, appImageDir);
             }
             return null;

@@ -172,155 +151,169 @@
     private File getPackages_AppPackage(Map<String, ? super Object> params) {
         return new File(PACKAGES_ROOT.fetchFrom(params),
                 APP_NAME.fetchFrom(params) + "-app.pkg");
     }
 
-    private File getPackages_DaemonPackage(Map<String, ? super Object> params) {
-        return new File(PACKAGES_ROOT.fetchFrom(params),
-                APP_NAME.fetchFrom(params) + "-daemon.pkg");
-    }
-
     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 getConfig_BackgroundImageDarkAqua(Map<String, ? super Object> params) {
+        return new File(CONFIG_ROOT.fetchFrom(params),
+                APP_NAME.fetchFrom(params) + "-background-darkAqua.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 String getAppIdentifier(Map<String, ? super Object> params) {
-        return IDENTIFIER.fetchFrom(params);
-    }
-
-    private String getDaemonIdentifier(Map<String, ? super Object> params) {
-        return IDENTIFIER.fetchFrom(params) + ".daemon";
+        return MAC_CF_BUNDLE_IDENTIFIER.fetchFrom(params);
     }
 
     private void preparePackageScripts(Map<String, ? super Object> params)
             throws IOException {
         Log.verbose(I18N.getString("message.preparing-scripts"));
 
         Map<String, String> data = new HashMap<>();
 
+        Path appLocation = Path.of(MAC_INSTALL_DIR.fetchFrom(params),
+                         APP_NAME.fetchFrom(params) + ".app", "Contents", "app");
+
         data.put("INSTALL_LOCATION", MAC_INSTALL_DIR.fetchFrom(params));
+        data.put("APP_LOCATION", appLocation.toString());
 
-        Writer w = new BufferedWriter(
-                new FileWriter(getScripts_PreinstallFile(params)));
-        String content = preprocessTextResource(
-                getScripts_PreinstallFile(params).getName(),
-                I18N.getString("resource.pkg-preinstall-script"),
-                TEMPLATE_PREINSTALL_SCRIPT,
-                data,
-                VERBOSE.fetchFrom(params),
-                RESOURCE_DIR.fetchFrom(params));
-        w.write(content);
-        w.close();
+        createResource(TEMPLATE_PREINSTALL_SCRIPT, params)
+                .setCategory(I18N.getString("resource.pkg-preinstall-script"))
+                .setSubstitutionData(data)
+                .saveToFile(getScripts_PreinstallFile(params));
         getScripts_PreinstallFile(params).setExecutable(true, false);
 
-        w = new BufferedWriter(
-                new FileWriter(getScripts_PostinstallFile(params)));
-        content = preprocessTextResource(
-                getScripts_PostinstallFile(params).getName(),
-                I18N.getString("resource.pkg-postinstall-script"),
-                TEMPLATE_POSTINSTALL_SCRIPT,
-                data,
-                VERBOSE.fetchFrom(params),
-                RESOURCE_DIR.fetchFrom(params));
-        w.write(content);
-        w.close();
+        createResource(TEMPLATE_POSTINSTALL_SCRIPT, params)
+                .setCategory(I18N.getString("resource.pkg-postinstall-script"))
+                .setSubstitutionData(data)
+                .saveToFile(getScripts_PostinstallFile(params));
         getScripts_PostinstallFile(params).setExecutable(true, false);
     }
 
+    private static String URLEncoding(String pkgName) throws URISyntaxException {
+        URI uri = new URI(null, null, pkgName, null);
+        return uri.toASCIIString();
+    }
+
     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\""
-                + "/>");
+        IOUtils.createXml(f.toPath(), xml -> {
+            xml.writeStartElement("installer-gui-script");
+            xml.writeAttribute("minSpecVersion", "1");
+
+            xml.writeStartElement("title");
+            xml.writeCharacters(APP_NAME.fetchFrom(params));
+            xml.writeEndElement();
+
+            xml.writeStartElement("background");
+            xml.writeAttribute("file", getConfig_BackgroundImage(params).getName());
+            xml.writeAttribute("mime-type", "image/png");
+            xml.writeAttribute("alignment", "bottomleft");
+            xml.writeAttribute("scaling", "none");
+            xml.writeEndElement();
+
+            xml.writeStartElement("background-darkAqua");
+            xml.writeAttribute("file", getConfig_BackgroundImageDarkAqua(params).getName());
+            xml.writeAttribute("mime-type", "image/png");
+            xml.writeAttribute("alignment", "bottomleft");
+            xml.writeAttribute("scaling", "none");
+            xml.writeEndElement();
 
         String licFileStr = LICENSE_FILE.fetchFrom(params);
         if (licFileStr != null) {
             File licFile = new File(licFileStr);
-            out.println("<license"
-                    + " file=\"" + licFile.getAbsolutePath() + "\""
-                    + " mime-type=\"text/rtf\""
-                    + "/>");
+                xml.writeStartElement("license");
+                xml.writeAttribute("file", licFile.getAbsolutePath());
+                xml.writeAttribute("mime-type", "text/rtf");
+                xml.writeEndElement();
         }
 
         /*
          * Note that the content of the distribution file
          * below is generated by productbuild --synthesize
          */
-
         String appId = getAppIdentifier(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>");
+            xml.writeStartElement("pkg-ref");
+            xml.writeAttribute("id", appId);
+            xml.writeEndElement(); // </pkg-ref>
+            xml.writeStartElement("options");
+            xml.writeAttribute("customize", "never");
+            xml.writeAttribute("require-scripts", "false");
+            xml.writeEndElement(); // </options>
+            xml.writeStartElement("choices-outline");
+            xml.writeStartElement("line");
+            xml.writeAttribute("choice", "default");
+            xml.writeStartElement("line");
+            xml.writeAttribute("choice", appId);
+            xml.writeEndElement(); // </line>
+            xml.writeEndElement(); // </line>
+            xml.writeEndElement(); // </choices-outline>
+            xml.writeStartElement("choice");
+            xml.writeAttribute("id", "default");
+            xml.writeEndElement(); // </choice>
+            xml.writeStartElement("choice");
+            xml.writeAttribute("id", appId);
+            xml.writeAttribute("visible", "false");
+            xml.writeStartElement("pkg-ref");
+            xml.writeAttribute("id", appId);
+            xml.writeEndElement(); // </pkg-ref>
+            xml.writeEndElement(); // </choice>
+            xml.writeStartElement("pkg-ref");
+            xml.writeAttribute("id", appId);
+            xml.writeAttribute("version", VERSION.fetchFrom(params));
+            xml.writeAttribute("onConclusion", "none");
+            try {
+                xml.writeCharacters(URLEncoding(
+                        getPackages_AppPackage(params).getName()));
+            } catch (URISyntaxException ex) {
+                throw new IOException(ex);
+            }
+            xml.writeEndElement(); // </pkg-ref>
 
-        out.close();
+            xml.writeEndElement(); // </installer-gui-script>
+        });
     }
 
     private boolean prepareConfigFiles(Map<String, ? super Object> params)
             throws IOException {
-        File imageTarget = getConfig_BackgroundImage(params);
-        fetchResource(imageTarget.getName(),
-                I18N.getString("resource.pkg-background-image"),
-                DEFAULT_BACKGROUND_IMAGE,
-                imageTarget,
-                VERBOSE.fetchFrom(params),
-                RESOURCE_DIR.fetchFrom(params));
+
+        createResource(DEFAULT_BACKGROUND_IMAGE, params)
+                .setCategory(I18N.getString("resource.pkg-background-image"))
+                .saveToFile(getConfig_BackgroundImage(params));
+
+        createResource(DEFAULT_BACKGROUND_IMAGE, params)
+                .setCategory(I18N.getString("resource.pkg-background-image"))
+                .saveToFile(getConfig_BackgroundImageDarkAqua(params));
 
         prepareDistributionXMLFile(params);
 
-        fetchResource(getConfig_Script(params).getName(),
-                I18N.getString("resource.post-install-script"),
-                (String) null,
-                getConfig_Script(params),
-                VERBOSE.fetchFrom(params),
-                RESOURCE_DIR.fetchFrom(params));
+        createResource(null, params)
+                .setCategory(I18N.getString("resource.post-install-script"))
+                .saveToFile(getConfig_Script(params));
 
         return true;
     }
 
     // name of post-image script

@@ -330,27 +323,28 @@
     }
 
     private void patchCPLFile(File cpl) throws IOException {
         String cplData = Files.readString(cpl.toPath());
         String[] lines = cplData.split("\n");
-        try (PrintWriter out = new PrintWriter(new BufferedWriter(
-                new FileWriter(cpl)))) {
-            boolean skip = false; // Used to skip Java.runtime bundle, since
+        try (PrintWriter out = new PrintWriter(Files.newBufferedWriter(
+                cpl.toPath()))) {
+            int skip = 0;
+            // Used to skip Java.runtime bundle, since
             // pkgbuild with --root will find two bundles app and Java runtime.
             // We cannot generate component proprty list when using
             // --component argument.
             for (int i = 0; i < lines.length; i++) {
                 if (lines[i].trim().equals("<key>BundleIsRelocatable</key>")) {
                     out.println(lines[i]);
                     out.println("<false/>");
                     i++;
                 } else if (lines[i].trim().equals("<key>ChildBundles</key>")) {
-                    skip = true;
-                } else if (skip && lines[i].trim().equals("</array>")) {
-                    skip = false;
+                    ++skip;
+                } else if ((skip > 0) && lines[i].trim().equals("</array>")) {
+                    --skip;
                 } else {
-                    if (!skip) {
+                    if (skip == 0) {
                         out.println(lines[i]);
                     }
                 }
             }
         }

@@ -410,11 +404,11 @@
                     "--install-location",
                     MAC_INSTALL_DIR.fetchFrom(params),
                     "--analyze",
                     cpl.getAbsolutePath());
 
-            IOUtils.exec(pb, false);
+            IOUtils.exec(pb);
 
             patchCPLFile(cpl);
 
             preparePackageScripts(params);
 

@@ -427,11 +421,11 @@
                     "--component-plist",
                     cpl.getAbsolutePath(),
                     "--scripts",
                     SCRIPTS_DIR.fetchFrom(params).getAbsolutePath(),
                     appPKG.getAbsolutePath());
-            IOUtils.exec(pb, false);
+            IOUtils.exec(pb);
 
             // build final package
             File finalPKG = new File(outdir, INSTALLER_NAME.fetchFrom(params)
                     + INSTALLER_SUFFIX.fetchFrom(params)
                     + ".pkg");

@@ -474,11 +468,11 @@
             commandLine.add(PACKAGES_ROOT.fetchFrom(params).getAbsolutePath());
 
             commandLine.add(finalPKG.getAbsolutePath());
 
             pb = new ProcessBuilder(commandLine);
-            IOUtils.exec(pb, false);
+            IOUtils.exec(pb);
 
             return finalPKG;
         } catch (Exception ignored) {
             Log.verbose(ignored);
             return null;

@@ -493,54 +487,31 @@
     public String getName() {
         return I18N.getString("pkg.bundler.name");
     }
 
     @Override
-    public String getDescription() {
-        return I18N.getString("pkg.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 {
+            throws ConfigException {
         try {
-            if (params == null) throw new ConfigException(
-                    I18N.getString("error.parameters-null"),
-                    I18N.getString("error.parameters-null.advice"));
+            Objects.requireNonNull(params);
 
             // run basic validation to ensure requirements are met
             // we are not interested in return code, only possible exception
             validateAppImageAndBundeler(params);
 
+            if (MAC_CF_BUNDLE_IDENTIFIER.fetchFrom(params) == null) {
+                throw new ConfigException(
+                        I18N.getString("message.app-image-requires-identifier"),
+                        I18N.getString(
+                            "message.app-image-requires-identifier.advice"));
+            }
+
             // 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);

@@ -571,9 +542,14 @@
         return bundle(params, outputParentDir);
     }
 
     @Override
     public boolean supported(boolean runtimeInstaller) {
-        return Platform.getPlatform() == Platform.MAC;
+        return true;
+    }
+
+    @Override
+    public boolean isDefault() {
+        return false;
     }
 
 }
< prev index next >