8230920 : jpackage problems when -input dir contains any files with "cfg" extension.
Reviewed-by: asemenyuk, almatvee
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java Mon Sep 30 15:13:14 2019 -0400
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 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.jpackage.internal;
+
+import java.io.BufferedWriter;
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import static jdk.jpackage.internal.StandardBundlerParam.*;
+
+class AppImageFile {
+
+ // These values will be loaded from AppImage xml file.
+ private final String creatorVersion;
+ private final String creatorPlatform;
+ private final String launcherName;
+ private final List<String> addLauncherNames;
+
+ final static String XML_FILENAME = ".jpackage.xml";
+
+ private final static Map<Platform, String> PLATFORM_LABELS = Map.of(
+ Platform.LINUX, "linux", Platform.WINDOWS, "windows", Platform.MAC,
+ "macOS");
+
+
+ private AppImageFile() {
+ this(null, null, null, null);
+ }
+
+ private AppImageFile(String launcherName, List<String> addLauncherNames,
+ String creatorVersion, String creatorPlatform) {
+ this.launcherName = launcherName;
+ this.addLauncherNames = addLauncherNames;
+ this.creatorVersion = creatorVersion;
+ this.creatorPlatform = creatorPlatform;
+ }
+
+ /**
+ * Would return null to indicate stored command line is invalid.
+ */
+ List<String> getAddLauncherNames() {
+ return addLauncherNames;
+ }
+
+ String getLauncherName() {
+ return launcherName;
+ }
+
+ void verifyCompatible() throws ConfigException {
+ // Just do nohing for now.
+ }
+
+ static void save(Path appImage, Map<String, Object> params)
+ throws IOException {
+ Path xmlFile = appImage.resolve(XML_FILENAME);
+ XMLOutputFactory xmlFactory = XMLOutputFactory.newInstance();
+
+ try (Writer w = new BufferedWriter(new FileWriter(xmlFile.toFile()))) {
+ XMLStreamWriter xml = xmlFactory.createXMLStreamWriter(w);
+
+ xml.writeStartDocument();
+ xml.writeStartElement("jpackage-state");
+ xml.writeAttribute("version", getVersion());
+ xml.writeAttribute("platform", getPlatform());
+
+ xml.writeStartElement("main-launcher");
+ xml.writeCharacters(APP_NAME.fetchFrom(params));
+ xml.writeEndElement();
+
+ List<Map<String, ? super Object>> addLaunchers =
+ ADD_LAUNCHERS.fetchFrom(params);
+
+ for (int i = 0; i < addLaunchers.size(); i++) {
+ Map<String, ? super Object> sl = addLaunchers.get(i);
+ xml.writeStartElement("add-launcher");
+ xml.writeCharacters(APP_NAME.fetchFrom(sl));
+ xml.writeEndElement();
+ }
+
+ xml.writeEndElement();
+ xml.writeEndDocument();
+ xml.flush();
+ xml.close();
+
+ } catch (XMLStreamException ex) {
+ Log.verbose(ex);
+ throw new IOException(ex);
+ }
+ }
+
+ static AppImageFile load(Path appImageDir) throws IOException {
+ try {
+ Path path = appImageDir.resolve(XML_FILENAME);
+ DocumentBuilderFactory dbf =
+ DocumentBuilderFactory.newDefaultInstance();
+ dbf.setFeature(
+ "http://apache.org/xml/features/nonvalidating/load-external-dtd",
+ false);
+ DocumentBuilder b = dbf.newDocumentBuilder();
+ Document doc = b.parse(new FileInputStream(path.toFile()));
+
+ XPath xPath = XPathFactory.newInstance().newXPath();
+
+ String mainLauncher = xpathQueryNullable(xPath,
+ "/jpackage-state/main-launcher/text()", doc);
+ if (mainLauncher == null) {
+ // No main launcher, this is fatal.
+ return new AppImageFile();
+ }
+
+ List<String> addLaunchers = new ArrayList<String>();
+
+ String platform = xpathQueryNullable(xPath,
+ "/jpackage-state/@platform", doc);
+
+ String version = xpathQueryNullable(xPath,
+ "/jpackage-state/@version", doc);
+
+ NodeList launcherNameNodes = (NodeList) xPath.evaluate(
+ "/jpackage-state/add-launcher/text()", doc,
+ XPathConstants.NODESET);
+
+ for (int i = 0; i != launcherNameNodes.getLength(); i++) {
+ addLaunchers.add(launcherNameNodes.item(i).getNodeValue());
+ }
+
+ AppImageFile file = new AppImageFile(
+ mainLauncher, addLaunchers, version, platform);
+ if (!file.isValid()) {
+ file = new AppImageFile();
+ }
+ return file;
+ } catch (ParserConfigurationException | SAXException ex) {
+ // Let caller sort this out
+ throw new IOException(ex);
+ } catch (XPathExpressionException ex) {
+ // This should never happen as XPath expressions should be correct
+ throw new RuntimeException(ex);
+ }
+ }
+
+ private static String xpathQueryNullable(XPath xPath, String xpathExpr,
+ Document xml) throws XPathExpressionException {
+ NodeList nodes = (NodeList) xPath.evaluate(xpathExpr, xml,
+ XPathConstants.NODESET);
+ if (nodes != null && nodes.getLength() > 0) {
+ return nodes.item(0).getNodeValue();
+ }
+ return null;
+ }
+
+ private static String getVersion() {
+ return System.getProperty("java.version");
+ }
+
+ private static String getPlatform() {
+ return PLATFORM_LABELS.get(Platform.getPlatform());
+ }
+
+ private boolean isValid() {
+ if (launcherName == null || launcherName.length() == 0 ||
+ addLauncherNames.indexOf("") != -1) {
+ // Some launchers have empty names. This is invalid.
+ return false;
+ }
+
+ // Add more validation.
+
+ return true;
+ }
+
+}
--- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java Thu Sep 26 10:37:37 2019 -0400
+++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java Mon Sep 30 15:13:14 2019 -0400
@@ -98,61 +98,6 @@
return true;
}
- private static boolean usePredefineAppName(Map<String, ? super Object> p) {
- return (PREDEFINED_APP_IMAGE.fetchFrom(p) != null);
- }
-
- private static String appName;
- synchronized static String getAppName(
- Map<String, ? super Object> p) {
- // If we building from predefined app image, then we should use names
- // from image and not from CLI.
- if (usePredefineAppName(p)) {
- if (appName == null) {
- // Use WIN_APP_IMAGE here, since we already copy pre-defined
- // image to WIN_APP_IMAGE
- File appImageDir = WIN_APP_IMAGE.fetchFrom(p);
-
- File appDir = new File(appImageDir.toString() + "\\app");
- File [] files = appDir.listFiles(
- (File dir, String name) -> name.endsWith(".cfg"));
- if (files == null || files.length == 0) {
- String name = APP_NAME.fetchFrom(p);
- Path exePath = appImageDir.toPath().resolve(name + ".exe");
- Path icoPath = appImageDir.toPath().resolve(name + ".ico");
- if (exePath.toFile().exists() &&
- icoPath.toFile().exists()) {
- return name;
- } else {
- throw new RuntimeException(MessageFormat.format(
- I18N.getString("error.cannot-find-launcher"),
- appImageDir));
- }
- } else {
- appName = files[0].getName();
- int index = appName.indexOf(".");
- if (index != -1) {
- appName = appName.substring(0, index);
- }
- if (files.length > 1) {
- Log.error(MessageFormat.format(I18N.getString(
- "message.multiple-launchers"), appName));
- }
- }
- return appName;
- } else {
- return appName;
- }
- }
-
- return APP_NAME.fetchFrom(p);
- }
-
- public static String getLauncherRelativePath(
- Map<String, ? super Object> p) {
- return getAppName(p) + ".exe";
- }
-
public boolean bundle(Map<String, ? super Object> p, File outputDirectory)
throws PackagerException {
return doBundle(p, outputDirectory, false) != null;
--- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java Thu Sep 26 10:37:37 2019 -0400
+++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java Mon Sep 30 15:13:14 2019 -0400
@@ -542,6 +542,25 @@
basedir.getAbsolutePath().length() + 1);
}
+ private AppImageFile appImageFile = null;
+ private String[] getLaunchers( Map<String, ? super Object> params) {
+ try {
+ ArrayList<String> launchers = new ArrayList<String>();
+ if (appImageFile == null) {
+ appImageFile = AppImageFile.load(
+ WIN_APP_IMAGE.fetchFrom(params).toPath());
+ }
+ launchers.add(appImageFile.getLauncherName());
+ launchers.addAll(appImageFile.getAddLauncherNames());
+ return launchers.toArray(new String[0]);
+ } catch (IOException ioe) {
+ Log.verbose(ioe.getMessage());
+ }
+ String [] launcherNames = new String [1];
+ launcherNames[0] = APP_NAME.fetchFrom(params);
+ return launcherNames;
+ }
+
private void prepareIconsFile(
Map<String, ? super Object> params) throws IOException {
@@ -558,39 +577,29 @@
xml.writeStartDocument();
xml.writeStartElement("Include");
- File launcher = new File(imageRootDir,
- WinAppBundler.getLauncherRelativePath(params));
- if (launcher.exists()) {
- String iconPath = launcher.getAbsolutePath().replace(
- ".exe", ".ico");
- if (MENU_HINT.fetchFrom(params)) {
- xml.writeStartElement("Icon");
- xml.writeAttribute("Id", "StartMenuIcon.exe");
- xml.writeAttribute("SourceFile", iconPath);
- xml.writeEndElement();
- }
- if (SHORTCUT_HINT.fetchFrom(params)) {
- xml.writeStartElement("Icon");
- xml.writeAttribute("Id", "DesktopIcon.exe");
- xml.writeAttribute("SourceFile", iconPath);
- xml.writeEndElement();
- }
+ String[] launcherNames = getLaunchers(params);
+
+ File[] icons = new File[launcherNames.length];
+ for (int i=0; i<launcherNames.length; i++) {
+ icons[i] = new File(imageRootDir, launcherNames[i] + ".ico");
}
- for (int i = 0; i < addLaunchers.size(); i++) {
- Map<String, ? super Object> sl = addLaunchers.get(i);
- if (SHORTCUT_HINT.fetchFrom(sl) || MENU_HINT.fetchFrom(sl)) {
- File addLauncher = new File(imageRootDir,
- WinAppBundler.getLauncherRelativePath(sl));
- String addLauncherPath
- = relativePath(imageRootDir, addLauncher);
- String addLauncherIconPath
- = addLauncherPath.replace(".exe", ".ico");
+ for (int i = 0; i < icons.length; i++) {
+ if (icons[i].exists()) {
+ String iconPath = icons[i].getAbsolutePath();
- xml.writeStartElement("Icon");
- xml.writeAttribute("Id", "Launcher" + i + ".exe");
- xml.writeAttribute("SourceFile", addLauncherIconPath);
- xml.writeEndElement();
+ if (MENU_HINT.fetchFrom(params)) {
+ xml.writeStartElement("Icon");
+ xml.writeAttribute("Id", "StartMenuIcon.exe" + i);
+ xml.writeAttribute("SourceFile", iconPath);
+ xml.writeEndElement();
+ }
+ if (SHORTCUT_HINT.fetchFrom(params)) {
+ xml.writeStartElement("Icon");
+ xml.writeAttribute("Id", "DesktopIcon.exe" + i);
+ xml.writeAttribute("SourceFile", iconPath);
+ xml.writeEndElement();
+ }
}
}
@@ -718,21 +727,16 @@
out.println(prefix + " <RemoveFolder Id=\"RemoveDir"
+ (id++) + "\" On=\"uninstall\" />");
- boolean needRegistryKey = !MSI_SYSTEM_WIDE.fetchFrom(params);
+
File imageRootDir = WIN_APP_IMAGE.fetchFrom(params);
- File launcherFile = new File(imageRootDir,
- WinAppBundler.getLauncherRelativePath(params));
// Find out if we need to use registry. We need it if
// - we doing user level install as file can not serve as KeyPath
// - if we adding shortcut in this component
-
- for (File f: files) {
- boolean isLauncher = f.equals(launcherFile);
- if (isLauncher) {
- needRegistryKey = true;
- }
- }
+ boolean menuShortcut = MENU_HINT.fetchFrom(params);
+ boolean desktopShortcut = SHORTCUT_HINT.fetchFrom(params);
+ boolean needRegistryKey = !MSI_SYSTEM_WIDE.fetchFrom(params) ||
+ menuShortcut || desktopShortcut;
if (needRegistryKey) {
// has to be under HKCU to make WiX happy
@@ -748,21 +752,23 @@
out.println(prefix + " </RegistryKey>");
}
- boolean menuShortcut = MENU_HINT.fetchFrom(params);
- boolean desktopShortcut = SHORTCUT_HINT.fetchFrom(params);
+ String[] launcherNames = getLaunchers(params);
+ File[] launcherFiles = new File[launcherNames.length];
+ for (int i=0; i<launcherNames.length; i++) {
+ launcherFiles[i] =
+ new File(imageRootDir, launcherNames[i] + ".exe");
+ }
Map<String, String> idToFileMap = new TreeMap<>();
boolean launcherSet = false;
for (File f : files) {
- boolean isLauncher = f.equals(launcherFile);
-
- launcherSet = launcherSet || isLauncher;
+ boolean isMainLauncher =
+ launcherFiles.length > 0 && f.equals(launcherFiles[0]);
- boolean doShortcuts =
- isLauncher && (menuShortcut || desktopShortcut);
+ launcherSet = launcherSet || isMainLauncher;
- String thisFileId = isLauncher ? LAUNCHER_ID : ("FileId" + (id++));
+ String thisFileId = isMainLauncher ? LAUNCHER_ID : ("FileId" + (id++));
idToFileMap.put(f.getName(), thisFileId);
out.println(prefix + " <File Id=\"" +
@@ -770,48 +776,46 @@
+ " Name=\"" + f.getName() + "\" "
+ " Source=\"" + relativePath(imageRootDir, f) + "\""
+ " ProcessorArchitecture=\"x64\"" + ">");
- if (doShortcuts && desktopShortcut) {
+ if (isMainLauncher && desktopShortcut) {
out.println(prefix
+ " <Shortcut Id=\"desktopShortcut\" Directory="
+ "\"DesktopFolder\""
- + " Name=\"" + APP_NAME.fetchFrom(params)
+ + " Name=\"" + launcherNames[0]
+ "\" WorkingDirectory=\"INSTALLDIR\""
- + " Advertise=\"no\" Icon=\"DesktopIcon.exe\""
+ + " Advertise=\"no\" Icon=\"DesktopIcon.exe0\""
+ " IconIndex=\"0\" />");
}
- if (doShortcuts && menuShortcut) {
+ if (isMainLauncher && menuShortcut) {
out.println(prefix
+ " <Shortcut Id=\"ExeShortcut\" Directory="
+ "\"ProgramMenuDir\""
- + " Name=\"" + APP_NAME.fetchFrom(params)
- + "\" Advertise=\"no\" Icon=\"StartMenuIcon.exe\""
+ + " Name=\"" + launcherNames[0]
+ + "\" Advertise=\"no\" Icon=\"StartMenuIcon.exe0\""
+ " IconIndex=\"0\" />");
}
- List<Map<String, ? super Object>> addLaunchers =
- ADD_LAUNCHERS.fetchFrom(params);
- for (int i = 0; i < addLaunchers.size(); i++) {
- Map<String, ? super Object> sl = addLaunchers.get(i);
- File addLauncherFile = new File(imageRootDir,
- WinAppBundler.getLauncherRelativePath(sl));
- if (f.equals(addLauncherFile)) {
- if (SHORTCUT_HINT.fetchFrom(sl)) {
+ // any additional launchers
+ for (int index = 1; index < launcherNames.length; index++ ) {
+
+ if (f.equals(launcherFiles[index])) {
+ if (desktopShortcut) {
out.println(prefix
+ " <Shortcut Id=\"desktopShortcut"
- + i + "\" Directory=\"DesktopFolder\""
- + " Name=\"" + APP_NAME.fetchFrom(sl)
+ + index + "\" Directory=\"DesktopFolder\""
+ + " Name=\"" + launcherNames[index]
+ "\" WorkingDirectory=\"INSTALLDIR\""
- + " Advertise=\"no\" Icon=\"Launcher"
- + i + ".exe\" IconIndex=\"0\" />");
+ + " Advertise=\"no\" Icon=\"DesktopIcon.exe"
+ + index + "\""
+ + " IconIndex=\"0\" />");
}
- if (MENU_HINT.fetchFrom(sl)) {
+ if (menuShortcut) {
out.println(prefix
- + " <Shortcut Id=\"ExeShortcut"
- + i + "\" Directory=\"ProgramMenuDir\""
- + " Name=\"" + APP_NAME.fetchFrom(sl)
- + "\" Advertise=\"no\" Icon=\"Launcher"
- + i + ".exe\" IconIndex=\"0\" />");
- // Should we allow different menu groups? Not for now.
+ + " <Shortcut Id=\"ExeShortcut"
+ + index + "\" Directory=\"ProgramMenuDir\""
+ + " Name=\"" + launcherNames[index]
+ + "\" Advertise=\"no\" Icon=\"StartMenuIcon.exe"
+ + index + "\""
+ + " IconIndex=\"0\" />");
}
}
}
--- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsAppImageBuilder.java Thu Sep 26 10:37:37 2019 -0400
+++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsAppImageBuilder.java Mon Sep 30 15:13:14 2019 -0400
@@ -187,6 +187,7 @@
} catch (PackagerException pe) {
throw new RuntimeException(pe);
}
+ AppImageFile.save(root, params);
// create the .exe launchers
createLauncherForEntryPoint(params);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/tools/jpackage/junit/jdk/jpackage/internal/AppImageFileTest.java Mon Sep 30 15:13:14 2019 -0400
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 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.jpackage.internal;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.LinkedHashMap;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.Rule;
+import org.junit.rules.TemporaryFolder;
+
+public class AppImageFileTest {
+
+ @Rule
+ public final TemporaryFolder tempFolder = new TemporaryFolder();
+
+ @Test
+ public void testIdentity() throws IOException {
+ Map<String, ? super Object> params = new LinkedHashMap<>();
+ params.put("name", "Foo");
+ params.put("app-version", "2.3");
+ params.put("description", "Duck is the King");
+ AppImageFile aif = create(params);
+
+ Assert.assertEquals("Foo", aif.getLauncherName());
+ }
+
+ @Test
+ public void testInvalidCommandLine() throws IOException {
+ // Just make sure AppImageFile will tolerate jpackage params that would
+ // never create app image at both load/save phases.
+ // People would edit this file just because they can.
+ // We should be ready to handle curious minds.
+ Map<String, ? super Object> params = new LinkedHashMap<>();
+ params.put("invalidParamName", "randomStringValue");
+ create(params);
+
+ params = new LinkedHashMap<>();
+ params.put("name", "foo");
+ params.put("app-version", "");
+ create(params);
+ }
+
+ @Test
+ public void testInavlidXml() throws IOException {
+ assertInvalid(createFromXml("<foo/>"));
+ assertInvalid(createFromXml("<jpackage-state/>"));
+ assertInvalid(createFromXml(
+ "<jpackage-state>",
+ "<main-launcher></main-launcher>",
+ "</jpackage-state>"));
+ }
+
+ @Test
+ public void testValidXml() throws IOException {
+ Assert.assertEquals("Foo", (createFromXml(
+ "<jpackage-state>",
+ "<main-launcher>Foo</main-launcher>",
+ "</jpackage-state>")).getLauncherName());
+
+ Assert.assertEquals("Foo", (createFromXml(
+ "<jpackage-state>",
+ "<main-launcher>Foo</main-launcher>",
+ "<main-launcher>Bar</main-launcher>",
+ "</jpackage-state>")).getLauncherName());
+
+ var file = createFromXml(
+ "<jpackage-state>",
+ "<main-launcher>Foo</main-launcher>",
+ "<launcher></launcher>",
+ "</jpackage-state>");
+ Assert.assertEquals("Foo", file.getLauncherName());
+ Assert.assertArrayEquals(new String[0],
+ file.getAddLauncherNames().toArray(String[]::new));
+ }
+
+ @Test
+ public void testMainLauncherName() throws IOException {
+ Map<String, ? super Object> params = new LinkedHashMap<>();
+ params.put("name", "Foo");
+ params.put("description", "Duck App Description");
+ AppImageFile aif = create(params);
+
+ Assert.assertEquals("Foo", aif.getLauncherName());
+ }
+
+ @Test
+ public void testAddLauncherNames() throws IOException {
+ }
+
+ private AppImageFile create(Map<String, Object> params) throws IOException {
+ AppImageFile.save(tempFolder.getRoot().toPath(), params);
+ return AppImageFile.load(tempFolder.getRoot().toPath());
+ }
+
+ private void assertInvalid(AppImageFile file) {
+ Assert.assertNull(file.getLauncherName());
+ Assert.assertNull(file.getAddLauncherNames());
+ }
+
+ private AppImageFile createFromXml(String... xmlData) throws IOException {
+ Path directory = tempFolder.getRoot().toPath();
+ Path path = directory.resolve(AppImageFile.XML_FILENAME);
+ path.toFile().mkdirs();
+ Files.delete(path);
+
+ ArrayList<String> data = new ArrayList();
+ data.add("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>");
+ data.addAll(List.of(xmlData));
+
+ Files.write(path, data, StandardOpenOption.CREATE,
+ StandardOpenOption.TRUNCATE_EXISTING);
+
+ AppImageFile image = AppImageFile.load(directory);
+ return image;
+ }
+
+}
--- a/test/jdk/tools/jpackage/junit/junit.java Thu Sep 26 10:37:37 2019 -0400
+++ b/test/jdk/tools/jpackage/junit/junit.java Mon Sep 30 15:13:14 2019 -0400
@@ -1,3 +1,28 @@
+/*
+ * Copyright (c) 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.
+ */
+
/*
* @test
* @summary jpackage unit tests
@@ -6,4 +31,5 @@
* jdk.jpackage.internal.PathGroupTest
* jdk.jpackage.internal.DeployParamsTest
* jdk.jpackage.internal.ApplicationLayoutTest
+ * jdk.jpackage.internal.AppImageFileTest
*/