test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java
branchJDK-8200758-branch
changeset 58648 3bf53ffa9ae7
parent 58416 f09bf58c1f17
child 58888 d802578912f3
--- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java	Wed Oct 16 09:57:23 2019 -0400
+++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java	Wed Oct 16 10:32:08 2019 -0400
@@ -22,11 +22,70 @@
  */
 package jdk.jpackage.test;
 
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.List;
 import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathFactory;
+import jdk.jpackage.test.Functional.ThrowingConsumer;
+import jdk.jpackage.test.Functional.ThrowingSupplier;
+import org.xml.sax.SAXException;
 
 public class MacHelper {
 
+    public static void withExplodedDmg(JPackageCommand cmd,
+            ThrowingConsumer<Path> consumer) {
+        cmd.verifyIsOfType(PackageType.MAC_DMG);
+
+        var plist = readPList(new Executor()
+                .setExecutable("/usr/bin/hdiutil")
+                .dumpOutput()
+                .addArguments("attach", cmd.outputBundle().toString(), "-plist")
+                .executeAndGetOutput());
+
+        final Path mountPoint = Path.of(plist.queryValue("mount-point"));
+        try {
+            Path dmgImage = mountPoint.resolve(cmd.name() + ".app");
+            TKit.trace(String.format("Exploded [%s] in [%s] directory",
+                    cmd.outputBundle(), dmgImage));
+            ThrowingConsumer.toConsumer(consumer).accept(dmgImage);
+        } finally {
+            new Executor()
+                    .setExecutable("/usr/bin/hdiutil")
+                    .addArgument("detach").addArgument(mountPoint)
+                    .execute().assertExitCodeIsZero();
+        }
+    }
+
+    public static PListWrapper readPListFromAppImage(Path appImage) {
+        return readPList(appImage.resolve("Contents/Info.plist"));
+    }
+
+    public static PListWrapper readPList(Path path) {
+        TKit.assertReadableFileExists(path);
+        return ThrowingSupplier.toSupplier(() -> readPList(Files.readAllLines(
+                path))).get();
+    }
+
+    public static PListWrapper readPList(List<String> lines) {
+        return readPList(lines.stream());
+    }
+
+    public static PListWrapper readPList(Stream<String> lines) {
+        return ThrowingSupplier.toSupplier(() -> new PListWrapper(lines.collect(
+                Collectors.joining()))).get();
+    }
+
     static String getBundleName(JPackageCommand cmd) {
         cmd.verifyIsOfType(PackageType.MAC);
         return String.format("%s-%s%s", getPackageName(cmd), cmd.version(),
@@ -45,6 +104,35 @@
                 () -> cmd.name());
     }
 
+    public static final class PListWrapper {
+        public String queryValue(String keyName) {
+            XPath xPath = XPathFactory.newInstance().newXPath();
+            // Query for the value of <string> element preceding <key> element
+            // with value equal to `keyName`
+            String query = String.format(
+                    "//string[preceding-sibling::key = \"%s\"][1]", keyName);
+            return ThrowingSupplier.toSupplier(() -> (String) xPath.evaluate(
+                    query, doc, XPathConstants.STRING)).get();
+        }
+
+        PListWrapper(String xml) throws ParserConfigurationException,
+                SAXException, IOException {
+            doc = createDocumentBuilder().parse(new ByteArrayInputStream(
+                    xml.getBytes(StandardCharsets.UTF_8)));
+        }
+
+        private static DocumentBuilder createDocumentBuilder() throws
+                ParserConfigurationException {
+            DocumentBuilderFactory dbf = DocumentBuilderFactory.newDefaultInstance();
+            dbf.setFeature(
+                    "http://apache.org/xml/features/nonvalidating/load-external-dtd",
+                    false);
+            return dbf.newDocumentBuilder();
+        }
+
+        private final org.w3c.dom.Document doc;
+    }
+
     static final Set<Path> CRITICAL_RUNTIME_FILES = Set.of(Path.of(
             "Contents/Home/lib/server/libjvm.dylib"));