8225249 : LinuxDebBundler and LinuxRpmBundler should share more code
Submitted-by: asemenyuk
Reviewed-by: herrick, almatvee
--- a/make/CompileJavaModules.gmk Mon Sep 16 19:24:32 2019 -0400
+++ b/make/CompileJavaModules.gmk Tue Sep 24 13:41:16 2019 -0400
@@ -380,8 +380,8 @@
################################################################################
-jdk.jpackage_COPY += .gif .png .txt .spec .script .prerm .preinst .postrm .postinst .list \
- .desktop .copyright .control .plist .template .icns .scpt .entitlements .wxs .wxl .iss .ico .bmp
+jdk.jpackage_COPY += .gif .png .txt .spec .script .prerm .preinst .postrm .postinst .list .sh \
+ .desktop .copyright .control .plist .template .icns .scpt .entitlements .wxs .wxl .ico .bmp
jdk.jpackage_CLEAN += .properties
--- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java Mon Sep 16 19:24:32 2019 -0400
+++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java Tue Sep 24 13:41:16 2019 -0400
@@ -110,12 +110,6 @@
return true;
}
- // it is static for the sake of sharing with "installer" bundlers
- // that may skip calls to validate/bundle in this class!
- static File getRootDir(File outDir, Map<String, ? super Object> params) {
- return new File(outDir, APP_NAME.fetchFrom(params));
- }
-
File doBundle(Map<String, ? super Object> params, File outputDirectory,
boolean dependentTask) throws PackagerException {
if (StandardBundlerParam.isRuntimeInstaller(params)) {
--- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java Mon Sep 16 19:24:32 2019 -0400
+++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppImageBuilder.java Tue Sep 24 13:41:16 2019 -0400
@@ -46,7 +46,7 @@
"jdk.jpackage.internal.resources.LinuxResources");
private static final String LIBRARY_NAME = "libapplauncher.so";
- private final static String DEFAULT_ICON = "java32.png";
+ final static String DEFAULT_ICON = "java32.png";
private final Path root;
private final Path appDir;
@@ -106,19 +106,7 @@
Files.copy(in, dstFile);
}
- // it is static for the sake of sharing with "installer" bundlers
- // that may skip calls to validate/bundle in this class!
- public static File getRootDir(File outDir,
- Map<String, ? super Object> params) {
- return new File(outDir, APP_NAME.fetchFrom(params));
- }
-
- public static String getLauncherRelativePath(
- Map<String, ? super Object> params) {
- return "bin" + File.separator + APP_NAME.fetchFrom(params);
- }
-
- private static String getLauncherName(Map<String, ? super Object> params) {
+ public static String getLauncherName(Map<String, ? super Object> params) {
return APP_NAME.fetchFrom(params);
}
--- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java Mon Sep 16 19:24:32 2019 -0400
+++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java Tue Sep 24 13:41:16 2019 -0400
@@ -25,15 +25,12 @@
package jdk.jpackage.internal;
-import javax.imageio.ImageIO;
-import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
-import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.PosixFilePermission;
@@ -44,21 +41,9 @@
import java.util.stream.Stream;
import static jdk.jpackage.internal.StandardBundlerParam.*;
-import static jdk.jpackage.internal.LinuxAppBundler.ICON_PNG;
-import static jdk.jpackage.internal.LinuxAppBundler.LINUX_INSTALL_DIR;
-import static jdk.jpackage.internal.LinuxAppBundler.LINUX_PACKAGE_DEPENDENCIES;
-
-public class LinuxDebBundler extends AbstractBundler {
+import static jdk.jpackage.internal.LinuxPackageBundler.I18N;
- private static final ResourceBundle I18N = ResourceBundle.getBundle(
- "jdk.jpackage.internal.resources.LinuxResources");
-
- public static final BundlerParamInfo<LinuxAppBundler> APP_BUNDLER =
- new StandardBundlerParam<>(
- "linux.app.bundler",
- LinuxAppBundler.class,
- params -> new LinuxAppBundler(),
- (s, p) -> null);
+public class LinuxDebBundler extends LinuxPackageBundler {
// Debian rules for package naming are used here
// https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Source
@@ -68,10 +53,10 @@
// They must be at least two characters long and
// must start with an alphanumeric character.
//
- private static final Pattern DEB_BUNDLE_NAME_PATTERN =
+ private static final Pattern DEB_PACKAGE_NAME_PATTERN =
Pattern.compile("^[a-z][a-z\\d\\+\\-\\.]+");
- public static final BundlerParamInfo<String> BUNDLE_NAME =
+ private static final BundlerParamInfo<String> PACKAGE_NAME =
new StandardBundlerParam<> (
Arguments.CLIOptions.LINUX_BUNDLE_NAME.getId(),
String.class,
@@ -85,7 +70,7 @@
return nm;
},
(s, p) -> {
- if (!DEB_BUNDLE_NAME_PATTERN.matcher(s).matches()) {
+ if (!DEB_PACKAGE_NAME_PATTERN.matcher(s).matches()) {
throw new IllegalArgumentException(new ConfigException(
MessageFormat.format(I18N.getString(
"error.invalid-value-for-package-name"), s),
@@ -100,7 +85,7 @@
new StandardBundlerParam<>(
"linux.deb.fullPackageName", String.class, params -> {
try {
- return BUNDLE_NAME.fetchFrom(params)
+ return PACKAGE_NAME.fetchFrom(params)
+ "_" + VERSION.fetchFrom(params)
+ "-" + RELEASE.fetchFrom(params)
+ "_" + getDebArch();
@@ -110,43 +95,14 @@
}
}, (s, p) -> s);
- private static final BundlerParamInfo<File> DEB_IMAGE_DIR =
- new StandardBundlerParam<>(
- "linux.deb.imageDir",
- File.class,
- params -> {
- File imagesRoot = IMAGES_ROOT.fetchFrom(params);
- if (!imagesRoot.exists()) imagesRoot.mkdirs();
- return new File(new File(imagesRoot, "linux-deb.image"),
- FULL_PACKAGE_NAME.fetchFrom(params));
- },
- (s, p) -> new File(s));
-
- public static final BundlerParamInfo<File> APP_IMAGE_ROOT =
- new StandardBundlerParam<>(
- "linux.deb.imageRoot",
- File.class,
- params -> {
- File imageDir = DEB_IMAGE_DIR.fetchFrom(params);
- return new File(imageDir, LINUX_INSTALL_DIR.fetchFrom(params));
- },
- (s, p) -> new File(s));
-
- public static final BundlerParamInfo<File> CONFIG_DIR =
- new StandardBundlerParam<>(
- "linux.deb.configDir",
- File.class,
- params -> new File(DEB_IMAGE_DIR.fetchFrom(params), "DEBIAN"),
- (s, p) -> new File(s));
-
- public static final BundlerParamInfo<String> EMAIL =
+ private static final BundlerParamInfo<String> EMAIL =
new StandardBundlerParam<> (
Arguments.CLIOptions.LINUX_DEB_MAINTAINER.getId(),
String.class,
params -> "Unknown",
(s, p) -> s);
- public static final BundlerParamInfo<String> MAINTAINER =
+ private static final BundlerParamInfo<String> MAINTAINER =
new StandardBundlerParam<> (
BundleParams.PARAM_MAINTAINER,
String.class,
@@ -154,14 +110,14 @@
+ EMAIL.fetchFrom(params) + ">",
(s, p) -> s);
- public static final BundlerParamInfo<String> SECTION =
+ private static final BundlerParamInfo<String> SECTION =
new StandardBundlerParam<>(
Arguments.CLIOptions.LINUX_CATEGORY.getId(),
String.class,
params -> "misc",
(s, p) -> s);
- public static final BundlerParamInfo<String> LICENSE_TEXT =
+ private static final BundlerParamInfo<String> LICENSE_TEXT =
new StandardBundlerParam<> (
"linux.deb.licenseText",
String.class,
@@ -184,65 +140,13 @@
},
(s, p) -> s);
- public static final BundlerParamInfo<String> COPYRIGHT_FILE =
+ private static final BundlerParamInfo<String> COPYRIGHT_FILE =
new StandardBundlerParam<>(
Arguments.CLIOptions.LINUX_DEB_COPYRIGHT_FILE.getId(),
String.class,
params -> null,
(s, p) -> s);
- public static final BundlerParamInfo<String> XDG_FILE_PREFIX =
- new StandardBundlerParam<> (
- "linux.xdg-prefix",
- String.class,
- params -> {
- try {
- String vendor;
- if (params.containsKey(VENDOR.getID())) {
- vendor = VENDOR.fetchFrom(params);
- } else {
- vendor = "jpackage";
- }
- String appName = APP_NAME.fetchFrom(params);
-
- return (appName + "-" + vendor).replaceAll("\\s", "");
- } catch (Exception e) {
- Log.verbose(e);
- }
- return "unknown-MimeInfo.xml";
- },
- (s, p) -> s);
-
- public static final BundlerParamInfo<String> MENU_GROUP =
- new StandardBundlerParam<>(
- Arguments.CLIOptions.LINUX_MENU_GROUP.getId(),
- String.class,
- params -> I18N.getString("param.menu-group.default"),
- (s, p) -> s
- );
-
- public static final StandardBundlerParam<Boolean> SHORTCUT_HINT =
- new StandardBundlerParam<>(
- Arguments.CLIOptions.LINUX_SHORTCUT_HINT.getId(),
- Boolean.class,
- params -> false,
- (s, p) -> (s == null || "null".equalsIgnoreCase(s))
- ? false : Boolean.valueOf(s)
- );
-
- private final static String DEFAULT_ICON = "java32.png";
- private final static String DEFAULT_CONTROL_TEMPLATE = "template.control";
- private final static String DEFAULT_PRERM_TEMPLATE = "template.prerm";
- private final static String DEFAULT_PREINSTALL_TEMPLATE =
- "template.preinst";
- private final static String DEFAULT_POSTRM_TEMPLATE = "template.postrm";
- private final static String DEFAULT_POSTINSTALL_TEMPLATE =
- "template.postinst";
- private final static String DEFAULT_COPYRIGHT_TEMPLATE =
- "template.copyright";
- private final static String DEFAULT_DESKTOP_FILE_TEMPLATE =
- "template.desktop";
-
private final static String TOOL_DPKG_DEB = "dpkg-deb";
private final static String TOOL_DPKG = "dpkg";
@@ -261,131 +165,43 @@
return true;
}
- @Override
- public boolean validate(Map<String, ? super Object> params)
- throws 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
- APP_BUNDLER.fetchFrom(params).validate(params);
+ public LinuxDebBundler() {
+ super(PACKAGE_NAME);
+ }
- // NOTE: Can we validate that the required tools are available
- // before we start?
- if (!testTool(TOOL_DPKG_DEB, "1")){
- throw new ConfigException(MessageFormat.format(
- I18N.getString("error.tool-not-found"), TOOL_DPKG_DEB),
- I18N.getString("error.tool-not-found.advice"));
- }
- if (!testTool(TOOL_DPKG, "1")){
- throw new ConfigException(MessageFormat.format(
- I18N.getString("error.tool-not-found"), TOOL_DPKG),
- I18N.getString("error.tool-not-found.advice"));
- }
+ @Override
+ public void doValidate(Map<String, ? super Object> params)
+ throws ConfigException {
+ // NOTE: Can we validate that the required tools are available
+ // before we start?
+ if (!testTool(TOOL_DPKG_DEB, "1")){
+ throw new ConfigException(MessageFormat.format(
+ I18N.getString("error.tool-not-found"), TOOL_DPKG_DEB),
+ I18N.getString("error.tool-not-found.advice"));
+ }
+ if (!testTool(TOOL_DPKG, "1")){
+ throw new ConfigException(MessageFormat.format(
+ I18N.getString("error.tool-not-found"), TOOL_DPKG),
+ I18N.getString("error.tool-not-found.advice"));
+ }
- // Show warning is license file is missing
- String licenseFile = LICENSE_FILE.fetchFrom(params);
- if (licenseFile == null) {
- Log.verbose(I18N.getString("message.debs-like-licenses"));
- }
-
- // only one mime type per association, at least one file extention
- List<Map<String, ? super Object>> associations =
- FILE_ASSOCIATIONS.fetchFrom(params);
- if (associations != null) {
- for (int i = 0; i < associations.size(); i++) {
- Map<String, ? super Object> assoc = associations.get(i);
- List<String> mimes = FA_CONTENT_TYPE.fetchFrom(assoc);
- if (mimes == null || mimes.isEmpty()) {
- String msgKey =
- "error.no-content-types-for-file-association";
- throw new ConfigException(
- MessageFormat.format(I18N.getString(msgKey), i),
- I18N.getString(msgKey + ".advise"));
-
- } else if (mimes.size() > 1) {
- String msgKey =
- "error.too-many-content-types-for-file-association";
- throw new ConfigException(
- MessageFormat.format(I18N.getString(msgKey), i),
- I18N.getString(msgKey + ".advise"));
- }
- }
- }
-
- // bundle name has some restrictions
- // the string converter will throw an exception if invalid
- BUNDLE_NAME.getStringConverter().apply(
- BUNDLE_NAME.fetchFrom(params), params);
-
- return true;
- } catch (RuntimeException re) {
- if (re.getCause() instanceof ConfigException) {
- throw (ConfigException) re.getCause();
- } else {
- throw new ConfigException(re);
- }
+ // Show warning is license file is missing
+ String licenseFile = LICENSE_FILE.fetchFrom(params);
+ if (licenseFile == null) {
+ Log.verbose(I18N.getString("message.debs-like-licenses"));
}
}
- private boolean prepareProto(Map<String, ? super Object> params)
- throws PackagerException, IOException {
- File appImage = StandardBundlerParam.getPredefinedAppImage(params);
-
- // we either have an application image or need to build one
- if (appImage != null) {
- // copy everything from appImage dir into appDir/name
- IOUtils.copyRecursive(appImage.toPath(),
- getConfig_RootDirectory(params).toPath());
- } else {
- File bundleDir = APP_BUNDLER.fetchFrom(params).doBundle(params,
- APP_IMAGE_ROOT.fetchFrom(params), true);
- if (bundleDir == null) {
- return false;
- }
- Files.move(bundleDir.toPath(), getConfig_RootDirectory(
- params).toPath(), StandardCopyOption.REPLACE_EXISTING);
- }
- return true;
- }
-
- public File bundle(Map<String, ? super Object> params,
- File outdir) throws PackagerException {
-
- IOUtils.writableOutputDir(outdir.toPath());
+ @Override
+ protected File buildPackageBundle(
+ Map<String, String> replacementData,
+ Map<String, ? super Object> params, File outputParentDir) throws
+ PackagerException, IOException {
- // we want to create following structure
- // <package-name>
- // DEBIAN
- // control (file with main package details)
- // menu (request to create menu)
- // ... other control files if needed ....
- // opt (by default)
- // AppFolder (this is where app image goes)
- // launcher executable
- // app
- // runtime
-
- File imageDir = DEB_IMAGE_DIR.fetchFrom(params);
- File configDir = CONFIG_DIR.fetchFrom(params);
-
- try {
-
- imageDir.mkdirs();
- configDir.mkdirs();
- if (prepareProto(params) && prepareProjectConfig(params)) {
- adjustPermissionsRecursive(imageDir);
- return buildDeb(params, outdir);
- }
- return null;
- } catch (IOException ex) {
- Log.verbose(ex);
- throw new PackagerException(ex);
- }
+ prepareProjectConfig(replacementData, params);
+ adjustPermissionsRecursive(createMetaPackage(params).sourceRoot().toFile());
+ return buildDeb(params, outputParentDir);
}
/*
@@ -429,26 +245,6 @@
return false;
}
- private long getInstalledSizeKB(Map<String, ? super Object> params) {
- return getInstalledSizeKB(APP_IMAGE_ROOT.fetchFrom(params)) >> 10;
- }
-
- private long getInstalledSizeKB(File dir) {
- long count = 0;
- File[] children = dir.listFiles();
- if (children != null) {
- for (File file : children) {
- if (file.isFile()) {
- count += file.length();
- }
- else if (file.isDirectory()) {
- count += getInstalledSizeKB(file);
- }
- }
- }
- return count;
- }
-
private void adjustPermissionsRecursive(File dir) throws IOException {
Files.walkFileTree(dir.toPath(), new SimpleFileVisitor<Path>() {
@Override
@@ -477,327 +273,61 @@
});
}
- private boolean prepareProjectConfig(Map<String, ? super Object> params)
- throws IOException {
- Map<String, String> data = createReplacementData(params);
- File rootDir = getConfig_RootDirectory(params);
- File binDir = new File(rootDir, "bin");
+ private class DebianFile {
+
+ DebianFile(Path dstFilePath, String comment) {
+ this.dstFilePath = dstFilePath;
+ this.comment = comment;
+ }
- File iconTarget = getConfig_IconFile(binDir, params);
- File icon = ICON_PNG.fetchFrom(params);
- if (!StandardBundlerParam.isRuntimeInstaller(params)) {
- // prepare installer icon
- if (icon == null || !icon.exists()) {
- fetchResource(iconTarget.getName(),
- I18N.getString("resource.menu-icon"),
- DEFAULT_ICON,
- iconTarget,
+ DebianFile setExecutable() {
+ permissions = "rwxr-xr-x";
+ return this;
+ }
+
+ void create(Map<String, String> data, Map<String, ? super Object> params)
+ throws IOException {
+ Files.createDirectories(dstFilePath.getParent());
+ try (Writer w = Files.newBufferedWriter(dstFilePath)) {
+ String content = preprocessTextResource(
+ dstFilePath.getFileName().toString(),
+ I18N.getString(comment),
+ "template." + dstFilePath.getFileName().toString(),
+ data,
VERBOSE.fetchFrom(params),
RESOURCE_DIR.fetchFrom(params));
- } else {
- fetchResource(iconTarget.getName(),
- I18N.getString("resource.menu-icon"),
- icon,
- iconTarget,
- VERBOSE.fetchFrom(params),
- RESOURCE_DIR.fetchFrom(params));
+ w.write(content);
+ }
+ if (permissions != null) {
+ setPermissions(dstFilePath.toFile(), permissions);
}
}
- StringBuilder installScripts = new StringBuilder();
- StringBuilder removeScripts = new StringBuilder();
- for (Map<String, ? super Object> addLauncher :
- ADD_LAUNCHERS.fetchFrom(params)) {
- Map<String, String> addLauncherData =
- createReplacementData(addLauncher);
- addLauncherData.put("APPLICATION_FS_NAME",
- data.get("APPLICATION_FS_NAME"));
- addLauncherData.put("DESKTOP_MIMES", "");
-
- if (!StandardBundlerParam.isRuntimeInstaller(params)) {
- // prepare desktop shortcut
- if (SHORTCUT_HINT.fetchFrom(params)) {
- try (Writer w = Files.newBufferedWriter(
- getConfig_DesktopShortcutFile(
- binDir, addLauncher).toPath())) {
- String content = preprocessTextResource(
- getConfig_DesktopShortcutFile(binDir,
- addLauncher).getName(),
- I18N.getString("resource.menu-shortcut-descriptor"),
- DEFAULT_DESKTOP_FILE_TEMPLATE,
- addLauncherData,
- VERBOSE.fetchFrom(params),
- RESOURCE_DIR.fetchFrom(params));
- w.write(content);
- }
- }
- }
-
- // prepare installer icon
- iconTarget = getConfig_IconFile(binDir, addLauncher);
- icon = ICON_PNG.fetchFrom(addLauncher);
- if (icon == null || !icon.exists()) {
- fetchResource(iconTarget.getName(),
- I18N.getString("resource.menu-icon"),
- DEFAULT_ICON,
- iconTarget,
- VERBOSE.fetchFrom(params),
- RESOURCE_DIR.fetchFrom(params));
- } else {
- fetchResource(iconTarget.getName(),
- I18N.getString("resource.menu-icon"),
- icon,
- iconTarget,
- VERBOSE.fetchFrom(params),
- RESOURCE_DIR.fetchFrom(params));
- }
-
- // postinst copying of desktop icon
- installScripts.append(
- " xdg-desktop-menu install --novendor ");
- installScripts.append(LINUX_INSTALL_DIR.fetchFrom(params));
- installScripts.append("/");
- installScripts.append(data.get("APPLICATION_FS_NAME"));
- installScripts.append("/bin/");
- installScripts.append(
- addLauncherData.get("APPLICATION_LAUNCHER_FILENAME"));
- installScripts.append(".desktop\n");
+ private final Path dstFilePath;
+ private final String comment;
+ private String permissions;
+ }
- // postrm cleanup of desktop icon
- removeScripts.append(
- " xdg-desktop-menu uninstall --novendor ");
- removeScripts.append(LINUX_INSTALL_DIR.fetchFrom(params));
- removeScripts.append("/");
- removeScripts.append(data.get("APPLICATION_FS_NAME"));
- removeScripts.append("/bin/");
- removeScripts.append(
- addLauncherData.get("APPLICATION_LAUNCHER_FILENAME"));
- removeScripts.append(".desktop\n");
- }
- data.put("ADD_LAUNCHERS_INSTALL", installScripts.toString());
- data.put("ADD_LAUNCHERS_REMOVE", removeScripts.toString());
-
- List<Map<String, ? super Object>> associations =
- FILE_ASSOCIATIONS.fetchFrom(params);
- data.put("FILE_ASSOCIATION_INSTALL", "");
- data.put("FILE_ASSOCIATION_REMOVE", "");
- data.put("DESKTOP_MIMES", "");
- if (associations != null) {
- String mimeInfoFile = XDG_FILE_PREFIX.fetchFrom(params)
- + "-MimeInfo.xml";
- StringBuilder mimeInfo = new StringBuilder(
- "<?xml version=\"1.0\"?>\n<mime-info xmlns="
- + "'http://www.freedesktop.org/standards/shared-mime-info'>\n");
- StringBuilder registrations = new StringBuilder();
- StringBuilder deregistrations = new StringBuilder();
- StringBuilder desktopMimes = new StringBuilder("MimeType=");
- boolean addedEntry = false;
-
- for (Map<String, ? super Object> assoc : associations) {
- // <mime-type type="application/x-vnd.awesome">
- // <comment>Awesome document</comment>
- // <glob pattern="*.awesome"/>
- // <glob pattern="*.awe"/>
- // </mime-type>
-
- if (assoc == null) {
- continue;
- }
-
- String description = FA_DESCRIPTION.fetchFrom(assoc);
- File faIcon = FA_ICON.fetchFrom(assoc);
- List<String> extensions = FA_EXTENSIONS.fetchFrom(assoc);
- if (extensions == null) {
- Log.error(I18N.getString(
- "message.creating-association-with-null-extension"));
- }
-
- List<String> mimes = FA_CONTENT_TYPE.fetchFrom(assoc);
- if (mimes == null || mimes.isEmpty()) {
- continue;
- }
- String thisMime = mimes.get(0);
- String dashMime = thisMime.replace('/', '-');
-
- mimeInfo.append(" <mime-type type='")
- .append(thisMime)
- .append("'>\n");
- if (description != null && !description.isEmpty()) {
- mimeInfo.append(" <comment>")
- .append(description)
- .append("</comment>\n");
- }
-
- if (extensions != null) {
- for (String ext : extensions) {
- mimeInfo.append(" <glob pattern='*.")
- .append(ext)
- .append("'/>\n");
- }
- }
-
- mimeInfo.append(" </mime-type>\n");
- if (!addedEntry) {
- registrations.append(" xdg-mime install ")
- .append(LINUX_INSTALL_DIR.fetchFrom(params))
- .append("/")
- .append(data.get("APPLICATION_FS_NAME"))
- .append("/bin/")
- .append(mimeInfoFile)
- .append("\n");
+ private void prepareProjectConfig(Map<String, String> data,
+ Map<String, ? super Object> params) throws IOException {
- deregistrations.append(" xdg-mime uninstall ")
- .append(LINUX_INSTALL_DIR.fetchFrom(params))
- .append("/")
- .append(data.get("APPLICATION_FS_NAME"))
- .append("/bin/")
- .append(mimeInfoFile)
- .append("\n");
- addedEntry = true;
- } else {
- desktopMimes.append(";");
- }
- desktopMimes.append(thisMime);
-
- if (faIcon != null && faIcon.exists()) {
- int size = getSquareSizeOfImage(faIcon);
-
- if (size > 0) {
- File target = new File(binDir,
- APP_NAME.fetchFrom(params)
- + "_fa_" + faIcon.getName());
- IOUtils.copyFile(faIcon, target);
-
- // xdg-icon-resource install --context mimetypes
- // --size 64 awesomeapp_fa_1.png
- // application-x.vnd-awesome
- registrations.append(
- " xdg-icon-resource install "
- + "--context mimetypes --size ")
- .append(size)
- .append(" ")
- .append(LINUX_INSTALL_DIR.fetchFrom(params))
- .append("/")
- .append(data.get("APPLICATION_FS_NAME"))
- .append("/")
- .append(target.getName())
- .append(" ")
- .append(dashMime)
- .append("\n");
-
- // x dg-icon-resource uninstall --context mimetypes
- // --size 64 awesomeapp_fa_1.png
- // application-x.vnd-awesome
- deregistrations.append(
- " xdg-icon-resource uninstall "
- + "--context mimetypes --size ")
- .append(size)
- .append(" ")
- .append(LINUX_INSTALL_DIR.fetchFrom(params))
- .append("/")
- .append(data.get("APPLICATION_FS_NAME"))
- .append("/")
- .append(target.getName())
- .append(" ")
- .append(dashMime)
- .append("\n");
- }
- }
- }
- mimeInfo.append("</mime-info>");
-
- if (addedEntry) {
- try (Writer w = Files.newBufferedWriter(
- new File(binDir, mimeInfoFile).toPath())) {
- w.write(mimeInfo.toString());
- }
- data.put("FILE_ASSOCIATION_INSTALL", registrations.toString());
- data.put("FILE_ASSOCIATION_REMOVE", deregistrations.toString());
- data.put("DESKTOP_MIMES", desktopMimes.toString());
- }
- }
-
- if (!StandardBundlerParam.isRuntimeInstaller(params)) {
- // prepare desktop shortcut
- if (SHORTCUT_HINT.fetchFrom(params)) {
- try (Writer w = Files.newBufferedWriter(
- getConfig_DesktopShortcutFile(binDir, params).toPath())) {
- String content = preprocessTextResource(
- getConfig_DesktopShortcutFile(
- binDir, params).getName(),
- I18N.getString("resource.menu-shortcut-descriptor"),
- DEFAULT_DESKTOP_FILE_TEMPLATE,
- data,
- VERBOSE.fetchFrom(params),
- RESOURCE_DIR.fetchFrom(params));
- w.write(content);
- }
- }
- }
- // prepare control file
- try (Writer w = Files.newBufferedWriter(
- getConfig_ControlFile(params).toPath())) {
- String content = preprocessTextResource(
- getConfig_ControlFile(params).getName(),
- I18N.getString("resource.deb-control-file"),
- DEFAULT_CONTROL_TEMPLATE,
- data,
- VERBOSE.fetchFrom(params),
- RESOURCE_DIR.fetchFrom(params));
- w.write(content);
- }
-
- try (Writer w = Files.newBufferedWriter(
- getConfig_PreinstallFile(params).toPath())) {
- String content = preprocessTextResource(
- getConfig_PreinstallFile(params).getName(),
- I18N.getString("resource.deb-preinstall-script"),
- DEFAULT_PREINSTALL_TEMPLATE,
- data,
- VERBOSE.fetchFrom(params),
- RESOURCE_DIR.fetchFrom(params));
- w.write(content);
- }
- setPermissions(getConfig_PreinstallFile(params), "rwxr-xr-x");
-
- try (Writer w = Files.newBufferedWriter(
- getConfig_PrermFile(params).toPath())) {
- String content = preprocessTextResource(
- getConfig_PrermFile(params).getName(),
- I18N.getString("resource.deb-prerm-script"),
- DEFAULT_PRERM_TEMPLATE,
- data,
- VERBOSE.fetchFrom(params),
- RESOURCE_DIR.fetchFrom(params));
- w.write(content);
- }
- setPermissions(getConfig_PrermFile(params), "rwxr-xr-x");
-
- try (Writer w = Files.newBufferedWriter(
- getConfig_PostinstallFile(params).toPath())) {
- String content = preprocessTextResource(
- getConfig_PostinstallFile(params).getName(),
- I18N.getString("resource.deb-postinstall-script"),
- DEFAULT_POSTINSTALL_TEMPLATE,
- data,
- VERBOSE.fetchFrom(params),
- RESOURCE_DIR.fetchFrom(params));
- w.write(content);
- }
- setPermissions(getConfig_PostinstallFile(params), "rwxr-xr-x");
-
- try (Writer w = Files.newBufferedWriter(
- getConfig_PostrmFile(params).toPath())) {
- String content = preprocessTextResource(
- getConfig_PostrmFile(params).getName(),
- I18N.getString("resource.deb-postrm-script"),
- DEFAULT_POSTRM_TEMPLATE,
- data,
- VERBOSE.fetchFrom(params),
- RESOURCE_DIR.fetchFrom(params));
- w.write(content);
- }
- setPermissions(getConfig_PostrmFile(params), "rwxr-xr-x");
+ Path configDir = createMetaPackage(params).sourceRoot().resolve("DEBIAN");
+ List<DebianFile> debianFiles = new ArrayList<>();
+ debianFiles.add(new DebianFile(
+ configDir.resolve("control"),
+ "resource.deb-control-file"));
+ debianFiles.add(new DebianFile(
+ configDir.resolve("preinst"),
+ "resource.deb-preinstall-script").setExecutable());
+ debianFiles.add(new DebianFile(
+ configDir.resolve("prerm"),
+ "resource.deb-prerm-script").setExecutable());
+ debianFiles.add(new DebianFile(
+ configDir.resolve("postinst"),
+ "resource.deb-postinstall-script").setExecutable());
+ debianFiles.add(new DebianFile(
+ configDir.resolve("postrm"),
+ "resource.deb-postrm-script").setExecutable());
getConfig_CopyrightFile(params).getParentFile().mkdirs();
String customCopyrightFile = COPYRIGHT_FILE.fetchFrom(params);
@@ -805,93 +335,36 @@
IOUtils.copyFile(new File(customCopyrightFile),
getConfig_CopyrightFile(params));
} else {
- try (Writer w = Files.newBufferedWriter(
- getConfig_CopyrightFile(params).toPath())) {
- String content = preprocessTextResource(
- getConfig_CopyrightFile(params).getName(),
- I18N.getString("resource.copyright-file"),
- DEFAULT_COPYRIGHT_TEMPLATE,
- data,
- VERBOSE.fetchFrom(params),
- RESOURCE_DIR.fetchFrom(params));
- w.write(content);
- }
+ debianFiles.add(new DebianFile(
+ getConfig_CopyrightFile(params).toPath(),
+ "resource.copyright-file"));
}
- return true;
+ for (DebianFile debianFile : debianFiles) {
+ debianFile.create(data, params);
+ }
}
- private Map<String, String> createReplacementData(
+ @Override
+ protected Map<String, String> createReplacementData(
Map<String, ? super Object> params) throws IOException {
Map<String, String> data = new HashMap<>();
- String launcher = LinuxAppImageBuilder.getLauncherRelativePath(params);
- data.put("APPLICATION_NAME", APP_NAME.fetchFrom(params));
- data.put("APPLICATION_FS_NAME",
- getConfig_RootDirectory(params).getName());
- data.put("APPLICATION_PACKAGE", BUNDLE_NAME.fetchFrom(params));
- data.put("APPLICATION_VENDOR", VENDOR.fetchFrom(params));
data.put("APPLICATION_MAINTAINER", MAINTAINER.fetchFrom(params));
- data.put("APPLICATION_VERSION", VERSION.fetchFrom(params));
- data.put("APPLICATION_RELEASE", RELEASE.fetchFrom(params));
data.put("APPLICATION_SECTION", SECTION.fetchFrom(params));
- data.put("APPLICATION_LAUNCHER_FILENAME", launcher);
- data.put("INSTALLATION_DIRECTORY", LINUX_INSTALL_DIR.fetchFrom(params));
- data.put("XDG_PREFIX", XDG_FILE_PREFIX.fetchFrom(params));
- data.put("DEPLOY_BUNDLE_CATEGORY", MENU_GROUP.fetchFrom(params));
- data.put("APPLICATION_DESCRIPTION", DESCRIPTION.fetchFrom(params));
data.put("APPLICATION_COPYRIGHT", COPYRIGHT.fetchFrom(params));
data.put("APPLICATION_LICENSE_TEXT", LICENSE_TEXT.fetchFrom(params));
data.put("APPLICATION_ARCH", getDebArch());
- data.put("APPLICATION_INSTALLED_SIZE",
- Long.toString(getInstalledSizeKB(params)));
- data.put("PACKAGE_DEPENDENCIES", LINUX_PACKAGE_DEPENDENCIES.fetchFrom(
- params));
- data.put("RUNTIME_INSTALLER", "" +
- StandardBundlerParam.isRuntimeInstaller(params));
+ data.put("APPLICATION_INSTALLED_SIZE", Long.toString(
+ createMetaPackage(params).sourceApplicationLayout().sizeInBytes() >> 10));
return data;
}
- private File getConfig_DesktopShortcutFile(File rootDir,
- Map<String, ? super Object> params) {
- return new File(rootDir, APP_NAME.fetchFrom(params) + ".desktop");
- }
-
- private File getConfig_IconFile(File rootDir,
- Map<String, ? super Object> params) {
- return new File(rootDir, APP_NAME.fetchFrom(params) + ".png");
- }
-
- private File getConfig_ControlFile(Map<String, ? super Object> params) {
- return new File(CONFIG_DIR.fetchFrom(params), "control");
- }
-
- private File getConfig_PreinstallFile(Map<String, ? super Object> params) {
- return new File(CONFIG_DIR.fetchFrom(params), "preinst");
- }
-
- private File getConfig_PrermFile(Map<String, ? super Object> params) {
- return new File(CONFIG_DIR.fetchFrom(params), "prerm");
- }
-
- private File getConfig_PostinstallFile(Map<String, ? super Object> params) {
- return new File(CONFIG_DIR.fetchFrom(params), "postinst");
- }
-
- private File getConfig_PostrmFile(Map<String, ? super Object> params) {
- return new File(CONFIG_DIR.fetchFrom(params), "postrm");
- }
-
private File getConfig_CopyrightFile(Map<String, ? super Object> params) {
- return Path.of(DEB_IMAGE_DIR.fetchFrom(params).getAbsolutePath(), "usr",
- "share", "doc", BUNDLE_NAME.fetchFrom(params), "copyright").toFile();
- }
-
- private File getConfig_RootDirectory(
- Map<String, ? super Object> params) {
- return Path.of(APP_IMAGE_ROOT.fetchFrom(params).getAbsolutePath(),
- BUNDLE_NAME.fetchFrom(params)).toFile();
+ PlatformPackage thePackage = createMetaPackage(params);
+ return thePackage.sourceRoot().resolve(Path.of("usr/share/doc",
+ thePackage.name(), "copyright")).toFile();
}
private File buildDeb(Map<String, ? super Object> params,
@@ -901,14 +374,13 @@
Log.verbose(MessageFormat.format(I18N.getString(
"message.outputting-to-location"), outFile.getAbsolutePath()));
- outFile.getParentFile().mkdirs();
+ PlatformPackage thePackage = createMetaPackage(params);
// run dpkg
ProcessBuilder pb = new ProcessBuilder(
"fakeroot", TOOL_DPKG_DEB, "-b",
- FULL_PACKAGE_NAME.fetchFrom(params),
+ thePackage.sourceRoot().toString(),
outFile.getAbsolutePath());
- pb = pb.directory(DEB_IMAGE_DIR.fetchFrom(params).getParentFile());
IOUtils.exec(pb);
Log.verbose(MessageFormat.format(I18N.getString(
@@ -928,22 +400,7 @@
}
@Override
- public String getBundleType() {
- return "INSTALLER";
- }
-
- @Override
- public File execute(Map<String, ? super Object> params,
- File outputParentDir) throws PackagerException {
- return bundle(params, outputParentDir);
- }
-
- @Override
public boolean supported(boolean runtimeInstaller) {
- return isSupported();
- }
-
- public static boolean isSupported() {
if (Platform.getPlatform() == Platform.LINUX) {
if (testTool(TOOL_DPKG_DEB, "1")) {
return true;
@@ -952,20 +409,6 @@
return false;
}
- public int getSquareSizeOfImage(File f) {
- try {
- BufferedImage bi = ImageIO.read(f);
- if (bi.getWidth() == bi.getHeight()) {
- return bi.getWidth();
- } else {
- return 0;
- }
- } catch (Exception e) {
- Log.verbose(e);
- return 0;
- }
- }
-
@Override
public boolean isDefault() {
return isDebian();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java Tue Sep 24 13:41:16 2019 -0400
@@ -0,0 +1,712 @@
+/*
+ * 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.awt.image.BufferedImage;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Writer;
+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.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import javax.imageio.ImageIO;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import static jdk.jpackage.internal.LinuxAppBundler.LINUX_INSTALL_DIR;
+import static jdk.jpackage.internal.LinuxAppBundler.LINUX_PACKAGE_DEPENDENCIES;
+import static jdk.jpackage.internal.LinuxAppImageBuilder.DEFAULT_ICON;
+import static jdk.jpackage.internal.LinuxAppImageBuilder.ICON_PNG;
+import static jdk.jpackage.internal.StandardBundlerParam.*;
+
+
+abstract class LinuxPackageBundler extends AbstractBundler {
+
+ protected static final ResourceBundle I18N = ResourceBundle.getBundle(
+ "jdk.jpackage.internal.resources.LinuxResources");
+
+ private static final String DESKTOP_COMMANDS_INSTALL = "DESKTOP_COMMANDS_INSTALL";
+ private static final String DESKTOP_COMMANDS_UNINSTALL = "DESKTOP_COMMANDS_UNINSTALL";
+ private static final String UTILITY_SCRIPTS = "UTILITY_SCRIPTS";
+
+ private static final BundlerParamInfo<LinuxAppBundler> APP_BUNDLER =
+ new StandardBundlerParam<>(
+ "linux.app.bundler",
+ LinuxAppBundler.class,
+ (params) -> new LinuxAppBundler(),
+ null
+ );
+
+ private static final BundlerParamInfo<String> MENU_GROUP =
+ new StandardBundlerParam<>(
+ Arguments.CLIOptions.LINUX_MENU_GROUP.getId(),
+ String.class,
+ params -> I18N.getString("param.menu-group.default"),
+ (s, p) -> s
+ );
+
+ private static final StandardBundlerParam<Boolean> SHORTCUT_HINT =
+ new StandardBundlerParam<>(
+ Arguments.CLIOptions.LINUX_SHORTCUT_HINT.getId(),
+ Boolean.class,
+ params -> false,
+ (s, p) -> (s == null || "null".equalsIgnoreCase(s))
+ ? false : Boolean.valueOf(s)
+ );
+
+ LinuxPackageBundler(BundlerParamInfo<String> packageName) {
+ this.packageName = packageName;
+ }
+
+ private final BundlerParamInfo<String> packageName;
+
+ @Override
+ final public boolean validate(Map<String, ? super Object> params)
+ throws 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
+ APP_BUNDLER.fetchFrom(params).validate(params);
+
+ validateFileAssociations(FILE_ASSOCIATIONS.fetchFrom(params));
+
+ // If package name has some restrictions, the string converter will
+ // throw an exception if invalid
+ packageName.getStringConverter().apply(packageName.fetchFrom(params),
+ params);
+
+ // Packaging specific validation
+ doValidate(params);
+
+ return true;
+ } catch (RuntimeException re) {
+ if (re.getCause() instanceof ConfigException) {
+ throw (ConfigException) re.getCause();
+ } else {
+ throw new ConfigException(re);
+ }
+ }
+ }
+
+ @Override
+ final public String getBundleType() {
+ return "INSTALLER";
+ }
+
+ @Override
+ final public File execute(Map<String, ? super Object> params,
+ File outputParentDir) throws PackagerException {
+ IOUtils.writableOutputDir(outputParentDir.toPath());
+
+ PlatformPackage thePackage = createMetaPackage(params);
+
+ try {
+ File appImage = StandardBundlerParam.getPredefinedAppImage(params);
+
+ // we either have an application image or need to build one
+ if (appImage != null) {
+ appImageLayout(params).resolveAt(appImage.toPath()).copy(
+ thePackage.sourceApplicationLayout());
+ } else {
+ appImage = APP_BUNDLER.fetchFrom(params).doBundle(params,
+ thePackage.sourceRoot().toFile(), true);
+ ApplicationLayout srcAppLayout = appImageLayout(params).resolveAt(
+ appImage.toPath());
+ if (appImage.equals(PREDEFINED_RUNTIME_IMAGE.fetchFrom(params))) {
+ // Application image points to run-time image.
+ // Copy it.
+ srcAppLayout.copy(thePackage.sourceApplicationLayout());
+ } else {
+ // Application image is a newly created directory tree.
+ // Move it.
+ srcAppLayout.move(thePackage.sourceApplicationLayout());
+ if (appImage.exists()) {
+ // Empty app image directory might remain after all application
+ // directories have been moved.
+ appImage.delete();
+ }
+ }
+ }
+
+ Map<String, String> data = createDefaultReplacementData(params);
+ if (StandardBundlerParam.isRuntimeInstaller(params)) {
+ Stream.of(DESKTOP_COMMANDS_INSTALL, DESKTOP_COMMANDS_UNINSTALL,
+ UTILITY_SCRIPTS).forEach(v -> data.put(v, ""));
+ } else {
+ data.putAll(
+ new DesktopIntegration(thePackage, params).prepareForApplication());
+ }
+
+ data.putAll(createReplacementData(params));
+
+ return buildPackageBundle(Collections.unmodifiableMap(data), params,
+ outputParentDir);
+ } catch (IOException ex) {
+ Log.verbose(ex);
+ throw new PackagerException(ex);
+ }
+ }
+
+ private Map<String, String> createDefaultReplacementData(
+ Map<String, ? super Object> params) throws IOException {
+ Map<String, String> data = new HashMap<>();
+
+ data.put("APPLICATION_PACKAGE", createMetaPackage(params).name());
+ data.put("APPLICATION_VENDOR", VENDOR.fetchFrom(params));
+ data.put("APPLICATION_VERSION", VERSION.fetchFrom(params));
+ data.put("APPLICATION_DESCRIPTION", DESCRIPTION.fetchFrom(params));
+ data.put("APPLICATION_RELEASE", RELEASE.fetchFrom(params));
+ data.put("PACKAGE_DEPENDENCIES", LINUX_PACKAGE_DEPENDENCIES.fetchFrom(
+ params));
+
+ return data;
+ }
+
+ abstract void doValidate(Map<String, ? super Object> params)
+ throws ConfigException;
+
+ abstract protected Map<String, String> createReplacementData(
+ Map<String, ? super Object> params) throws IOException;
+
+ abstract protected File buildPackageBundle(
+ Map<String, String> replacementData,
+ Map<String, ? super Object> params, File outputParentDir) throws
+ PackagerException, IOException;
+
+ final protected PlatformPackage createMetaPackage(
+ Map<String, ? super Object> params) {
+ return new PlatformPackage() {
+ @Override
+ public String name() {
+ return packageName.fetchFrom(params);
+ }
+
+ @Override
+ public Path sourceRoot() {
+ return IMAGES_ROOT.fetchFrom(params).toPath().toAbsolutePath();
+ }
+
+ @Override
+ public ApplicationLayout sourceApplicationLayout() {
+ return appImageLayout(params).resolveAt(
+ applicationInstallDir(sourceRoot()));
+ }
+
+ @Override
+ public ApplicationLayout installedApplicationLayout() {
+ return appImageLayout(params).resolveAt(
+ applicationInstallDir(Path.of("/")));
+ }
+
+ private Path applicationInstallDir(Path root) {
+ Path installDir = Path.of(LINUX_INSTALL_DIR.fetchFrom(params),
+ name());
+ if (installDir.isAbsolute()) {
+ installDir = Path.of("." + installDir.toString()).normalize();
+ }
+ return root.resolve(installDir);
+ }
+ };
+ }
+
+ private ApplicationLayout appImageLayout(
+ Map<String, ? super Object> params) {
+ if (StandardBundlerParam.isRuntimeInstaller(params)) {
+ return ApplicationLayout.javaRuntime();
+ }
+ return ApplicationLayout.unixApp();
+ }
+
+ private static void validateFileAssociations(
+ List<Map<String, ? super Object>> associations) throws
+ ConfigException {
+ // only one mime type per association, at least one file extention
+ int assocIdx = 0;
+ for (var assoc : associations) {
+ ++assocIdx;
+ List<String> mimes = FA_CONTENT_TYPE.fetchFrom(assoc);
+ if (mimes == null || mimes.isEmpty()) {
+ String msgKey = "error.no-content-types-for-file-association";
+ throw new ConfigException(
+ MessageFormat.format(I18N.getString(msgKey), assocIdx),
+ I18N.getString(msgKey + ".advise"));
+
+ }
+
+ if (mimes.size() > 1) {
+ String msgKey = "error.too-many-content-types-for-file-association";
+ throw new ConfigException(
+ MessageFormat.format(I18N.getString(msgKey), assocIdx),
+ I18N.getString(msgKey + ".advise"));
+ }
+ }
+ }
+
+ /**
+ * Helper to create files for desktop integration.
+ */
+ private class DesktopIntegration {
+
+ DesktopIntegration(PlatformPackage thePackage,
+ Map<String, ? super Object> params) {
+
+ associations = FILE_ASSOCIATIONS.fetchFrom(params).stream().filter(
+ a -> {
+ if (a == null) {
+ return false;
+ }
+ List<String> mimes = FA_CONTENT_TYPE.fetchFrom(a);
+ return (mimes != null && !mimes.isEmpty());
+ }).collect(Collectors.toUnmodifiableList());
+
+ launchers = ADD_LAUNCHERS.fetchFrom(params);
+
+ this.thePackage = thePackage;
+
+ customIconFile = ICON_PNG.fetchFrom(params);
+
+ verbose = VERBOSE.fetchFrom(params);
+ resourceDir = RESOURCE_DIR.fetchFrom(params);
+
+ // XDG recommends to use vendor prefix in desktop file names as xdg
+ // commands copy files to system directories.
+ // Package name should be a good prefix.
+ final String desktopFileName = String.format("%s-%s.desktop",
+ thePackage.name(), APP_NAME.fetchFrom(params));
+ final String mimeInfoFileName = String.format("%s-%s-MimeInfo.xml",
+ thePackage.name(), APP_NAME.fetchFrom(params));
+
+ mimeInfoFile = new DesktopFile(mimeInfoFileName);
+
+ if (!associations.isEmpty() || SHORTCUT_HINT.fetchFrom(params) || customIconFile != null) {
+ //
+ // Create primary .desktop file if one of conditions is met:
+ // - there are file associations configured
+ // - user explicitely requested to create a shortcut
+ // - custom icon specified
+ //
+ desktopFile = new DesktopFile(desktopFileName);
+ iconFile = new DesktopFile(String.format("%s.png",
+ APP_NAME.fetchFrom(params)));
+ } else {
+ desktopFile = null;
+ iconFile = null;
+ }
+
+ this.desktopFileData = Collections.unmodifiableMap(
+ createDataForDesktopFile(params));
+ }
+
+ Map<String, String> prepareForApplication() throws IOException {
+ if (iconFile != null) {
+ // Create application icon file.
+ prepareSrcIconFile();
+ }
+
+ Map<String, String> data = new HashMap<>(desktopFileData);
+
+ final ShellCommands shellCommands;
+ if (desktopFile != null) {
+ // Create application desktop description file.
+ createDesktopFile(data);
+
+ // Shell commands will be created only if desktop file
+ // should be installed.
+ shellCommands = new ShellCommands();
+ } else {
+ shellCommands = null;
+ }
+
+ if (!associations.isEmpty()) {
+ // Create XML file with mime types corresponding to file associations.
+ createFileAssociationsMimeInfoFile();
+
+ shellCommands.setFileAssociations();
+
+ // Create icon files corresponding to file associations
+ Map<String, Path> mimeTypeWithIconFile = createFileAssociationIconFiles();
+ mimeTypeWithIconFile.forEach((k, v) -> {
+ shellCommands.addIcon(k, v);
+ });
+ }
+
+ // Create shell commands to install/uninstall integration with desktop of the app.
+ if (shellCommands != null) {
+ shellCommands.applyTo(data);
+ }
+
+ boolean needCleanupScripts = !associations.isEmpty();
+
+ // Take care of additional launchers if there are any.
+ // Process every additional launcher as the main application launcher.
+ // Collect shell commands to install/uninstall integration with desktop
+ // of the additional launchers and append them to the corresponding
+ // commands of the main launcher.
+ List<String> installShellCmds = new ArrayList<>(Arrays.asList(
+ data.get(DESKTOP_COMMANDS_INSTALL)));
+ List<String> uninstallShellCmds = new ArrayList<>(Arrays.asList(
+ data.get(DESKTOP_COMMANDS_UNINSTALL)));
+ for (Map<String, ? super Object> params : launchers) {
+ DesktopIntegration integration = new DesktopIntegration(
+ thePackage, params);
+
+ if (!integration.associations.isEmpty()) {
+ needCleanupScripts = true;
+ }
+
+ Map<String, String> launcherData = integration.prepareForApplication();
+
+ installShellCmds.add(launcherData.get(DESKTOP_COMMANDS_INSTALL));
+ uninstallShellCmds.add(launcherData.get(
+ DESKTOP_COMMANDS_UNINSTALL));
+ }
+
+ data.put(DESKTOP_COMMANDS_INSTALL, stringifyShellCommands(
+ installShellCmds));
+ data.put(DESKTOP_COMMANDS_UNINSTALL, stringifyShellCommands(
+ uninstallShellCmds));
+
+ if (needCleanupScripts) {
+ // Pull in utils.sh scrips library.
+ try (InputStream is = getResourceAsStream("utils.sh");
+ InputStreamReader isr = new InputStreamReader(is);
+ BufferedReader reader = new BufferedReader(isr)) {
+ data.put(UTILITY_SCRIPTS, reader.lines().collect(
+ Collectors.joining(System.lineSeparator())));
+ }
+ } else {
+ data.put(UTILITY_SCRIPTS, "");
+ }
+
+ return data;
+ }
+
+ private Map<String, String> createDataForDesktopFile(
+ Map<String, ? super Object> params) {
+ Map<String, String> data = new HashMap<>();
+ data.put("APPLICATION_NAME", APP_NAME.fetchFrom(params));
+ data.put("APPLICATION_DESCRIPTION", DESCRIPTION.fetchFrom(params));
+ data.put("APPLICATION_ICON",
+ iconFile != null ? iconFile.installPath().toString() : null);
+ data.put("DEPLOY_BUNDLE_CATEGORY", MENU_GROUP.fetchFrom(params));
+ data.put("APPLICATION_LAUNCHER",
+ thePackage.installedApplicationLayout().launchersDirectory().resolve(
+ LinuxAppImageBuilder.getLauncherName(params)).toString());
+
+ return data;
+ }
+
+ /**
+ * Shell commands to integrate something with desktop.
+ */
+ private class ShellCommands {
+
+ ShellCommands() {
+ registerIconCmds = new ArrayList<>();
+ unregisterIconCmds = new ArrayList<>();
+
+ registerDesktopFileCmd = String.join(" ", "xdg-desktop-menu",
+ "install", desktopFile.installPath().toString());
+ unregisterDesktopFileCmd = String.join(" ", "xdg-desktop-menu",
+ "uninstall", desktopFile.installPath().toString());
+ }
+
+ void setFileAssociations() {
+ registerFileAssociationsCmd = String.join(" ", "xdg-mime",
+ "install",
+ mimeInfoFile.installPath().toString());
+ unregisterFileAssociationsCmd = String.join(" ", "xdg-mime",
+ "uninstall", mimeInfoFile.installPath().toString());
+
+ //
+ // Add manual cleanup of system files to get rid of
+ // the default mime type handlers.
+ //
+ // Even after mime type is unregisterd with `xdg-mime uninstall`
+ // command and desktop file deleted with `xdg-desktop-menu uninstall`
+ // command, records in
+ // `/usr/share/applications/defaults.list` (Ubuntu 16) or
+ // `/usr/local/share/applications/defaults.list` (OracleLinux 7)
+ // files remain referencing deleted mime time and deleted
+ // desktop file which makes `xdg-mime query default` output name
+ // of non-existing desktop file.
+ //
+ String cleanUpCommand = String.join(" ",
+ "uninstall_default_mime_handler",
+ desktopFile.installPath().getFileName().toString(),
+ String.join(" ", getMimeTypeNamesFromFileAssociations()));
+
+ unregisterFileAssociationsCmd = stringifyShellCommands(
+ unregisterFileAssociationsCmd, cleanUpCommand);
+ }
+
+ void addIcon(String mimeType, Path iconFile) {
+ final int imgSize = getSquareSizeOfImage(iconFile.toFile());
+ final String dashMime = mimeType.replace('/', '-');
+ registerIconCmds.add(String.join(" ", "xdg-icon-resource",
+ "install", "--context", "mimetypes", "--size ",
+ Integer.toString(imgSize), iconFile.toString(), dashMime));
+ unregisterIconCmds.add(String.join(" ", "xdg-icon-resource",
+ "uninstall", dashMime));
+ }
+
+ void applyTo(Map<String, String> data) {
+ List<String> cmds = new ArrayList<>();
+
+ cmds.add(registerDesktopFileCmd);
+ cmds.add(registerFileAssociationsCmd);
+ cmds.addAll(registerIconCmds);
+ data.put(DESKTOP_COMMANDS_INSTALL, stringifyShellCommands(cmds));
+
+ cmds.clear();
+ cmds.add(unregisterDesktopFileCmd);
+ cmds.add(unregisterFileAssociationsCmd);
+ cmds.addAll(unregisterIconCmds);
+ data.put(DESKTOP_COMMANDS_UNINSTALL, stringifyShellCommands(cmds));
+ }
+
+ private String registerDesktopFileCmd;
+ private String unregisterDesktopFileCmd;
+
+ private String registerFileAssociationsCmd;
+ private String unregisterFileAssociationsCmd;
+
+ private List<String> registerIconCmds;
+ private List<String> unregisterIconCmds;
+ }
+
+ private final PlatformPackage thePackage;
+
+ private final List<Map<String, ? super Object>> associations;
+
+ private final List<Map<String, ? super Object>> launchers;
+
+ /**
+ * Desktop integration file. xml, icon, etc.
+ * Resides somewhere in application installation tree.
+ * Has two paths:
+ * - path where it should be placed at package build time;
+ * - path where it should be installed by package manager;
+ */
+ private class DesktopFile {
+
+ DesktopFile(String fileName) {
+ installPath = thePackage
+ .installedApplicationLayout()
+ .destktopIntegrationDirectory().resolve(fileName);
+ srcPath = thePackage
+ .sourceApplicationLayout()
+ .destktopIntegrationDirectory().resolve(fileName);
+ }
+
+ private final Path installPath;
+ private final Path srcPath;
+
+ Path installPath() {
+ return installPath;
+ }
+
+ Path srcPath() {
+ return srcPath;
+ }
+ }
+
+ private final boolean verbose;
+ private final File resourceDir;
+
+ private final DesktopFile mimeInfoFile;
+ private final DesktopFile desktopFile;
+ private final DesktopFile iconFile;
+
+ private final Map<String, String> desktopFileData;
+
+ /**
+ * Path to icon file provided by user or null.
+ */
+ private final File customIconFile;
+
+ private void appendFileAssociation(XMLStreamWriter xml,
+ Map<String, ? super Object> assoc) throws XMLStreamException {
+
+ xml.writeStartElement("mime-type");
+ final String thisMime = FA_CONTENT_TYPE.fetchFrom(assoc).get(0);
+ xml.writeAttribute("type", thisMime);
+
+ final String description = FA_DESCRIPTION.fetchFrom(assoc);
+ if (description != null && !description.isEmpty()) {
+ xml.writeStartElement("comment");
+ xml.writeCharacters(description);
+ xml.writeEndElement();
+ }
+
+ final List<String> extensions = FA_EXTENSIONS.fetchFrom(assoc);
+ if (extensions == null) {
+ Log.error(I18N.getString(
+ "message.creating-association-with-null-extension"));
+ } else {
+ for (String ext : extensions) {
+ xml.writeStartElement("glob");
+ xml.writeAttribute("pattern", "*." + ext);
+ xml.writeEndElement();
+ }
+ }
+
+ xml.writeEndElement();
+ }
+
+ private void createFileAssociationsMimeInfoFile() throws IOException {
+ XMLOutputFactory xmlFactory = XMLOutputFactory.newInstance();
+
+ try (Writer w = new BufferedWriter(new FileWriter(
+ mimeInfoFile.srcPath().toFile()))) {
+ XMLStreamWriter xml = xmlFactory.createXMLStreamWriter(w);
+
+ xml.writeStartDocument();
+ xml.writeStartElement("mime-info");
+ xml.writeNamespace("xmlns",
+ "http://www.freedesktop.org/standards/shared-mime-info");
+
+ for (var assoc : associations) {
+ appendFileAssociation(xml, assoc);
+ }
+
+ xml.writeEndElement();
+ xml.writeEndDocument();
+ xml.flush();
+ xml.close();
+
+ } catch (XMLStreamException ex) {
+ Log.verbose(ex);
+ throw new IOException(ex);
+ }
+ }
+
+ private Map<String, Path> createFileAssociationIconFiles() throws
+ IOException {
+ Map<String, Path> mimeTypeWithIconFile = new HashMap<>();
+ for (var assoc : associations) {
+ File customFaIcon = FA_ICON.fetchFrom(assoc);
+ if (customFaIcon == null || !customFaIcon.exists() || getSquareSizeOfImage(
+ customFaIcon) == 0) {
+ continue;
+ }
+
+ String fname = iconFile.srcPath().getFileName().toString();
+ if (fname.indexOf(".") > 0) {
+ fname = fname.substring(0, fname.lastIndexOf("."));
+ }
+
+ DesktopFile faIconFile = new DesktopFile(
+ fname + "_fa_" + customFaIcon.getName());
+
+ IOUtils.copyFile(customFaIcon, faIconFile.srcPath().toFile());
+
+ mimeTypeWithIconFile.put(FA_CONTENT_TYPE.fetchFrom(assoc).get(0),
+ faIconFile.installPath());
+ }
+ return mimeTypeWithIconFile;
+ }
+
+ private void createDesktopFile(Map<String, String> data) throws IOException {
+ List<String> mimeTypes = getMimeTypeNamesFromFileAssociations();
+ data.put("DESKTOP_MIMES", "MimeType=" + String.join(";", mimeTypes));
+
+ // prepare desktop shortcut
+ try (Writer w = Files.newBufferedWriter(desktopFile.srcPath())) {
+ String content = preprocessTextResource(
+ desktopFile.srcPath().getFileName().toString(),
+ I18N.getString("resource.menu-shortcut-descriptor"),
+ "template.desktop",
+ data,
+ verbose,
+ resourceDir);
+ w.write(content);
+ }
+ }
+
+ private void prepareSrcIconFile() throws IOException {
+ if (customIconFile == null || !customIconFile.exists()) {
+ fetchResource(iconFile.srcPath().getFileName().toString(),
+ I18N.getString("resource.menu-icon"),
+ DEFAULT_ICON,
+ iconFile.srcPath().toFile(),
+ verbose,
+ resourceDir);
+ } else {
+ fetchResource(iconFile.srcPath().getFileName().toString(),
+ I18N.getString("resource.menu-icon"),
+ customIconFile,
+ iconFile.srcPath().toFile(),
+ verbose,
+ resourceDir);
+ }
+ }
+
+ private List<String> getMimeTypeNamesFromFileAssociations() {
+ return associations.stream().map(
+ a -> FA_CONTENT_TYPE.fetchFrom(a).get(0)).collect(
+ Collectors.toUnmodifiableList());
+ }
+ }
+
+ private static int getSquareSizeOfImage(File f) {
+ try {
+ BufferedImage bi = ImageIO.read(f);
+ if (bi.getWidth() == bi.getHeight()) {
+ return bi.getWidth();
+ }
+ } catch (IOException e) {
+ Log.verbose(e);
+ }
+ return 0;
+ }
+
+ private static String stringifyShellCommands(String ... commands) {
+ return stringifyShellCommands(Arrays.asList(commands));
+ }
+
+ private static String stringifyShellCommands(List<String> commands) {
+ return String.join(System.lineSeparator(), commands.stream().filter(
+ s -> s != null && !s.isEmpty()).collect(Collectors.toList()));
+ }
+}
--- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java Mon Sep 16 19:24:32 2019 -0400
+++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java Tue Sep 24 13:41:16 2019 -0400
@@ -25,10 +25,9 @@
package jdk.jpackage.internal;
-import javax.imageio.ImageIO;
-import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Files;
+import java.nio.file.Path;
import java.text.MessageFormat;
import java.util.*;
import java.util.regex.Matcher;
@@ -36,7 +35,6 @@
import static jdk.jpackage.internal.StandardBundlerParam.*;
import static jdk.jpackage.internal.LinuxAppBundler.LINUX_INSTALL_DIR;
-import static jdk.jpackage.internal.LinuxAppBundler.LINUX_PACKAGE_DEPENDENCIES;
/**
* There are two command line options to configure license information for RPM
@@ -49,28 +47,7 @@
* to set license information. --license-file makes little sense in case of RPM
* packaging.
*/
-public class LinuxRpmBundler extends AbstractBundler {
-
- private static final ResourceBundle I18N = ResourceBundle.getBundle(
- "jdk.jpackage.internal.resources.LinuxResources");
-
- public static final BundlerParamInfo<LinuxAppBundler> APP_BUNDLER =
- new StandardBundlerParam<>(
- "linux.app.bundler",
- LinuxAppBundler.class,
- params -> new LinuxAppBundler(),
- null);
-
- public static final BundlerParamInfo<File> RPM_IMAGE_DIR =
- new StandardBundlerParam<>(
- "linux.rpm.imageDir",
- File.class,
- params -> {
- File imagesRoot = IMAGES_ROOT.fetchFrom(params);
- if (!imagesRoot.exists()) imagesRoot.mkdirs();
- return new File(imagesRoot, "linux-rpm.image");
- },
- (s, p) -> new File(s));
+public class LinuxRpmBundler extends LinuxPackageBundler {
// Fedora rules for package naming are used here
// https://fedoraproject.org/wiki/Packaging:NamingGuidelines?rd=Packaging/NamingGuidelines
@@ -80,10 +57,10 @@
//
// abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._+
//
- private static final Pattern RPM_BUNDLE_NAME_PATTERN =
+ private static final Pattern RPM_PACKAGE_NAME_PATTERN =
Pattern.compile("[a-z\\d\\+\\-\\.\\_]+", Pattern.CASE_INSENSITIVE);
- public static final BundlerParamInfo<String> BUNDLE_NAME =
+ public static final BundlerParamInfo<String> PACKAGE_NAME =
new StandardBundlerParam<> (
Arguments.CLIOptions.LINUX_BUNDLE_NAME.getId(),
String.class,
@@ -97,7 +74,7 @@
return nm;
},
(s, p) -> {
- if (!RPM_BUNDLE_NAME_PATTERN.matcher(s).matches()) {
+ if (!RPM_PACKAGE_NAME_PATTERN.matcher(s).matches()) {
String msgKey = "error.invalid-value-for-package-name";
throw new IllegalArgumentException(
new ConfigException(MessageFormat.format(
@@ -109,14 +86,6 @@
}
);
- public static final BundlerParamInfo<String> MENU_GROUP =
- new StandardBundlerParam<>(
- Arguments.CLIOptions.LINUX_MENU_GROUP.getId(),
- String.class,
- params -> I18N.getString("param.menu-group.default"),
- (s, p) -> s
- );
-
public static final BundlerParamInfo<String> LICENSE_TYPE =
new StandardBundlerParam<>(
Arguments.CLIOptions.LINUX_RPM_LICENSE_TYPE.getId(),
@@ -132,41 +101,7 @@
params -> null,
(s, p) -> s);
- public static final BundlerParamInfo<String> XDG_FILE_PREFIX =
- new StandardBundlerParam<> (
- "linux.xdg-prefix",
- String.class,
- params -> {
- try {
- String vendor;
- if (params.containsKey(VENDOR.getID())) {
- vendor = VENDOR.fetchFrom(params);
- } else {
- vendor = "jpackage";
- }
- String appName = APP_NAME.fetchFrom(params);
-
- return (vendor + "-" + appName).replaceAll("\\s", "");
- } catch (Exception e) {
- Log.verbose(e);
- }
- return "unknown-MimeInfo.xml";
- },
- (s, p) -> s);
-
- public static final StandardBundlerParam<Boolean> SHORTCUT_HINT =
- new StandardBundlerParam<>(
- Arguments.CLIOptions.LINUX_SHORTCUT_HINT.getId(),
- Boolean.class,
- params -> false,
- (s, p) -> (s == null || "null".equalsIgnoreCase(s))
- ? false : Boolean.valueOf(s)
- );
-
- private final static String DEFAULT_ICON = "java32.png";
private final static String DEFAULT_SPEC_TEMPLATE = "template.spec";
- private final static String DEFAULT_DESKTOP_FILE_TEMPLATE =
- "template.desktop";
public final static String TOOL_RPMBUILD = "rpmbuild";
public final static double TOOL_RPMBUILD_MIN_VERSION = 4.0d;
@@ -195,430 +130,72 @@
}
}
- @Override
- public boolean validate(Map<String, ? super Object> params)
- throws 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
- APP_BUNDLER.fetchFrom(params).validate(params);
-
- // validate presense of required tools
- if (!testTool(TOOL_RPMBUILD, TOOL_RPMBUILD_MIN_VERSION)){
- throw new ConfigException(
- MessageFormat.format(
- I18N.getString("error.cannot-find-rpmbuild"),
- TOOL_RPMBUILD_MIN_VERSION),
- MessageFormat.format(
- I18N.getString("error.cannot-find-rpmbuild.advice"),
- TOOL_RPMBUILD_MIN_VERSION));
- }
-
- // only one mime type per association, at least one file extension
- List<Map<String, ? super Object>> associations =
- FILE_ASSOCIATIONS.fetchFrom(params);
- if (associations != null) {
- for (int i = 0; i < associations.size(); i++) {
- Map<String, ? super Object> assoc = associations.get(i);
- List<String> mimes = FA_CONTENT_TYPE.fetchFrom(assoc);
- if (mimes == null || mimes.isEmpty()) {
- String msgKey =
- "error.no-content-types-for-file-association";
- throw new ConfigException(
- MessageFormat.format(I18N.getString(msgKey), i),
- I18N.getString(msgKey + ".advice"));
- } else if (mimes.size() > 1) {
- String msgKey =
- "error.no-content-types-for-file-association";
- throw new ConfigException(
- MessageFormat.format(I18N.getString(msgKey), i),
- I18N.getString(msgKey + ".advice"));
- }
- }
- }
-
- // bundle name has some restrictions
- // the string converter will throw an exception if invalid
- BUNDLE_NAME.getStringConverter().apply(
- BUNDLE_NAME.fetchFrom(params), params);
-
- return true;
- } catch (RuntimeException re) {
- if (re.getCause() instanceof ConfigException) {
- throw (ConfigException) re.getCause();
- } else {
- throw new ConfigException(re);
- }
- }
+ public LinuxRpmBundler() {
+ super(PACKAGE_NAME);
}
- private boolean prepareProto(Map<String, ? super Object> params)
- throws PackagerException, IOException {
- File appImage = StandardBundlerParam.getPredefinedAppImage(params);
- File appDir = null;
-
- // we either have an application image or need to build one
- if (appImage != null) {
- appDir = new File(RPM_IMAGE_DIR.fetchFrom(params),
- APP_NAME.fetchFrom(params));
- // copy everything from appImage dir into appDir/name
- IOUtils.copyRecursive(appImage.toPath(), appDir.toPath());
- } else {
- appDir = APP_BUNDLER.fetchFrom(params).doBundle(params,
- RPM_IMAGE_DIR.fetchFrom(params), true);
- }
- return appDir != null;
- }
+ @Override
+ public void doValidate(Map<String, ? super Object> params)
+ throws ConfigException {
+ if (params == null) throw new ConfigException(
+ I18N.getString("error.parameters-null"),
+ I18N.getString("error.parameters-null.advice"));
- public File bundle(Map<String, ? super Object> params,
- File outdir) throws PackagerException {
-
- IOUtils.writableOutputDir(outdir.toPath());
-
- File imageDir = RPM_IMAGE_DIR.fetchFrom(params);
- try {
-
- imageDir.mkdirs();
-
- if (prepareProto(params) && prepareProjectConfig(params)) {
- return buildRPM(params, outdir);
- }
- return null;
- } catch (IOException ex) {
- Log.verbose(ex);
- throw new PackagerException(ex);
+ // validate presense of required tools
+ if (!testTool(TOOL_RPMBUILD, TOOL_RPMBUILD_MIN_VERSION)){
+ throw new ConfigException(
+ MessageFormat.format(
+ I18N.getString("error.cannot-find-rpmbuild"),
+ TOOL_RPMBUILD_MIN_VERSION),
+ MessageFormat.format(
+ I18N.getString("error.cannot-find-rpmbuild.advice"),
+ TOOL_RPMBUILD_MIN_VERSION));
}
}
- private boolean prepareProjectConfig(Map<String, ? super Object> params)
- throws IOException {
- Map<String, String> data = createReplacementData(params);
- File rootDir =
- LinuxAppBundler.getRootDir(RPM_IMAGE_DIR.fetchFrom(params), params);
- File binDir = new File(rootDir, "bin");
-
- // prepare installer icon
- File iconTarget = getConfig_IconFile(binDir, params);
- File icon = LinuxAppBundler.ICON_PNG.fetchFrom(params);
- if (!StandardBundlerParam.isRuntimeInstaller(params)) {
- if (icon == null || !icon.exists()) {
- fetchResource(iconTarget.getName(),
- I18N.getString("resource.menu-icon"),
- DEFAULT_ICON,
- iconTarget,
- VERBOSE.fetchFrom(params),
- RESOURCE_DIR.fetchFrom(params));
- } else {
- fetchResource(iconTarget.getName(),
- I18N.getString("resource.menu-icon"),
- icon,
- iconTarget,
- VERBOSE.fetchFrom(params),
- RESOURCE_DIR.fetchFrom(params));
- }
- }
-
- StringBuilder installScripts = new StringBuilder();
- StringBuilder removeScripts = new StringBuilder();
- for (Map<String, ? super Object> addLauncher :
- ADD_LAUNCHERS.fetchFrom(params)) {
- Map<String, String> addLauncherData =
- createReplacementData(addLauncher);
- addLauncherData.put("APPLICATION_FS_NAME",
- data.get("APPLICATION_FS_NAME"));
- addLauncherData.put("DESKTOP_MIMES", "");
-
- // prepare desktop shortcut
- if (SHORTCUT_HINT.fetchFrom(params)) {
- try (Writer w = Files.newBufferedWriter(
- getConfig_DesktopShortcutFile(binDir,
- addLauncher).toPath())) {
- String content = preprocessTextResource(
- getConfig_DesktopShortcutFile(binDir,
- addLauncher).getName(),
- I18N.getString("resource.menu-shortcut-descriptor"),
- DEFAULT_DESKTOP_FILE_TEMPLATE, addLauncherData,
- VERBOSE.fetchFrom(params),
- RESOURCE_DIR.fetchFrom(params));
- w.write(content);
- }
- }
-
- // prepare installer icon
- iconTarget = getConfig_IconFile(binDir, addLauncher);
- icon = LinuxAppBundler.ICON_PNG.fetchFrom(addLauncher);
- if (icon == null || !icon.exists()) {
- fetchResource(iconTarget.getName(),
- I18N.getString("resource.menu-icon"),
- DEFAULT_ICON,
- iconTarget,
- VERBOSE.fetchFrom(params),
- RESOURCE_DIR.fetchFrom(params));
- } else {
- fetchResource(iconTarget.getName(),
- I18N.getString("resource.menu-icon"),
- icon,
- iconTarget,
- VERBOSE.fetchFrom(params),
- RESOURCE_DIR.fetchFrom(params));
- }
-
- // post copying of desktop icon
- installScripts.append("xdg-desktop-menu install --novendor ");
- installScripts.append(LINUX_INSTALL_DIR.fetchFrom(params));
- installScripts.append("/");
- installScripts.append(data.get("APPLICATION_FS_NAME"));
- installScripts.append("/bin/");
- installScripts.append(addLauncherData.get(
- "APPLICATION_LAUNCHER_FILENAME"));
- installScripts.append(".desktop\n");
-
- // preun cleanup of desktop icon
- removeScripts.append("xdg-desktop-menu uninstall --novendor ");
- removeScripts.append(LINUX_INSTALL_DIR.fetchFrom(params));
- removeScripts.append("/");
- removeScripts.append(data.get("APPLICATION_FS_NAME"));
- removeScripts.append("/bin/");
- removeScripts.append(addLauncherData.get(
- "APPLICATION_LAUNCHER_FILENAME"));
- removeScripts.append(".desktop\n");
-
- }
- data.put("ADD_LAUNCHERS_INSTALL", installScripts.toString());
- data.put("ADD_LAUNCHERS_REMOVE", removeScripts.toString());
-
- StringBuilder cdsScript = new StringBuilder();
-
- data.put("APP_CDS_CACHE", cdsScript.toString());
-
- List<Map<String, ? super Object>> associations =
- FILE_ASSOCIATIONS.fetchFrom(params);
- data.put("FILE_ASSOCIATION_INSTALL", "");
- data.put("FILE_ASSOCIATION_REMOVE", "");
- data.put("DESKTOP_MIMES", "");
- if (associations != null) {
- String mimeInfoFile = XDG_FILE_PREFIX.fetchFrom(params)
- + "-MimeInfo.xml";
- StringBuilder mimeInfo = new StringBuilder(
- "<?xml version=\"1.0\"?>\n<mime-info xmlns="
- +"'http://www.freedesktop.org/standards/shared-mime-info'>\n");
- StringBuilder registrations = new StringBuilder();
- StringBuilder deregistrations = new StringBuilder();
- StringBuilder desktopMimes = new StringBuilder("MimeType=");
- boolean addedEntry = false;
-
- for (Map<String, ? super Object> assoc : associations) {
- // <mime-type type="application/x-vnd.awesome">
- // <comment>Awesome document</comment>
- // <glob pattern="*.awesome"/>
- // <glob pattern="*.awe"/>
- // </mime-type>
-
- if (assoc == null) {
- continue;
- }
+ @Override
+ protected File buildPackageBundle(
+ Map<String, String> replacementData,
+ Map<String, ? super Object> params, File outputParentDir) throws
+ PackagerException, IOException {
- String description = FA_DESCRIPTION.fetchFrom(assoc);
- File faIcon = FA_ICON.fetchFrom(assoc);
- List<String> extensions = FA_EXTENSIONS.fetchFrom(assoc);
- if (extensions == null) {
- Log.verbose(I18N.getString(
- "message.creating-association-with-null-extension"));
- }
-
- List<String> mimes = FA_CONTENT_TYPE.fetchFrom(assoc);
- if (mimes == null || mimes.isEmpty()) {
- continue;
- }
- String thisMime = mimes.get(0);
- String dashMime = thisMime.replace('/', '-');
-
- mimeInfo.append(" <mime-type type='")
- .append(thisMime)
- .append("'>\n");
- if (description != null && !description.isEmpty()) {
- mimeInfo.append(" <comment>")
- .append(description)
- .append("</comment>\n");
- }
-
- if (extensions != null) {
- for (String ext : extensions) {
- mimeInfo.append(" <glob pattern='*.")
- .append(ext)
- .append("'/>\n");
- }
- }
-
- mimeInfo.append(" </mime-type>\n");
- if (!addedEntry) {
- registrations.append("xdg-mime install ")
- .append(LINUX_INSTALL_DIR.fetchFrom(params))
- .append("/")
- .append(data.get("APPLICATION_FS_NAME"))
- .append("/bin/")
- .append(mimeInfoFile)
- .append("\n");
-
- deregistrations.append("xdg-mime uninstall ")
- .append(LINUX_INSTALL_DIR.fetchFrom(params))
- .append("/")
- .append(data.get("APPLICATION_FS_NAME"))
- .append("/bin/")
- .append(mimeInfoFile)
- .append("\n");
- addedEntry = true;
- } else {
- desktopMimes.append(";");
- }
- desktopMimes.append(thisMime);
-
- if (faIcon != null && faIcon.exists()) {
- int size = getSquareSizeOfImage(faIcon);
-
- if (size > 0) {
- File target = new File(binDir,
- APP_NAME.fetchFrom(params)
- + "_fa_" + faIcon.getName());
- IOUtils.copyFile(faIcon, target);
-
- // xdg-icon-resource install --context mimetypes
- // --size 64 awesomeapp_fa_1.png
- // application-x.vnd-awesome
- registrations.append(
- "xdg-icon-resource install "
- + "--context mimetypes --size ")
- .append(size)
- .append(" ")
- .append(LINUX_INSTALL_DIR.fetchFrom(params))
- .append("/")
- .append(data.get("APPLICATION_FS_NAME"))
- .append("/")
- .append(target.getName())
- .append(" ")
- .append(dashMime)
- .append("\n");
-
- // xdg-icon-resource uninstall --context mimetypes
- // --size 64 awesomeapp_fa_1.png
- // application-x.vnd-awesome
- deregistrations.append(
- "xdg-icon-resource uninstall "
- + "--context mimetypes --size ")
- .append(size)
- .append(" ")
- .append(LINUX_INSTALL_DIR.fetchFrom(params))
- .append("/")
- .append(data.get("APPLICATION_FS_NAME"))
- .append("/")
- .append(target.getName())
- .append(" ")
- .append(dashMime)
- .append("\n");
- }
- }
- }
- mimeInfo.append("</mime-info>");
-
- if (addedEntry) {
- try (Writer w = Files.newBufferedWriter(
- new File(binDir, mimeInfoFile).toPath())) {
- w.write(mimeInfo.toString());
- }
- data.put("FILE_ASSOCIATION_INSTALL", registrations.toString());
- data.put("FILE_ASSOCIATION_REMOVE", deregistrations.toString());
- data.put("DESKTOP_MIMES", desktopMimes.toString());
- }
- }
-
- if (!StandardBundlerParam.isRuntimeInstaller(params)) {
- // prepare desktop shortcut
- if (SHORTCUT_HINT.fetchFrom(params)) {
- try (Writer w = Files.newBufferedWriter(
- getConfig_DesktopShortcutFile(binDir, params).toPath())) {
- String content = preprocessTextResource(
- getConfig_DesktopShortcutFile(binDir,
- params).getName(),
- I18N.getString("resource.menu-shortcut-descriptor"),
- DEFAULT_DESKTOP_FILE_TEMPLATE, data,
- VERBOSE.fetchFrom(params),
- RESOURCE_DIR.fetchFrom(params));
- w.write(content);
- }
- }
- }
+ Path specFile = specFile(params);
// prepare spec file
- try (Writer w = Files.newBufferedWriter(
- getConfig_SpecFile(params).toPath())) {
+ Files.createDirectories(specFile.getParent());
+ try (Writer w = Files.newBufferedWriter(specFile)) {
String content = preprocessTextResource(
- getConfig_SpecFile(params).getName(),
+ specFile.getFileName().toString(),
I18N.getString("resource.rpm-spec-file"),
- DEFAULT_SPEC_TEMPLATE, data,
+ DEFAULT_SPEC_TEMPLATE, replacementData,
VERBOSE.fetchFrom(params),
RESOURCE_DIR.fetchFrom(params));
w.write(content);
}
- return true;
+ return buildRPM(params, outputParentDir);
}
- private Map<String, String> createReplacementData(
+ @Override
+ protected Map<String, String> createReplacementData(
Map<String, ? super Object> params) throws IOException {
Map<String, String> data = new HashMap<>();
- String launcher = LinuxAppImageBuilder.getLauncherRelativePath(params);
- data.put("APPLICATION_NAME", APP_NAME.fetchFrom(params));
- data.put("APPLICATION_FS_NAME", APP_NAME.fetchFrom(params));
- data.put("APPLICATION_PACKAGE", BUNDLE_NAME.fetchFrom(params));
- data.put("APPLICATION_VENDOR", VENDOR.fetchFrom(params));
- data.put("APPLICATION_VERSION", VERSION.fetchFrom(params));
- data.put("APPLICATION_RELEASE", RELEASE.fetchFrom(params));
- data.put("APPLICATION_LAUNCHER_FILENAME", launcher);
- data.put("INSTALLATION_DIRECTORY", LINUX_INSTALL_DIR.fetchFrom(params));
- data.put("XDG_PREFIX", XDG_FILE_PREFIX.fetchFrom(params));
- data.put("DEPLOY_BUNDLE_CATEGORY", MENU_GROUP.fetchFrom(params));
- data.put("APPLICATION_DESCRIPTION", DESCRIPTION.fetchFrom(params));
+ data.put("APPLICATION_DIRECTORY", Path.of(LINUX_INSTALL_DIR.fetchFrom(
+ params), PACKAGE_NAME.fetchFrom(params)).toString());
data.put("APPLICATION_SUMMARY", APP_NAME.fetchFrom(params));
data.put("APPLICATION_LICENSE_TYPE", LICENSE_TYPE.fetchFrom(params));
-
- String licenseFile = LICENSE_FILE.fetchFrom(params);
- if (licenseFile == null) {
- licenseFile = "";
- }
- data.put("APPLICATION_LICENSE_FILE", licenseFile);
+ data.put("APPLICATION_LICENSE_FILE", Optional.ofNullable(
+ LICENSE_FILE.fetchFrom(params)).orElse(""));
+ data.put("APPLICATION_GROUP", Optional.ofNullable(
+ GROUP.fetchFrom(params)).orElse(""));
- String group = GROUP.fetchFrom(params);
- if (group == null) {
- group = "";
- }
- data.put("APPLICATION_GROUP", group);
-
- String deps = LINUX_PACKAGE_DEPENDENCIES.fetchFrom(params);
- data.put("PACKAGE_DEPENDENCIES",
- deps.isEmpty() ? "" : "Requires: " + deps);
- data.put("RUNTIME_INSTALLER", "" +
- StandardBundlerParam.isRuntimeInstaller(params));
return data;
}
- private File getConfig_DesktopShortcutFile(File rootDir,
- Map<String, ? super Object> params) {
- return new File(rootDir, APP_NAME.fetchFrom(params) + ".desktop");
- }
-
- private File getConfig_IconFile(File rootDir,
- Map<String, ? super Object> params) {
- return new File(rootDir, APP_NAME.fetchFrom(params) + ".png");
- }
-
- private File getConfig_SpecFile(Map<String, ? super Object> params) {
- return new File(RPM_IMAGE_DIR.fetchFrom(params),
- APP_NAME.fetchFrom(params) + ".spec");
+ private Path specFile(Map<String, ? super Object> params) {
+ return TEMP_ROOT.fetchFrom(params).toPath().resolve(Path.of("SPECS",
+ PACKAGE_NAME.fetchFrom(params) + ".spec"));
}
private File buildRPM(Map<String, ? super Object> params,
@@ -627,22 +204,19 @@
"message.outputting-bundle-location"),
outdir.getAbsolutePath()));
- File broot = new File(TEMP_ROOT.fetchFrom(params), "rmpbuildroot");
-
- outdir.mkdirs();
+ PlatformPackage thePackage = createMetaPackage(params);
//run rpmbuild
ProcessBuilder pb = new ProcessBuilder(
TOOL_RPMBUILD,
- "-bb", getConfig_SpecFile(params).getAbsolutePath(),
- "--define", "%_sourcedir "
- + RPM_IMAGE_DIR.fetchFrom(params).getAbsolutePath(),
+ "-bb", specFile(params).toAbsolutePath().toString(),
+ "--define", String.format("%%_sourcedir %s", thePackage.sourceRoot()),
// save result to output dir
- "--define", "%_rpmdir " + outdir.getAbsolutePath(),
+ "--define", String.format("%%_rpmdir %s", outdir.getAbsolutePath()),
// do not use other system directories to build as current user
- "--define", "%_topdir " + broot.getAbsolutePath()
+ "--define", String.format("%%_topdir %s",
+ TEMP_ROOT.fetchFrom(params).toPath().toAbsolutePath())
);
- pb = pb.directory(RPM_IMAGE_DIR.fetchFrom(params));
IOUtils.exec(pb);
Log.verbose(MessageFormat.format(
@@ -678,22 +252,7 @@
}
@Override
- public String getBundleType() {
- return "INSTALLER";
- }
-
- @Override
- public File execute(Map<String, ? super Object> params,
- File outputParentDir) throws PackagerException {
- return bundle(params, outputParentDir);
- }
-
- @Override
public boolean supported(boolean runtimeInstaller) {
- return isSupported();
- }
-
- public static boolean isSupported() {
if (Platform.getPlatform() == Platform.LINUX) {
if (testTool(TOOL_RPMBUILD, TOOL_RPMBUILD_MIN_VERSION)) {
return true;
@@ -702,20 +261,6 @@
return false;
}
- public int getSquareSizeOfImage(File f) {
- try {
- BufferedImage bi = ImageIO.read(f);
- if (bi.getWidth() == bi.getHeight()) {
- return bi.getWidth();
- } else {
- return 0;
- }
- } catch (Exception e) {
- e.printStackTrace();
- return 0;
- }
- }
-
@Override
public boolean isDefault() {
return !LinuxDebBundler.isDebian();
--- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/template.desktop Mon Sep 16 19:24:32 2019 -0400
+++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/template.desktop Tue Sep 24 13:41:16 2019 -0400
@@ -1,8 +1,8 @@
[Desktop Entry]
Name=APPLICATION_NAME
Comment=APPLICATION_DESCRIPTION
-Exec=INSTALLATION_DIRECTORY/APPLICATION_FS_NAME/APPLICATION_LAUNCHER_FILENAME
-Icon=INSTALLATION_DIRECTORY/APPLICATION_FS_NAME/APPLICATION_LAUNCHER_FILENAME.png
+Exec=APPLICATION_LAUNCHER
+Icon=APPLICATION_ICON
Terminal=false
Type=Application
Categories=DEPLOY_BUNDLE_CATEGORY
--- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/template.postinst Mon Sep 16 19:24:32 2019 -0400
+++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/template.postinst Tue Sep 24 13:41:16 2019 -0400
@@ -1,5 +1,5 @@
#!/bin/sh
-# postinst script for APPLICATION_NAME
+# postinst script for APPLICATION_PACKAGE
#
# see: dh_installdeb(1)
@@ -19,12 +19,7 @@
case "$1" in
configure)
- if [ "RUNTIME_INSTALLER" != "true" ]; then
- echo Adding shortcut to the menu
-ADD_LAUNCHERS_INSTALL
- xdg-desktop-menu install --novendor INSTALLATION_DIRECTORY/APPLICATION_FS_NAME/APPLICATION_LAUNCHER_FILENAME.desktop
-FILE_ASSOCIATION_INSTALL
- fi
+DESKTOP_COMMANDS_INSTALL
;;
abort-upgrade|abort-remove|abort-deconfigure)
--- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/template.postrm Mon Sep 16 19:24:32 2019 -0400
+++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/template.postrm Tue Sep 24 13:41:16 2019 -0400
@@ -1,5 +1,5 @@
#!/bin/sh
-# postrm script for APPLICATION_NAME
+# postrm script for APPLICATION_PACKAGE
#
# see: dh_installdeb(1)
--- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/template.preinst Mon Sep 16 19:24:32 2019 -0400
+++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/template.preinst Tue Sep 24 13:41:16 2019 -0400
@@ -1,5 +1,5 @@
#!/bin/sh
-# preinst script for APPLICATION_NAME
+# preinst script for APPLICATION_PACKAGE
#
# see: dh_installdeb(1)
--- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/template.prerm Mon Sep 16 19:24:32 2019 -0400
+++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/template.prerm Tue Sep 24 13:41:16 2019 -0400
@@ -1,5 +1,5 @@
#!/bin/sh
-# prerm script for APPLICATION_NAME
+# prerm script for APPLICATION_PACKAGE
#
# see: dh_installdeb(1)
@@ -17,14 +17,11 @@
# the debian-policy package
+UTILITY_SCRIPTS
+
case "$1" in
remove|upgrade|deconfigure)
- if [ "RUNTIME_INSTALLER" != "true" ]; then
- echo Removing shortcut
-ADD_LAUNCHERS_REMOVE
- xdg-desktop-menu uninstall --novendor INSTALLATION_DIRECTORY/APPLICATION_FS_NAME/APPLICATION_LAUNCHER_FILENAME.desktop
-FILE_ASSOCIATION_REMOVE
- fi
+DESKTOP_COMMANDS_UNINSTALL
;;
failed-upgrade)
--- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/template.spec Mon Sep 16 19:24:32 2019 -0400
+++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/template.spec Tue Sep 24 13:41:16 2019 -0400
@@ -4,7 +4,7 @@
Release: APPLICATION_RELEASE
License: APPLICATION_LICENSE_TYPE
Vendor: APPLICATION_VENDOR
-Prefix: INSTALLATION_DIRECTORY
+Prefix: %{dirname:APPLICATION_DIRECTORY}
Provides: APPLICATION_PACKAGE
%if "xAPPLICATION_GROUP" != x
Group: APPLICATION_GROUP
@@ -12,7 +12,9 @@
Autoprov: 0
Autoreq: 0
-PACKAGE_DEPENDENCIES
+%if "xPACKAGE_DEPENDENCIES" != x
+Requires: PACKAGE_DEPENDENCIES
+%endif
#avoid ARCH subfolder
%define _rpmfilename %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm
@@ -31,8 +33,8 @@
%install
rm -rf %{buildroot}
-mkdir -p %{buildroot}INSTALLATION_DIRECTORY
-cp -r %{_sourcedir}/APPLICATION_FS_NAME %{buildroot}INSTALLATION_DIRECTORY
+install -d -m 755 %{buildroot}APPLICATION_DIRECTORY
+cp -r %{_sourcedir}APPLICATION_DIRECTORY/* %{buildroot}APPLICATION_DIRECTORY
%if "xAPPLICATION_LICENSE_FILE" != x
%define license_install_file %{_defaultlicensedir}/%{name}-%{version}/%{basename:APPLICATION_LICENSE_FILE}
install -d -m 755 %{buildroot}%{dirname:%{license_install_file}}
@@ -40,24 +42,20 @@
%endif
%files
-%{?license_install_file:%license %{license_install_file}}
+%if "xAPPLICATION_LICENSE_FILE" != x
+ %license %{license_install_file}
+ %{dirname:%{license_install_file}}
+%endif
# If installation directory for the application is /a/b/c, we want only root
# component of the path (/a) in the spec file to make sure all subdirectories
# are owned by the package.
-%(echo INSTALLATION_DIRECTORY/APPLICATION_FS_NAME | sed -e "s|\(^/[^/]\{1,\}\).*$|\1|")
+%(echo APPLICATION_DIRECTORY | sed -e "s|\(^/[^/]\{1,\}\).*$|\1|")
%post
-if [ "RUNTIME_INSTALLER" != "true" ]; then
-ADD_LAUNCHERS_INSTALL
- xdg-desktop-menu install --novendor INSTALLATION_DIRECTORY/APPLICATION_FS_NAME/APPLICATION_LAUNCHER_FILENAME.desktop
-FILE_ASSOCIATION_INSTALL
-fi
+DESKTOP_COMMANDS_INSTALL
%preun
-if [ "RUNTIME_INSTALLER" != "true" ]; then
-ADD_LAUNCHERS_REMOVE
- xdg-desktop-menu uninstall --novendor INSTALLATION_DIRECTORY/APPLICATION_FS_NAME/APPLICATION_LAUNCHER_FILENAME.desktop
-FILE_ASSOCIATION_REMOVE
-fi
+UTILITY_SCRIPTS
+DESKTOP_COMMANDS_UNINSTALL
%clean
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/utils.sh Tue Sep 24 13:41:16 2019 -0400
@@ -0,0 +1,104 @@
+#
+# Remove $1 desktop file from the list of default handlers for $2 mime type
+# in $3 file dumping output to stdout.
+#
+_filter_out_default_mime_handler ()
+{
+ local defaults_list="$3"
+
+ local desktop_file="$1"
+ local mime_type="$2"
+
+ awk -f- "$defaults_list" <<EOF
+ BEGIN {
+ mime_type="$mime_type"
+ mime_type_regexp="~" mime_type "="
+ desktop_file="$desktop_file"
+ }
+ \$0 ~ mime_type {
+ \$0 = substr(\$0, length(mime_type) + 2);
+ split(\$0, desktop_files, ";")
+ remaining_desktop_files
+ counter=0
+ for (idx in desktop_files) {
+ if (desktop_files[idx] != desktop_file) {
+ ++counter;
+ }
+ }
+ if (counter) {
+ printf mime_type "="
+ for (idx in desktop_files) {
+ if (desktop_files[idx] != desktop_file) {
+ printf desktop_files[idx]
+ if (--counter) {
+ printf ";"
+ }
+ }
+ }
+ printf "\n"
+ }
+ next
+ }
+
+ { print }
+EOF
+}
+
+
+#
+# Remove $2 desktop file from the list of default handlers for $@ mime types
+# in $1 file.
+# Result is saved in $1 file.
+#
+_uninstall_default_mime_handler ()
+{
+ local defaults_list=$1
+ shift
+ [ -f "$defaults_list" ] || return 0
+
+ local desktop_file="$1"
+ shift
+
+ tmpfile1=$(mktemp)
+ tmpfile2=$(mktemp)
+ cat "$defaults_list" > "$tmpfile1"
+
+ local v
+ local update=
+ for mime in "$@"; do
+ _filter_out_default_mime_handler "$desktop_file" "$mime" "$tmpfile1" > "$tmpfile2"
+ v="$tmpfile2"
+ tmpfile2="$tmpfile1"
+ tmpfile1="$v"
+
+ if ! diff -q "$tmpfile1" "$tmpfile2" > /dev/null; then
+ update=yes
+ trace Remove $desktop_file default handler for $mime mime type from $defaults_list file
+ fi
+ done
+
+ if [ -n "$update" ]; then
+ cat "$tmpfile1" > "$defaults_list"
+ trace "$defaults_list" file updated
+ fi
+
+ rm -f "$tmpfile1" "$tmpfile2"
+}
+
+
+#
+# Remove $1 desktop file from the list of default handlers for $@ mime types
+# in all known system defaults lists.
+#
+uninstall_default_mime_handler ()
+{
+ for f in /usr/share/applications/defaults.list /usr/local/share/applications/defaults.list; do
+ _uninstall_default_mime_handler "$f" "$@"
+ done
+}
+
+
+trace ()
+{
+ echo "$@"
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayout.java Tue Sep 24 13:41:16 2019 -0400
@@ -0,0 +1,116 @@
+/*
+ * 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.nio.file.Path;
+import java.util.Map;
+
+
+/**
+ * Application directory layout.
+ */
+final class ApplicationLayout implements PathGroup.Facade<ApplicationLayout> {
+ enum PathRole {
+ RUNTIME, APP, LAUNCHERS_DIR, DESKTOP
+ }
+
+ ApplicationLayout(Map<Object, Path> paths) {
+ data = new PathGroup(paths);
+ }
+
+ private ApplicationLayout(PathGroup data) {
+ this.data = data;
+ }
+
+ @Override
+ public PathGroup pathGroup() {
+ return data;
+ }
+
+ @Override
+ public ApplicationLayout resolveAt(Path root) {
+ return new ApplicationLayout(pathGroup().resolveAt(root));
+ }
+
+ /**
+ * Path to launchers directory.
+ */
+ Path launchersDirectory() {
+ return pathGroup().getPath(PathRole.LAUNCHERS_DIR);
+ }
+
+ /**
+ * Path to application data directory.
+ */
+ Path appDirectory() {
+ return pathGroup().getPath(PathRole.APP);
+ }
+
+ /**
+ * Path to Java runtime directory.
+ */
+ Path runtimeDirectory() {
+ return pathGroup().getPath(PathRole.RUNTIME);
+ }
+
+ /**
+ * Path to directory with application's desktop integration files.
+ */
+ Path destktopIntegrationDirectory() {
+ return pathGroup().getPath(PathRole.DESKTOP);
+ }
+
+ static ApplicationLayout unixApp() {
+ return new ApplicationLayout(Map.of(
+ PathRole.LAUNCHERS_DIR, Path.of("bin"),
+ PathRole.APP, Path.of("app"),
+ PathRole.RUNTIME, Path.of("runtime"),
+ PathRole.DESKTOP, Path.of("bin")
+ ));
+ }
+
+ static ApplicationLayout windowsApp() {
+ return new ApplicationLayout(Map.of(
+ PathRole.LAUNCHERS_DIR, Path.of(""),
+ PathRole.APP, Path.of("app"),
+ PathRole.RUNTIME, Path.of("runtime"),
+ PathRole.DESKTOP, Path.of("")
+ ));
+ }
+
+ static ApplicationLayout platformApp() {
+ if (Platform.getPlatform() == Platform.WINDOWS) {
+ return windowsApp();
+ }
+
+ return unixApp();
+ }
+
+ static ApplicationLayout javaRuntime() {
+ return new ApplicationLayout(Map.of(PathRole.RUNTIME, Path.of("")));
+ }
+
+ private final PathGroup data;
+}
--- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java Mon Sep 16 19:24:32 2019 -0400
+++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java Tue Sep 24 13:41:16 2019 -0400
@@ -525,7 +525,7 @@
Log.error(msg1);
if (e.getCause() != null && e.getCause() != e) {
String msg2 = e.getCause().getMessage();
- if (!msg1.contains(msg2)) {
+ if (msg2 != null && !msg1.contains(msg2)) {
Log.error(msg2);
}
}
--- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java Mon Sep 16 19:24:32 2019 -0400
+++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java Tue Sep 24 13:41:16 2019 -0400
@@ -79,21 +79,7 @@
}
public static void copyRecursive(Path src, Path dest) throws IOException {
- Files.walkFileTree(src, new SimpleFileVisitor<Path>() {
- @Override
- public FileVisitResult preVisitDirectory(final Path dir,
- final BasicFileAttributes attrs) throws IOException {
- Files.createDirectories(dest.resolve(src.relativize(dir)));
- return FileVisitResult.CONTINUE;
- }
-
- @Override
- public FileVisitResult visitFile(final Path file,
- final BasicFileAttributes attrs) throws IOException {
- Files.copy(file, dest.resolve(src.relativize(file)));
- return FileVisitResult.CONTINUE;
- }
- });
+ copyRecursive(src, dest, List.of());
}
public static void copyRecursive(Path src, Path dest,
@@ -148,23 +134,6 @@
destFile.setReadable(true, false);
}
- public static long getFolderSize(File folder) {
- long foldersize = 0;
-
- File[] children = folder.listFiles();
- if (children != null) {
- for (File f : children) {
- if (f.isDirectory()) {
- foldersize += getFolderSize(f);
- } else {
- foldersize += f.length();
- }
- }
- }
-
- return foldersize;
- }
-
// run "launcher paramfile" in the directory where paramfile is kept
public static void run(String launcher, File paramFile)
throws IOException {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PathGroup.java Tue Sep 24 13:41:16 2019 -0400
@@ -0,0 +1,181 @@
+/*
+ * 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.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+
+/**
+ * Group of paths.
+ * Each path in the group is assigned a unique id.
+ */
+final class PathGroup {
+ PathGroup(Map<Object, Path> paths) {
+ entries = Collections.unmodifiableMap(paths);
+ }
+
+ Path getPath(Object id) {
+ return entries.get(id);
+ }
+
+ /**
+ * All configured entries.
+ */
+ Collection<Path> paths() {
+ return entries.values();
+ }
+
+ /**
+ * Root entries.
+ */
+ List<Path> roots() {
+ // Sort by the number of path components in ascending order.
+ List<Path> sorted = paths().stream().sorted(
+ (a, b) -> a.getNameCount() - b.getNameCount()).collect(
+ Collectors.toList());
+
+ return paths().stream().filter(
+ v -> v == sorted.stream().sequential().filter(
+ v2 -> v == v2 || v2.endsWith(v)).findFirst().get()).collect(
+ Collectors.toList());
+ }
+
+ long sizeInBytes() throws IOException {
+ long reply = 0;
+ for (Path dir : roots().stream().filter(f -> Files.isDirectory(f)).collect(
+ Collectors.toList())) {
+ reply += Files.walk(dir).filter(p -> Files.isRegularFile(p)).mapToLong(
+ f -> f.toFile().length()).sum();
+ }
+ return reply;
+ }
+
+ PathGroup resolveAt(Path root) {
+ return new PathGroup(entries.entrySet().stream().collect(
+ Collectors.toMap(e -> e.getKey(),
+ e -> root.resolve(e.getValue()))));
+ }
+
+ void copy(PathGroup dst) throws IOException {
+ copy(this, dst, false);
+ }
+
+ void move(PathGroup dst) throws IOException {
+ copy(this, dst, true);
+ }
+
+ static interface Facade<T> {
+ PathGroup pathGroup();
+
+ default Collection<Path> paths() {
+ return pathGroup().paths();
+ }
+
+ default List<Path> roots() {
+ return pathGroup().roots();
+ }
+
+ default long sizeInBytes() throws IOException {
+ return pathGroup().sizeInBytes();
+ }
+
+ T resolveAt(Path root);
+
+ default void copy(Facade<T> dst) throws IOException {
+ pathGroup().copy(dst.pathGroup());
+ }
+
+ default void move(Facade<T> dst) throws IOException {
+ pathGroup().move(dst.pathGroup());
+ }
+ }
+
+ private static void copy(PathGroup src, PathGroup dst, boolean move) throws
+ IOException {
+ copy(move, src.entries.keySet().stream().filter(
+ id -> dst.entries.containsKey(id)).map(id -> Map.entry(
+ src.entries.get(id), dst.entries.get(id))).collect(
+ Collectors.toCollection(ArrayList::new)));
+ }
+
+ private static void copy(boolean move, List<Map.Entry<Path, Path>> entries)
+ throws IOException {
+
+ // Reorder entries. Entries with source entries with the least amount of
+ // descending entries found between source entries should go first.
+ entries.sort((e1, e2) -> e1.getKey().getNameCount() - e2.getKey().getNameCount());
+
+ for (var entry : entries.stream().sequential().filter(e -> {
+ return e == entries.stream().sequential().filter(e2 -> isDuplicate(e2, e)).findFirst().get();
+ }).collect(Collectors.toList())) {
+ Path src = entry.getKey();
+ Path dst = entry.getValue();
+
+ if (src.equals(dst)) {
+ continue;
+ }
+
+ Files.createDirectories(dst.getParent());
+ if (move) {
+ Files.move(src, dst);
+ } else if (src.toFile().isDirectory()) {
+ IOUtils.copyRecursive(src, dst);
+ } else {
+ IOUtils.copyFile(src.toFile(), dst.toFile());
+ }
+ }
+ }
+
+ private static boolean isDuplicate(Map.Entry<Path, Path> a,
+ Map.Entry<Path, Path> b) {
+ if (a == b || a.equals(b)) {
+ return true;
+ }
+
+ if (b.getKey().getNameCount() < a.getKey().getNameCount()) {
+ return isDuplicate(b, a);
+ }
+
+ if (!a.getKey().endsWith(b.getKey())) {
+ return false;
+ }
+
+ Path relativeSrcPath = a.getKey().relativize(b.getKey());
+ Path relativeDstPath = a.getValue().relativize(b.getValue());
+
+ return relativeSrcPath.equals(relativeDstPath);
+ }
+
+ private final Map<Object, Path> entries;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PlatformPackage.java Tue Sep 24 13:41:16 2019 -0400
@@ -0,0 +1,53 @@
+/*
+ * 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.nio.file.Path;
+
+/**
+ *
+ * Platform package of an application.
+ */
+interface PlatformPackage {
+ /**
+ * Platform-specific package name.
+ */
+ String name();
+
+ /**
+ * Root directory where sources for packaging tool should be stored
+ */
+ Path sourceRoot();
+
+ /**
+ * Source application layout from which to build the package.
+ */
+ ApplicationLayout sourceApplicationLayout();
+
+ /**
+ * Application layout of the installed package.
+ */
+ ApplicationLayout installedApplicationLayout();
+}
--- a/test/jdk/tools/jpackage/apps/image/Hello.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/apps/image/Hello.java Tue Sep 24 13:41:16 2019 -0400
@@ -21,60 +21,39 @@
* questions.
*/
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.PrintWriter;
+import java.io.BufferedOutputStream;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.io.IOException;
public class Hello {
private static final String MSG = "jpackage test application";
private static final int EXPECTED_NUM_OF_PARAMS = 3; // Starts at 1
- public static void main(String[] args) {
- printToStdout(args);
- printToFile(args);
+ public static void main(String[] args) throws IOException {
+ printArgs(args, System.out);
+
+ try (PrintStream out = new PrintStream(new BufferedOutputStream(
+ new FileOutputStream("appOutput.txt")))) {
+ printArgs(args, out);
+ }
}
- private static void printToStdout(String[] args) {
- System.out.println(MSG);
+ private static void printArgs(String[] args, PrintStream out) {
+ out.println(MSG);
- System.out.println("args.length: " + args.length);
+ out.println("args.length: " + args.length);
for (String arg : args) {
- System.out.println(arg);
+ out.println(arg);
}
for (int index = 1; index <= EXPECTED_NUM_OF_PARAMS; index++) {
String value = System.getProperty("param" + index);
if (value != null) {
- System.out.println("-Dparam" + index + "=" + value);
+ out.println("-Dparam" + index + "=" + value);
}
}
}
-
- private static void printToFile(String[] args) {
- String outputFile = "appOutput.txt";
- File file = new File(outputFile);
-
- try (PrintWriter out
- = new PrintWriter(new BufferedWriter(new FileWriter(file)))) {
- out.println(MSG);
-
- out.println("args.length: " + args.length);
-
- for (String arg : args) {
- out.println(arg);
- }
-
- for (int index = 1; index <= EXPECTED_NUM_OF_PARAMS; index++) {
- String value = System.getProperty("param" + index);
- if (value != null) {
- out.println("-Dparam" + index + "=" + value);
- }
- }
- } catch (Exception ex) {
- System.err.println(ex.getMessage());
- }
- }
}
--- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java Tue Sep 24 13:41:16 2019 -0400
@@ -31,7 +31,10 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import java.util.spi.ToolProvider;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
public final class Executor extends CommandArguments<Executor> {
@@ -75,6 +78,11 @@
return this;
}
+ public Executor dumpOtput() {
+ saveOutputType = SaveOutputType.DUMP;
+ return this;
+ }
+
public class Result {
Result(int exitCode) {
@@ -82,7 +90,7 @@
}
public String getFirstLineOfOutput() {
- return output.get(0).trim();
+ return output.get(0);
}
public List<String> getOutput() {
@@ -126,6 +134,14 @@
throw new IllegalStateException("No command to execute");
}
+ public String executeAndGetFirstLineOfOutput() {
+ return saveFirstLineOfOutput().execute().assertExitCodeIsZero().getFirstLineOfOutput();
+ }
+
+ public List<String> executeAndGetOutput() {
+ return saveOutput().execute().assertExitCodeIsZero().getOutput();
+ }
+
private Result runExecutable() throws IOException, InterruptedException {
List<String> command = new ArrayList<>();
command.add(executable);
@@ -134,10 +150,16 @@
ProcessBuilder builder = new ProcessBuilder(command);
StringBuilder sb = new StringBuilder(getPrintableCommandLine());
if (saveOutputType != SaveOutputType.NONE) {
- outputFile = Test.createTempFile(".out");
builder.redirectErrorStream(true);
- builder.redirectOutput(outputFile.toFile());
- sb.append(String.format("; redirect output to [%s]", outputFile));
+
+ if (saveOutputType == SaveOutputType.DUMP) {
+ builder.inheritIO();
+ sb.append("; redirect output to stdout");
+ } else {
+ outputFile = Test.createTempFile(".out");
+ builder.redirectOutput(outputFile.toFile());
+ sb.append(String.format("; redirect output to [%s]", outputFile));
+ }
}
if (directory != null) {
builder.directory(directory.toFile());
@@ -150,8 +172,10 @@
Result reply = new Result(process.waitFor());
Test.trace("Done. Exit code: " + reply.exitCode);
if (saveOutputType == SaveOutputType.FIRST_LINE) {
+ // If the command produced no ouput, save null in 'result.output' list.
reply.output = Arrays.asList(
- Files.readAllLines(outputFile).stream().findFirst().get());
+ Files.readAllLines(outputFile).stream().findFirst().orElse(
+ null));
} else if (saveOutputType == SaveOutputType.FULL) {
reply.output = Collections.unmodifiableList(Files.readAllLines(
outputFile));
@@ -184,18 +208,28 @@
}
public String getPrintableCommandLine() {
- String argsStr = String.format("; args(%d)=%s", args.size(),
- Arrays.toString(args.toArray()));
-
+ final String exec;
+ String format = "[%s](%d)";
if (toolProvider == null && executable == null) {
- return "[null]; " + argsStr;
+ exec = "<null>";
+ } else if (toolProvider != null) {
+ format = "tool provider " + format;
+ exec = toolProvider.name();
+ } else {
+ exec = executable;
}
- if (toolProvider != null) {
- return String.format("tool provider=[%s]; ", toolProvider.name()) + argsStr;
- }
+ return String.format(format, printCommandLine(exec, args),
+ args.size() + 1);
+ }
- return String.format("[%s]; ", executable) + argsStr;
+ private static String printCommandLine(String executable, List<String> args) {
+ // Want command line printed in a way it can be easily copy/pasted
+ // to be executed manally
+ Pattern regex = Pattern.compile("\\s");
+ return Stream.concat(Stream.of(executable), args.stream()).map(
+ v -> (v.isEmpty() || regex.matcher(v).find()) ? "\"" + v + "\"" : v).collect(
+ Collectors.joining(" "));
}
private ToolProvider toolProvider;
@@ -204,6 +238,6 @@
private Path directory;
private static enum SaveOutputType {
- NONE, FULL, FIRST_LINE
+ NONE, FULL, FIRST_LINE, DUMP
};
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/FileAssociations.java Tue Sep 24 13:41:16 2019 -0400
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ *
+ * 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.test;
+
+import java.nio.file.Path;
+import java.util.Map;
+
+
+public class FileAssociations {
+ public FileAssociations(String faSuffixName) {
+ suffixName = faSuffixName;
+ setFilename("fa");
+ setDescription("jpackage test extention");
+ }
+
+ public void createFile() {
+ Test.createPropertiesFile(file,
+ Map.entry("extension", suffixName),
+ Map.entry("mime-type", getMime()),
+ Map.entry("description", description));
+ }
+
+ final public FileAssociations setFilename(String v) {
+ file = Test.workDir().resolve(v + ".properties");
+ return this;
+ }
+
+ final public FileAssociations setDescription(String v) {
+ description = v;
+ return this;
+ }
+
+ public Path getPropertiesFile() {
+ return file;
+ }
+
+ public String getSuffix() {
+ return "." + suffixName;
+ }
+
+ public String getMime() {
+ return "application/x-jpackage-" + suffixName;
+ }
+
+ private Path file;
+ final private String suffixName;
+ private String description;
+}
--- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java Tue Sep 24 13:41:16 2019 -0400
@@ -30,31 +30,36 @@
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
-
+import java.util.function.Consumer;
public class HelloApp {
+
+ private static final String MAIN_CLASS = "Hello";
+ private static final String JAR_FILENAME = "hello.jar";
+ private static final Consumer<JPackageCommand> CREATE_JAR_ACTION = (cmd) -> {
+ new JarBuilder()
+ .setOutputJar(cmd.inputDir().resolve(JAR_FILENAME).toFile())
+ .setMainClass(MAIN_CLASS)
+ .addSourceFile(Test.TEST_SRC_ROOT.resolve(
+ Path.of("apps", "image", MAIN_CLASS + ".java")))
+ .create();
+ };
+
static void addTo(JPackageCommand cmd) {
- cmd.addAction(new Runnable() {
- @Override
- public void run() {
- String mainClass = "Hello";
- Path jar = cmd.inputDir().resolve("hello.jar");
- new JarBuilder()
- .setOutputJar(jar.toFile())
- .setMainClass(mainClass)
- .addSourceFile(Test.TEST_SRC_ROOT.resolve(
- Path.of("apps", "image", mainClass + ".java")))
- .create();
- cmd.addArguments("--main-jar", jar.getFileName().toString());
- cmd.addArguments("--main-class", mainClass);
- }
- });
+ cmd.addAction(CREATE_JAR_ACTION);
+ cmd.addArguments("--main-jar", JAR_FILENAME);
+ cmd.addArguments("--main-class", MAIN_CLASS);
if (PackageType.WINDOWS.contains(cmd.packageType())) {
cmd.addArguments("--win-console");
}
}
- public static void verifyOutputFile(Path outputFile, String ... args) {
+ static void verifyOutputFile(Path outputFile, String... args) {
+ if (!outputFile.isAbsolute()) {
+ verifyOutputFile(outputFile.toAbsolutePath().normalize(), args);
+ return;
+ }
+
Test.assertFileExists(outputFile, true);
List<String> output = null;
@@ -87,9 +92,35 @@
counter.incrementAndGet(), outputFile)));
}
+ public static void executeLauncherAndVerifyOutput(JPackageCommand cmd) {
+ final Path launcherPath;
+ if (cmd.packageType() == PackageType.IMAGE) {
+ launcherPath = cmd.appImage().resolve(cmd.launcherPathInAppImage());
+ if (cmd.isFakeRuntimeInAppImage(String.format(
+ "Not running [%s] launcher from application image",
+ launcherPath))) {
+ return;
+ }
+ } else {
+ launcherPath = cmd.launcherInstallationPath();
+ if (cmd.isFakeRuntimeInstalled(String.format(
+ "Not running [%s] launcher", launcherPath))) {
+ return;
+ }
+ }
+
+ executeAndVerifyOutput(launcherPath, cmd.getAllArgumentValues(
+ "--arguments"));
+ }
+
public static void executeAndVerifyOutput(Path helloAppLauncher,
String... defaultLauncherArgs) {
File outputFile = Test.workDir().resolve(OUTPUT_FILENAME).toFile();
+ try {
+ Files.deleteIfExists(outputFile.toPath());
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
new Executor()
.setDirectory(outputFile.getParentFile().toPath())
.setExecutable(helloAppLauncher.toString())
@@ -99,5 +130,5 @@
verifyOutputFile(outputFile.toPath(), defaultLauncherArgs);
}
- public final static String OUTPUT_FILENAME = "appOutput.txt";
+ final static String OUTPUT_FILENAME = "appOutput.txt";
}
--- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java Tue Sep 24 13:41:16 2019 -0400
@@ -22,7 +22,11 @@
*/
package jdk.jpackage.test;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
import java.nio.file.Path;
+import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -30,9 +34,9 @@
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
+import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
-import java.util.stream.Stream;
/**
* jpackage command line with prerequisite actions. Prerequisite actions can be
@@ -45,14 +49,14 @@
actions = new ArrayList<>();
}
- static JPackageCommand createImmutable(JPackageCommand v) {
+ JPackageCommand createImmutableCopy() {
JPackageCommand reply = new JPackageCommand();
reply.immutable = true;
- reply.args.addAll(v.args);
+ reply.args.addAll(args);
return reply;
}
- public void setArgumentValue(String argName, String newValue) {
+ public JPackageCommand setArgumentValue(String argName, String newValue) {
verifyMutable();
String prevArg = null;
@@ -67,7 +71,7 @@
it.previous();
it.remove();
}
- return;
+ return this;
}
prevArg = value;
}
@@ -75,6 +79,16 @@
if (newValue != null) {
addArguments(argName, newValue);
}
+
+ return this;
+ }
+
+ public JPackageCommand setArgumentValue(String argName, Path newValue) {
+ return setArgumentValue(argName, newValue.toString());
+ }
+
+ public JPackageCommand removeArgument(String argName) {
+ return setArgumentValue(argName, (String)null);
}
public boolean hasArgument(String argName) {
@@ -130,6 +144,10 @@
return values.toArray(String[]::new);
}
+ public JPackageCommand addArguments(String name, Path value) {
+ return addArguments(name, value.toString());
+ }
+
public PackageType packageType() {
return getArgumentValue("--package-type",
() -> PackageType.DEFAULT,
@@ -153,17 +171,54 @@
}
public boolean isRuntime() {
- return getArgumentValue("--runtime-image", () -> false, v -> true);
+ return hasArgument("--runtime-image")
+ && !hasArgument("--main-jar")
+ && !hasArgument("--module")
+ && !hasArgument("--app-image");
}
public JPackageCommand setDefaultInputOutput() {
- verifyMutable();
- addArguments("--input", Test.defaultInputDir().toString());
- addArguments("--dest", Test.defaultOutputDir().toString());
+ addArguments("--input", Test.defaultInputDir());
+ addArguments("--dest", Test.defaultOutputDir());
return this;
}
- JPackageCommand addAction(Runnable action) {
+ public JPackageCommand setFakeRuntime() {
+ verifyMutable();
+
+ try {
+ Path fakeRuntimeDir = Test.workDir().resolve("fake_runtime");
+ Files.createDirectories(fakeRuntimeDir);
+
+ if (Test.isWindows() || Test.isLinux()) {
+ // Needed to make WindowsAppBundler happy as it copies MSVC dlls
+ // from `bin` directory.
+ // Need to make the code in rpm spec happy as it assumes there is
+ // always something in application image.
+ fakeRuntimeDir.resolve("bin").toFile().mkdir();
+ }
+
+ Path bulk = fakeRuntimeDir.resolve(Path.of("bin", "bulk"));
+
+ // Mak sure fake runtime takes some disk space.
+ // Package bundles with 0KB size are unexpected and considered
+ // an error by PackageTest.
+ Files.createDirectories(bulk.getParent());
+ try (FileOutputStream out = new FileOutputStream(bulk.toFile())) {
+ byte[] bytes = new byte[4 * 1024];
+ new SecureRandom().nextBytes(bytes);
+ out.write(bytes);
+ }
+
+ addArguments("--runtime-image", fakeRuntimeDir);
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+
+ return this;
+ }
+
+ JPackageCommand addAction(Consumer<JPackageCommand> action) {
verifyMutable();
actions.add(action);
return this;
@@ -184,15 +239,7 @@
}
JPackageCommand setDefaultAppName() {
- StackTraceElement st[] = Thread.currentThread().getStackTrace();
- for (StackTraceElement ste : st) {
- if ("main".equals(ste.getMethodName())) {
- String name = ste.getClassName();
- name = Stream.of(name.split("[.$]")).reduce((f, l) -> l).get();
- addArguments("--name", name);
- break;
- }
- }
+ addArguments("--name", Test.enclosingMainMethodClass().getSimpleName());
return this;
}
@@ -227,6 +274,12 @@
}
if (PackageType.LINUX.contains(type)) {
+ if (isRuntime()) {
+ // Not fancy, but OK.
+ return Path.of(getArgumentValue("--install-dir", () -> "/opt"),
+ LinuxHelper.getPackageName(this));
+ }
+
// Launcher is in "bin" subfolder of the installation directory.
return launcherInstallationPath().getParent().getParent();
}
@@ -243,6 +296,21 @@
}
/**
+ * Returns path where application's Java runtime will be installed.
+ * If the command will package Java run-time only, still returns path to
+ * runtime subdirectory.
+ *
+ * E.g. on Linux for app named `Foo` the function will return
+ * `/opt/foo/runtime`
+ */
+ public Path appRuntimeInstallationDirectory() {
+ if (PackageType.IMAGE == packageType()) {
+ return null;
+ }
+ return appInstallationDirectory().resolve("runtime");
+ }
+
+ /**
* Returns path where application launcher will be installed.
* If the command will package Java run-time only, still returns path to
* application launcher.
@@ -317,17 +385,81 @@
throw new IllegalArgumentException("Unexpected package type");
}
+ /**
+ * Returns path to runtime directory relative to image directory.
+ *
+ * Function will always return "runtime".
+ *
+ * @throws IllegalArgumentException if command is configured for platform
+ * packaging
+ */
+ public Path appRuntimeDirectoryInAppImage() {
+ final PackageType type = packageType();
+ if (PackageType.IMAGE != type) {
+ throw new IllegalArgumentException("Unexpected package type");
+ }
+
+ return Path.of("runtime");
+ }
+
+ public boolean isFakeRuntimeInAppImage(String msg) {
+ return isFakeRuntime(appImage().resolve(
+ appRuntimeDirectoryInAppImage()), msg);
+ }
+
+ public boolean isFakeRuntimeInstalled(String msg) {
+ return isFakeRuntime(appRuntimeInstallationDirectory(), msg);
+ }
+
+ private static boolean isFakeRuntime(Path runtimeDir, String msg) {
+ final List<Path> criticalRuntimeFiles;
+ if (Test.isWindows()) {
+ criticalRuntimeFiles = List.of(Path.of("server\\jvm.dll"));
+ } else if (Test.isLinux()) {
+ criticalRuntimeFiles = List.of(Path.of("server/libjvm.so"));
+ } else if (Test.isOSX()) {
+ criticalRuntimeFiles = List.of(Path.of("server/libjvm.dylib"));
+ } else {
+ throw new IllegalArgumentException("Unknwon platform");
+ }
+
+ if (criticalRuntimeFiles.stream().filter(v -> v.toFile().exists())
+ .findFirst().orElse(null) == null) {
+ // Fake runtime
+ Test.trace(String.format(
+ "%s because application runtime directory [%s] is incomplete",
+ msg, runtimeDir));
+ return true;
+ }
+ return false;
+ }
+
public Executor.Result execute() {
verifyMutable();
if (actions != null) {
- actions.stream().forEach(r -> r.run());
+ actions.stream().forEach(r -> r.accept(this));
}
+
return new Executor()
.setExecutable(JavaTool.JPACKAGE)
- .addArguments(args)
+ .dumpOtput()
+ .addArguments(new JPackageCommand().addArguments(
+ args).adjustArgumentsBeforeExecution().args)
.execute();
}
+ private JPackageCommand adjustArgumentsBeforeExecution() {
+ if (!hasArgument("--runtime-image") && !hasArgument("--app-image") && DEFAULT_RUNTIME_IMAGE != null) {
+ addArguments("--runtime-image", DEFAULT_RUNTIME_IMAGE);
+ }
+
+ if (!hasArgument("--verbose") && Test.VERBOSE_JPACKAGE) {
+ addArgument("--verbose");
+ }
+
+ return this;
+ }
+
String getPrintableCommandLine() {
return new Executor()
.setExecutable(JavaTool.JPACKAGE)
@@ -350,7 +482,7 @@
return !immutable;
}
- private final List<Runnable> actions;
+ private final List<Consumer<JPackageCommand>> actions;
private boolean immutable;
private final static Map<String, PackageType> PACKAGE_TYPES
@@ -364,4 +496,20 @@
return reply;
}
}.get();
+
+ public final static Path DEFAULT_RUNTIME_IMAGE;
+
+ static {
+ // Set the property to the path of run-time image to speed up
+ // building app images and platform bundles by avoiding running jlink
+ // The value of the property will be automativcally appended to
+ // jpackage command line if the command line doesn't have
+ // `--runtime-image` parameter set.
+ String val = Test.getConfigProperty("runtime-image");
+ if (val != null) {
+ DEFAULT_RUNTIME_IMAGE = Path.of(val);
+ } else {
+ DEFAULT_RUNTIME_IMAGE = null;
+ }
+ }
}
--- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java Tue Sep 24 13:41:16 2019 -0400
@@ -22,9 +22,15 @@
*/
package jdk.jpackage.test;
+import java.io.IOException;
+import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.Arrays;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
import java.util.stream.Stream;
public class LinuxHelper {
@@ -68,7 +74,6 @@
final Path packageFile = cmd.outputBundle();
Executor exec = new Executor();
- exec.saveOutput();
switch (packageType) {
case LINUX_DEB:
exec.setExecutable("dpkg")
@@ -83,7 +88,7 @@
break;
}
- Stream<String> lines = exec.execute().assertExitCodeIsZero().getOutput().stream();
+ Stream<String> lines = exec.executeAndGetOutput().stream();
if (packageType == PackageType.LINUX_DEB) {
// Typical text lines produced by dpkg look like:
// drwxr-xr-x root/root 0 2019-08-30 05:30 ./opt/appcategorytest/runtime/lib/
@@ -109,26 +114,176 @@
}).get();
}
+ static long getInstalledPackageSizeKB(JPackageCommand cmd) {
+ cmd.verifyIsOfType(PackageType.LINUX);
+
+ final Path packageFile = cmd.outputBundle();
+ switch (cmd.packageType()) {
+ case LINUX_DEB:
+ return Long.parseLong(getDebBundleProperty(packageFile,
+ "Installed-Size"));
+
+ case LINUX_RPM:
+ return Long.parseLong(getRpmBundleProperty(packageFile, "Size")) >> 10;
+ }
+
+ return 0;
+ }
+
static String getDebBundleProperty(Path bundle, String fieldName) {
return new Executor()
- .saveFirstLineOfOutput()
.setExecutable("dpkg-deb")
.addArguments("-f", bundle.toString(), fieldName)
- .execute()
- .assertExitCodeIsZero().getFirstLineOfOutput();
+ .executeAndGetFirstLineOfOutput();
}
- static String geRpmBundleProperty(Path bundle, String fieldName) {
+ static String getRpmBundleProperty(Path bundle, String fieldName) {
return new Executor()
- .saveFirstLineOfOutput()
.setExecutable("rpm")
.addArguments(
"-qp",
"--queryformat",
String.format("%%{%s}", fieldName),
bundle.toString())
- .execute()
- .assertExitCodeIsZero().getFirstLineOfOutput();
+ .executeAndGetFirstLineOfOutput();
+ }
+
+ static void addDebBundleDesktopIntegrationVerifier(PackageTest test,
+ boolean integrated) {
+ Function<List<String>, String> verifier = (lines) -> {
+ // Lookup for xdg commands
+ return lines.stream().filter(line -> {
+ Set<String> words = Set.of(line.split("\\s+"));
+ return words.contains("xdg-desktop-menu") || words.contains(
+ "xdg-mime") || words.contains("xdg-icon-resource");
+ }).findFirst().orElse(null);
+ };
+
+ test.addBundleVerifier(cmd -> {
+ Test.withTempDirectory(tempDir -> {
+ try {
+ // Extract control Debian package files into temporary directory
+ new Executor()
+ .setExecutable("dpkg")
+ .addArguments(
+ "-e",
+ cmd.outputBundle().toString(),
+ tempDir.toString()
+ ).execute().assertExitCodeIsZero();
+
+ Path controlFile = Path.of("postinst");
+
+ // Lookup for xdg commands in postinstall script
+ String lineWithXsdCommand = verifier.apply(
+ Files.readAllLines(tempDir.resolve(controlFile)));
+ String assertMsg = String.format(
+ "Check if %s@%s control file uses xdg commands",
+ cmd.outputBundle(), controlFile);
+ if (integrated) {
+ Test.assertNotNull(lineWithXsdCommand, assertMsg);
+ } else {
+ Test.assertNull(lineWithXsdCommand, assertMsg);
+ }
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ });
+ });
+ }
+
+ static void initFileAssociationsTestFile(Path testFile) {
+ try {
+ // Write something in test file.
+ // On Ubuntu and Oracle Linux empty files are considered
+ // plain text. Seems like a system bug.
+ //
+ // $ >foo.jptest1
+ // $ xdg-mime query filetype foo.jptest1
+ // text/plain
+ // $ echo > foo.jptest1
+ // $ xdg-mime query filetype foo.jptest1
+ // application/x-jpackage-jptest1
+ //
+ Files.write(testFile, Arrays.asList(""));
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ private static Path getSystemDesktopFilesFolder() {
+ return Stream.of("/usr/share/applications",
+ "/usr/local/share/applications").map(Path::of).filter(dir -> {
+ return Files.exists(dir.resolve("defaults.list"));
+ }).findFirst().orElseThrow(() -> new RuntimeException(
+ "Failed to locate system .desktop files folder"));
+ }
+
+ static void addFileAssociationsVerifier(PackageTest test, FileAssociations fa) {
+ test.addInstallVerifier(cmd -> {
+ Test.withTempFile(fa.getSuffix(), testFile -> {
+ initFileAssociationsTestFile(testFile);
+
+ String mimeType = queryFileMimeType(testFile);
+
+ Test.assertEquals(fa.getMime(), mimeType, String.format(
+ "Check mime type of [%s] file", testFile));
+
+ String desktopFileName = queryMimeTypeDefaultHandler(mimeType);
+
+ Path desktopFile = getSystemDesktopFilesFolder().resolve(
+ desktopFileName);
+
+ Test.assertFileExists(desktopFile, true);
+
+ Test.trace(String.format("Reading [%s] file...", desktopFile));
+ String mimeHandler = null;
+ try {
+ mimeHandler = Files.readAllLines(desktopFile).stream().peek(
+ v -> Test.trace(v)).filter(
+ v -> v.startsWith("Exec=")).map(
+ v -> v.split("=", 2)[1]).findFirst().orElseThrow();
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ Test.trace(String.format("Done"));
+
+ Test.assertEquals(cmd.launcherInstallationPath().toString(),
+ mimeHandler, String.format(
+ "Check mime type handler is the main application launcher"));
+
+ });
+ });
+
+ test.addUninstallVerifier(cmd -> {
+ Test.withTempFile(fa.getSuffix(), testFile -> {
+ initFileAssociationsTestFile(testFile);
+
+ String mimeType = queryFileMimeType(testFile);
+
+ Test.assertNotEquals(fa.getMime(), mimeType, String.format(
+ "Check mime type of [%s] file", testFile));
+
+ String desktopFileName = queryMimeTypeDefaultHandler(fa.getMime());
+
+ Test.assertNull(desktopFileName, String.format(
+ "Check there is no default handler for [%s] mime type",
+ fa.getMime()));
+ });
+ });
+ }
+
+ private static String queryFileMimeType(Path file) {
+ return new Executor()
+ .setExecutable("xdg-mime")
+ .addArguments("query", "filetype", file.toString())
+ .executeAndGetFirstLineOfOutput();
+ }
+
+ private static String queryMimeTypeDefaultHandler(String mimeType) {
+ return new Executor()
+ .setExecutable("xdg-mime")
+ .addArguments("query", "default", mimeType)
+ .executeAndGetFirstLineOfOutput();
}
private static String getPackageArch(PackageType type) {
@@ -139,7 +294,6 @@
String arch = archs.get(type);
if (arch == null) {
Executor exec = new Executor();
- exec.saveFirstLineOfOutput();
switch (type) {
case LINUX_DEB:
exec.setExecutable("dpkg").addArgument(
@@ -151,7 +305,7 @@
"--eval=%{_target_cpu}");
break;
}
- arch = exec.execute().assertExitCodeIsZero().getFirstLineOfOutput();
+ arch = exec.executeAndGetFirstLineOfOutput();
archs.put(type, arch);
}
return arch;
--- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java Tue Sep 24 13:41:16 2019 -0400
@@ -22,19 +22,26 @@
*/
package jdk.jpackage.test;
+import java.awt.Desktop;
import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import static jdk.jpackage.test.PackageType.LINUX_DEB;
+import static jdk.jpackage.test.PackageType.LINUX_RPM;
/**
* Instance of PackageTest is for configuring and running a single jpackage
@@ -59,6 +66,7 @@
forTypes();
setJPackageExitCode(0);
handlers = new HashMap<>();
+ namedInitializers = new HashSet<>();
currentTypes.forEach(v -> handlers.put(v, new Handler(v)));
}
@@ -79,14 +87,25 @@
}
public PackageTest setJPackageExitCode(int v) {
- expectedJPackageExitCode = 0;
+ expectedJPackageExitCode = v;
+ return this;
+ }
+
+ private PackageTest addInitializer(Consumer<JPackageCommand> v, String id) {
+ if (id != null) {
+ if (namedInitializers.contains(id)) {
+ return this;
+ }
+
+ namedInitializers.add(id);
+ }
+ currentTypes.stream().forEach(type -> handlers.get(type).addInitializer(
+ v));
return this;
}
public PackageTest addInitializer(Consumer<JPackageCommand> v) {
- currentTypes.stream().forEach(type -> handlers.get(type).addInitializer(
- v));
- return this;
+ return addInitializer(v, null);
}
public PackageTest addBundleVerifier(
@@ -111,7 +130,7 @@
break;
case LINUX_RPM:
- propertyValue = LinuxHelper.geRpmBundleProperty(
+ propertyValue = LinuxHelper.getRpmBundleProperty(
cmd.outputBundle(), propertyName);
break;
@@ -131,6 +150,13 @@
});
}
+ public PackageTest addBundleDesktopIntegrationVerifier(boolean integrated) {
+ forTypes(LINUX_DEB, () -> {
+ LinuxHelper.addDebBundleDesktopIntegrationVerifier(this, integrated);
+ });
+ return this;
+ }
+
public PackageTest addInstallVerifier(Consumer<JPackageCommand> v) {
currentTypes.stream().forEach(
type -> handlers.get(type).addInstallVerifier(v));
@@ -143,11 +169,70 @@
return this;
}
+ public PackageTest addHelloAppFileAssociationsVerifier(FileAssociations fa,
+ String... faLauncherDefaultArgs) {
+
+ addInitializer(cmd -> HelloApp.addTo(cmd), "HelloApp");
+ addInstallVerifier(cmd -> {
+ if (cmd.isFakeRuntimeInstalled(
+ "Not running file associations test")) {
+ return;
+ }
+
+ Test.withTempFile(fa.getSuffix(), testFile -> {
+ if (PackageType.LINUX.contains(cmd.packageType())) {
+ LinuxHelper.initFileAssociationsTestFile(testFile);
+ }
+
+ try {
+ final Path appOutput = Path.of(HelloApp.OUTPUT_FILENAME);
+ Files.deleteIfExists(appOutput);
+
+ Test.trace(String.format("Use desktop to open [%s] file",
+ testFile));
+ Desktop.getDesktop().open(testFile.toFile());
+ Test.waitForFileCreated(appOutput, 7);
+
+ List<String> expectedArgs = new ArrayList<>(List.of(
+ faLauncherDefaultArgs));
+ expectedArgs.add(testFile.toString());
+
+ // Wait a little bit after file has been created to
+ // make sure there are no pending writes into it.
+ Thread.sleep(3000);
+ HelloApp.verifyOutputFile(appOutput, expectedArgs.toArray(
+ String[]::new));
+ } catch (IOException | InterruptedException ex) {
+ throw new RuntimeException(ex);
+ }
+ });
+ });
+
+ forTypes(PackageType.LINUX, () -> {
+ LinuxHelper.addFileAssociationsVerifier(this, fa);
+ });
+
+ return this;
+ }
+
+ private void forTypes(Collection<PackageType> types, Runnable action) {
+ Set<PackageType> oldTypes = Set.of(currentTypes.toArray(
+ PackageType[]::new));
+ try {
+ forTypes(types);
+ action.run();
+ } finally {
+ forTypes(oldTypes);
+ }
+ }
+
+ private void forTypes(PackageType type, Runnable action) {
+ forTypes(List.of(type), action);
+ }
+
public PackageTest configureHelloApp() {
- addInitializer(cmd -> HelloApp.addTo(cmd));
- addInstallVerifier(cmd -> HelloApp.executeAndVerifyOutput(
- cmd.launcherInstallationPath(), cmd.getAllArgumentValues(
- "--arguments")));
+ addInitializer(cmd -> HelloApp.addTo(cmd), "HelloApp");
+ addInstallVerifier(HelloApp::executeLauncherAndVerifyOutput);
return this;
}
@@ -230,23 +315,27 @@
result.assertExitCodeIs(expectedJPackageExitCode);
Test.assertFileExists(cmd.outputBundle(),
expectedJPackageExitCode == 0);
- verifyPackageBundle(JPackageCommand.createImmutable(cmd),
- result);
+ verifyPackageBundle(cmd.createImmutableCopy(), result);
break;
- case VERIFY_INSTALLED:
- verifyPackageInstalled(JPackageCommand.createImmutable(cmd));
+ case VERIFY_INSTALL:
+ verifyPackageInstalled(cmd.createImmutableCopy());
break;
- case VERIFY_UNINSTALLED:
- verifyPackageUninstalled(
- JPackageCommand.createImmutable(cmd));
+ case VERIFY_UNINSTALL:
+ verifyPackageUninstalled(cmd.createImmutableCopy());
break;
}
}
private void verifyPackageBundle(JPackageCommand cmd,
Executor.Result result) {
+ if (PackageType.LINUX.contains(cmd.packageType())) {
+ Test.assertNotEquals(0L, LinuxHelper.getInstalledPackageSizeKB(
+ cmd), String.format(
+ "Check installed size of [%s] package in KB is not zero",
+ LinuxHelper.getPackageName(cmd)));
+ }
bundleVerifiers.stream().forEach(v -> v.accept(cmd, result));
}
@@ -255,14 +344,14 @@
cmd.getPrintableCommandLine()));
if (cmd.isRuntime()) {
Test.assertDirectoryExists(
- cmd.appInstallationDirectory().resolve("runtime"), false);
+ cmd.appRuntimeInstallationDirectory(), false);
Test.assertDirectoryExists(
cmd.appInstallationDirectory().resolve("app"), false);
+ } else {
+ Test.assertExecutableFileExists(cmd.launcherInstallationPath(),
+ true);
}
- Test.assertExecutableFileExists(cmd.launcherInstallationPath(),
- !cmd.isRuntime());
-
if (PackageType.WINDOWS.contains(cmd.packageType())) {
new WindowsHelper.AppVerifier(cmd);
}
@@ -295,6 +384,7 @@
private Collection<PackageType> currentTypes;
private int expectedJPackageExitCode;
private Map<PackageType, Handler> handlers;
+ private Set<String> namedInitializers;
private Action action;
/**
@@ -308,40 +398,45 @@
/**
* Verify bundle installed.
*/
- VERIFY_INSTALLED,
+ VERIFY_INSTALL,
/**
* Verify bundle uninstalled.
*/
- VERIFY_UNINSTALLED
+ VERIFY_UNINSTALL;
+
+ @Override
+ public String toString() {
+ return name().toLowerCase().replace('_', '-');
+ }
};
private final static Action DEFAULT_ACTION;
private final static File bundleOutputDir;
static {
- final String JPACKAGE_TEST_OUTPUT = "jpackage.test.output";
-
- String val = System.getProperty(JPACKAGE_TEST_OUTPUT);
+ final String propertyName = "output";
+ String val = Test.getConfigProperty(propertyName);
if (val == null) {
bundleOutputDir = null;
} else {
bundleOutputDir = new File(val).getAbsoluteFile();
- Test.assertTrue(bundleOutputDir.isDirectory(), String.format(
- "Check value of %s property [%s] references a directory",
- JPACKAGE_TEST_OUTPUT, bundleOutputDir));
- Test.assertTrue(bundleOutputDir.canWrite(), String.format(
- "Check value of %s property [%s] references writable directory",
- JPACKAGE_TEST_OUTPUT, bundleOutputDir));
+ if (!bundleOutputDir.isDirectory()) {
+ throw new IllegalArgumentException(String.format(
+ "Invalid value of %s sytem property: [%s]. Should be existing directory",
+ Test.getConfigPropertyName(propertyName),
+ bundleOutputDir));
+ }
}
}
static {
- if (System.getProperty("jpackage.verify.install") != null) {
- DEFAULT_ACTION = Action.VERIFY_INSTALLED;
- } else if (System.getProperty("jpackage.verify.uninstall") != null) {
- DEFAULT_ACTION = Action.VERIFY_UNINSTALLED;
- } else {
- DEFAULT_ACTION = Action.CREATE;
- }
+ final String propertyName = "action";
+ String action = Optional.ofNullable(Test.getConfigProperty(propertyName)).orElse(
+ Action.CREATE.toString()).toLowerCase();
+ DEFAULT_ACTION = Stream.of(Action.values()).filter(
+ a -> a.toString().equals(action)).findFirst().orElseThrow(
+ () -> new IllegalArgumentException(String.format(
+ "Unrecognized value of %s property: [%s]",
+ Test.getConfigPropertyName(propertyName), action)));
}
}
--- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageType.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageType.java Tue Sep 24 13:41:16 2019 -0400
@@ -24,8 +24,6 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
@@ -61,7 +59,7 @@
Test.trace(String.format("Bundler %s supported", getName()));
}
}
-
+
PackageType(String bundleSuffix, String bundlerClass) {
this(bundleSuffix.substring(1), bundleSuffix, bundlerClass);
}
@@ -96,15 +94,13 @@
private static boolean isBundlerSupported(String bundlerClass) {
try {
Class clazz = Class.forName(bundlerClass);
- Method isSupported = clazz.getDeclaredMethod("isSupported");
- return ((Boolean) isSupported.invoke(clazz));
+ Method supported = clazz.getMethod("supported", boolean.class);
+ return ((Boolean) supported.invoke(clazz.newInstance(), true));
} catch (ClassNotFoundException ex) {
return false;
- } catch (IllegalAccessException | InvocationTargetException ex) {
+ } catch (InstantiationException | NoSuchMethodException
+ | IllegalAccessException | InvocationTargetException ex) {
throw new RuntimeException(ex);
- } catch (NoSuchMethodException ex) {
- // Not all bundler classes has isSupported() method.
- return true;
}
}
@@ -118,28 +114,28 @@
public final static Set<PackageType> NATIVE = Stream.concat(
Stream.concat(LINUX.stream(), WINDOWS.stream()),
MAC.stream()).collect(Collectors.toUnmodifiableSet());
-
+
public final static PackageType DEFAULT = ((Supplier<PackageType>) () -> {
if (Test.isLinux()) {
return LINUX.stream().filter(v -> v.isSupported()).findFirst().orElseThrow();
}
-
+
if (Test.isWindows()) {
return WIN_EXE;
}
-
+
if (Test.isOSX()) {
return MAC_DMG;
}
-
+
throw new IllegalStateException("Unknwon platform");
}).get();
-
+
private final static class Inner {
-
+
private final static Set<String> DISABLED_PACKAGERS = Stream.of(
Optional.ofNullable(
- System.getProperty("jpackage.test.disabledPackagers")).orElse(
+ Test.getConfigProperty("disabledPackagers")).orElse(
"").split(",")).collect(Collectors.toUnmodifiableSet());
}
}
--- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Test.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Test.java Tue Sep 24 13:41:16 2019 -0400
@@ -22,8 +22,11 @@
*/
package jdk.jpackage.test;
-import java.io.File;
+import java.io.BufferedOutputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.PrintStream;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -33,11 +36,17 @@
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import jdk.jpackage.internal.IOUtils;
-public class Test {
+final public class Test {
public static final Path TEST_SRC_ROOT = new Supplier<Path>() {
@Override
@@ -55,6 +64,62 @@
}
}.get();
+ private static class Instance implements AutoCloseable {
+ Instance(String args[]) {
+ assertCount = 0;
+
+ name = enclosingMainMethodClass().getSimpleName();
+ extraLogStream = openLogStream();
+
+ currentTest = this;
+
+ log(String.format("[ RUN ] %s", name));
+ }
+
+ @Override
+ public void close() {
+ log(String.format("%s %s; checks=%d",
+ success ? "[ OK ]" : "[ FAILED ]", name, assertCount));
+
+ if (extraLogStream != null) {
+ extraLogStream.close();
+ }
+ }
+
+ void notifyAssert() {
+ assertCount++;
+ }
+
+ void notifySuccess() {
+ success = true;
+ }
+
+ private int assertCount;
+ private boolean success;
+ private final String name;
+ private final PrintStream extraLogStream;
+ }
+
+ public static void run(String args[], TestBody action) {
+ if (currentTest != null) {
+ throw new IllegalStateException(
+ "Unexpeced nested or concurrent Test.run() call");
+ }
+
+ try (Instance instance = new Instance(args)) {
+ action.run();
+ instance.notifySuccess();
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ } finally {
+ currentTest = null;
+ }
+ }
+
+ public static interface TestBody {
+ public void run() throws Exception;
+ }
+
public static Path workDir() {
return Path.of(".");
}
@@ -67,6 +132,20 @@
return workDir().resolve("output");
}
+ static Class enclosingMainMethodClass() {
+ StackTraceElement st[] = Thread.currentThread().getStackTrace();
+ for (StackTraceElement ste : st) {
+ if ("main".equals(ste.getMethodName())) {
+ try {
+ return Class.forName(ste.getClassName());
+ } catch (ClassNotFoundException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ }
+ return null;
+ }
+
static boolean isWindows() {
return (OS.contains("win"));
}
@@ -80,7 +159,39 @@
}
static private void log(String v) {
- System.err.println(v);
+ System.out.println(v);
+ if (currentTest != null && currentTest.extraLogStream != null) {
+ currentTest.extraLogStream.println(v);
+ }
+ }
+
+ public static Class getTestClass () {
+ return enclosingMainMethodClass();
+ }
+
+ public static void createPropertiesFile(Path propsFilename,
+ Collection<Map.Entry<String, String>> props) {
+ trace(String.format("Create [%s] properties file...",
+ propsFilename.toAbsolutePath().normalize()));
+ try {
+ Files.write(propsFilename, props.stream().peek(e -> trace(
+ String.format("%s=%s", e.getKey(), e.getValue()))).map(
+ e -> String.format("%s=%s", e.getKey(), e.getValue())).collect(
+ Collectors.toList()));
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ trace("Done");
+ }
+
+ public static void createPropertiesFile(Path propsFilename,
+ Map.Entry<String, String>... props) {
+ createPropertiesFile(propsFilename, List.of(props));
+ }
+
+ public static void createPropertiesFile(Path propsFilename,
+ Map<String, String> props) {
+ createPropertiesFile(propsFilename, props.entrySet());
}
public static void trace(String v) {
@@ -100,12 +211,54 @@
throw new AssertionError(v);
}
+ private static final String TEMP_FILE_PREFIX = null;
+
public static Path createTempDirectory() throws IOException {
- return Files.createTempDirectory("jpackage_");
+ return Files.createTempDirectory(workDir(), TEMP_FILE_PREFIX);
}
public static Path createTempFile(String suffix) throws IOException {
- return File.createTempFile("jpackage_", suffix).toPath();
+ return Files.createTempFile(workDir(), TEMP_FILE_PREFIX, suffix);
+ }
+
+ public static void withTempFile(String suffix, Consumer<Path> action) {
+ Path tempFile = null;
+ boolean keepIt = true;
+ try {
+ tempFile = createTempFile(suffix);
+ action.accept(tempFile);
+ keepIt = false;
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ } finally {
+ if (tempFile != null && !keepIt) {
+ try {
+ Files.deleteIfExists(tempFile);
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ }
+ }
+
+ public static void withTempDirectory(Consumer<Path> action) {
+ Path tempDir = null;
+ boolean keepIt = true;
+ try {
+ tempDir = createTempDirectory();
+ action.accept(tempDir);
+ keepIt = false;
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ } finally {
+ try {
+ if (tempDir != null && tempDir.toFile().isDirectory() && !keepIt) {
+ IOUtils.deleteRecursive(tempDir.toFile());
+ }
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
}
public static void waitForFileCreated(Path fileToWaitFor,
@@ -166,7 +319,8 @@
return msg;
}
- public static void assertEquals(int expected, int actual, String msg) {
+ public static void assertEquals(long expected, long actual, String msg) {
+ currentTest.notifyAssert();
if (expected != actual) {
error(concatMessages(String.format(
"Expected [%d]. Actual [%d]", expected, actual),
@@ -176,21 +330,8 @@
traceAssert(String.format("assertEquals(%d): %s", expected, msg));
}
- public static void assertEquals(String expected, String actual, String msg) {
- if (expected == null && actual == null) {
- return;
- }
-
- if (actual == null || !expected.equals(actual)) {
- error(concatMessages(String.format(
- "Expected [%s]. Actual [%s]", expected, actual),
- msg));
- }
-
- traceAssert(String.format("assertEquals(%s): %s", expected, msg));
- }
-
- public static void assertNotEquals(int expected, int actual, String msg) {
+ public static void assertNotEquals(long expected, long actual, String msg) {
+ currentTest.notifyAssert();
if (expected == actual) {
error(concatMessages(String.format("Unexpected [%d] value", actual),
msg));
@@ -200,7 +341,33 @@
actual, msg));
}
+ public static void assertEquals(String expected, String actual, String msg) {
+ currentTest.notifyAssert();
+ if ((actual != null && !actual.equals(expected))
+ || (expected != null && !expected.equals(actual))) {
+ error(concatMessages(String.format(
+ "Expected [%s]. Actual [%s]", expected, actual),
+ msg));
+ }
+
+ traceAssert(String.format("assertEquals(%s): %s", expected, msg));
+ }
+
+ public static void assertNotEquals(String expected, String actual, String msg) {
+ currentTest.notifyAssert();
+ if ((actual != null && !actual.equals(expected))
+ || (expected != null && !expected.equals(actual))) {
+
+ traceAssert(String.format("assertNotEquals(%s, %s): %s", expected,
+ actual, msg));
+ return;
+ }
+
+ error(concatMessages(String.format("Unexpected [%s] value", actual), msg));
+ }
+
public static void assertNull(Object value, String msg) {
+ currentTest.notifyAssert();
if (value != null) {
error(concatMessages(String.format("Unexpected not null value [%s]",
value), msg));
@@ -210,6 +377,7 @@
}
public static void assertNotNull(Object value, String msg) {
+ currentTest.notifyAssert();
if (value == null) {
error(concatMessages("Unexpected null value", msg));
}
@@ -218,6 +386,7 @@
}
public static void assertTrue(boolean actual, String msg) {
+ currentTest.notifyAssert();
if (!actual) {
error(concatMessages("Unexpected FALSE", msg));
}
@@ -226,6 +395,7 @@
}
public static void assertFalse(boolean actual, String msg) {
+ currentTest.notifyAssert();
if (actual) {
error(concatMessages("Unexpected TRUE", msg));
}
@@ -268,24 +438,67 @@
}
public static void assertUnexpected(String msg) {
+ currentTest.notifyAssert();
error(concatMessages("Unexpected", msg));
}
+ private static PrintStream openLogStream() {
+ if (LOG_FILE == null) {
+ return null;
+ }
+
+ try {
+ return new PrintStream(new FileOutputStream(LOG_FILE.toFile(), true));
+ } catch (FileNotFoundException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ private static Instance currentTest;
+
private static final boolean TRACE;
private static final boolean TRACE_ASSERTS;
+ static final boolean VERBOSE_JPACKAGE;
+
+ static String getConfigProperty(String propertyName) {
+ return System.getProperty(getConfigPropertyName(propertyName));
+ }
+
+ static String getConfigPropertyName(String propertyName) {
+ return "jpackage.test." + propertyName;
+ }
+
+ static final Path LOG_FILE = new Supplier<Path>() {
+ @Override
+ public Path get() {
+ String val = getConfigProperty("logfile");
+ if (val == null) {
+ return null;
+ }
+ return Path.of(val);
+ }
+ }.get();
+
static {
- String val = System.getProperty("jpackage.test.suppress-logging");
+ String val = getConfigProperty("suppress-logging");
if (val == null) {
TRACE = true;
TRACE_ASSERTS = true;
+ VERBOSE_JPACKAGE = true;
+ } else if ("all".equals(val.toLowerCase())) {
+ TRACE = false;
+ TRACE_ASSERTS = false;
+ VERBOSE_JPACKAGE = false;
} else {
Set<String> logOptions = Set.of(val.toLowerCase().split(","));
TRACE = !(logOptions.contains("trace") || logOptions.contains("t"));
TRACE_ASSERTS = !(logOptions.contains("assert") || logOptions.contains(
"a"));
+ VERBOSE_JPACKAGE = !(logOptions.contains("jpackage") || logOptions.contains(
+ "jp"));
}
}
private static final String OS = System.getProperty("os.name").toLowerCase();
-}
+}
\ No newline at end of file
--- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java Tue Sep 24 13:41:16 2019 -0400
@@ -97,7 +97,7 @@
private void verifyStartMenuShortcut() {
boolean appInstalled = cmd.launcherInstallationPath().toFile().exists();
- if (cmd.hasArgument("--win-menu") || !cmd.hasArgument("--win-shortcut")) {
+ if (cmd.hasArgument("--win-menu")) {
if (isUserLocalInstall(cmd)) {
verifyUserLocalStartMenuShortcut(appInstalled);
verifySystemStartMenuShortcut(false);
@@ -129,12 +129,11 @@
}
private void verifyFileAssociationsRegistry() {
- Path faFile = cmd.getArgumentValue("--file-associations",
- () -> (Path) null, Path::of);
- if (faFile == null) {
- return;
- }
+ Stream.of(cmd.getAllArgumentValues("--file-associations")).map(
+ Path::of).forEach(this::verifyFileAssociationsRegistry);
+ }
+ private void verifyFileAssociationsRegistry(Path faFile) {
boolean appInstalled = cmd.launcherInstallationPath().toFile().exists();
try {
Test.trace(String.format(
--- a/test/jdk/tools/jpackage/linux/AppCategoryTest.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/linux/AppCategoryTest.java Tue Sep 24 13:41:16 2019 -0400
@@ -21,6 +21,7 @@
* questions.
*/
+import jdk.jpackage.test.Test;
import jdk.jpackage.test.PackageTest;
import jdk.jpackage.test.PackageType;
@@ -49,19 +50,21 @@
*/
public class AppCategoryTest {
- public static void main(String[] args) throws Exception {
+ public static void main(String[] args) {
final String CATEGORY = "Foo";
- new PackageTest()
- .forTypes(PackageType.LINUX)
- .configureHelloApp()
- .addInitializer(cmd -> {
- cmd.addArguments("--linux-app-category", CATEGORY);
- })
- .forTypes(PackageType.LINUX_DEB)
- .addBundlePropertyVerifier("Section", CATEGORY)
- .forTypes(PackageType.LINUX_RPM)
- .addBundlePropertyVerifier("Group", CATEGORY)
- .run();
+ Test.run(args, () -> {
+ new PackageTest()
+ .forTypes(PackageType.LINUX)
+ .configureHelloApp()
+ .addInitializer(cmd -> {
+ cmd.addArguments("--linux-app-category", CATEGORY);
+ })
+ .forTypes(PackageType.LINUX_DEB)
+ .addBundlePropertyVerifier("Section", CATEGORY)
+ .forTypes(PackageType.LINUX_RPM)
+ .addBundlePropertyVerifier("Group", CATEGORY)
+ .run();
+ });
}
}
--- a/test/jdk/tools/jpackage/linux/BundleNameTest.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/linux/BundleNameTest.java Tue Sep 24 13:41:16 2019 -0400
@@ -21,6 +21,7 @@
* questions.
*/
+import jdk.jpackage.test.Test;
import jdk.jpackage.test.PackageTest;
import jdk.jpackage.test.PackageType;
@@ -49,19 +50,21 @@
*/
public class BundleNameTest {
- public static void main(String[] args) throws Exception {
+ public static void main(String[] args) {
final String PACKAGE_NAME = "quickbrownfox2";
- new PackageTest()
- .forTypes(PackageType.LINUX)
- .configureHelloApp()
- .addInitializer(cmd -> {
- cmd.addArguments("--linux-package-name", PACKAGE_NAME);
- })
- .forTypes(PackageType.LINUX_DEB)
- .addBundlePropertyVerifier("Package", PACKAGE_NAME)
- .forTypes(PackageType.LINUX_RPM)
- .addBundlePropertyVerifier("Name", PACKAGE_NAME)
- .run();
+ Test.run(args, () -> {
+ new PackageTest()
+ .forTypes(PackageType.LINUX)
+ .configureHelloApp()
+ .addInitializer(cmd -> {
+ cmd.addArguments("--linux-package-name", PACKAGE_NAME);
+ })
+ .forTypes(PackageType.LINUX_DEB)
+ .addBundlePropertyVerifier("Package", PACKAGE_NAME)
+ .forTypes(PackageType.LINUX_RPM)
+ .addBundlePropertyVerifier("Name", PACKAGE_NAME)
+ .run();
+ });
}
}
--- a/test/jdk/tools/jpackage/linux/LicenseTypeTest.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/linux/LicenseTypeTest.java Tue Sep 24 13:41:16 2019 -0400
@@ -21,6 +21,7 @@
* questions.
*/
+import jdk.jpackage.test.Test;
import jdk.jpackage.test.PackageTest;
import jdk.jpackage.test.PackageType;
@@ -44,14 +45,16 @@
*/
public class LicenseTypeTest {
- public static void main(String[] args) throws Exception {
+ public static void main(String[] args) {
final String LICENSE_TYPE = "JP_LICENSE_TYPE";
- new PackageTest().forTypes(PackageType.LINUX_RPM).configureHelloApp()
- .addInitializer(cmd -> {
- cmd.addArguments("--linux-rpm-license-type", LICENSE_TYPE);
- })
- .addBundlePropertyVerifier("License", LICENSE_TYPE)
- .run();
+ Test.run(args, () -> {
+ new PackageTest().forTypes(PackageType.LINUX_RPM).configureHelloApp()
+ .addInitializer(cmd -> {
+ cmd.addArguments("--linux-rpm-license-type", LICENSE_TYPE);
+ })
+ .addBundlePropertyVerifier("License", LICENSE_TYPE)
+ .run();
+ });
}
}
--- a/test/jdk/tools/jpackage/linux/MaintainerTest.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/linux/MaintainerTest.java Tue Sep 24 13:41:16 2019 -0400
@@ -46,19 +46,21 @@
*/
public class MaintainerTest {
- public static void main(String[] args) throws Exception {
+ public static void main(String[] args) {
final String MAINTAINER = "jpackage-test@java.com";
- new PackageTest().forTypes(PackageType.LINUX_DEB).configureHelloApp()
- .addInitializer(cmd -> {
- cmd.addArguments("--linux-deb-maintainer", MAINTAINER);
- })
- .addBundlePropertyVerifier("Maintainer", (propName, propValue) -> {
- String lookupValue = "<" + MAINTAINER + ">";
- Test.assertTrue(propValue.endsWith(lookupValue),
- String.format("Check value of %s property [%s] ends with %s",
- propName, propValue, lookupValue));
- })
- .run();
+ Test.run(args, () -> {
+ new PackageTest().forTypes(PackageType.LINUX_DEB).configureHelloApp()
+ .addInitializer(cmd -> {
+ cmd.addArguments("--linux-deb-maintainer", MAINTAINER);
+ })
+ .addBundlePropertyVerifier("Maintainer", (propName, propValue) -> {
+ String lookupValue = "<" + MAINTAINER + ">";
+ Test.assertTrue(propValue.endsWith(lookupValue),
+ String.format("Check value of %s property [%s] ends with %s",
+ propName, propValue, lookupValue));
+ })
+ .run();
+ });
}
}
--- a/test/jdk/tools/jpackage/linux/PackageDepsTest.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/linux/PackageDepsTest.java Tue Sep 24 13:41:16 2019 -0400
@@ -21,6 +21,7 @@
* questions.
*/
+import jdk.jpackage.test.Test;
import jdk.jpackage.test.PackageTest;
import jdk.jpackage.test.PackageType;
@@ -56,26 +57,28 @@
// produced by jtreg tests install/uninstall packages in the right order.
static class APackageDepsTestPrereq {
- public static void main(String[] args) throws Exception {
+ public static void main(String[] args) {
new PackageTest().forTypes(PackageType.LINUX).configureHelloApp().run();
}
}
- public static void main(String[] args) throws Exception {
+ public static void main(String[] args) {
final String PREREQ_PACKAGE_NAME = "apackagedepstestprereq";
- APackageDepsTestPrereq.main(args);
+ Test.run(args, () -> {
+ APackageDepsTestPrereq.main(args);
- new PackageTest()
- .forTypes(PackageType.LINUX)
- .configureHelloApp()
- .addInitializer(cmd -> {
- cmd.addArguments("--linux-package-deps", PREREQ_PACKAGE_NAME);
- })
- .forTypes(PackageType.LINUX_DEB)
- .addBundlePropertyVerifier("Depends", PREREQ_PACKAGE_NAME)
- .forTypes(PackageType.LINUX_RPM)
- .addBundlePropertyVerifier("Requires", PREREQ_PACKAGE_NAME)
- .run();
+ new PackageTest()
+ .forTypes(PackageType.LINUX)
+ .configureHelloApp()
+ .addInitializer(cmd -> {
+ cmd.addArguments("--linux-package-deps", PREREQ_PACKAGE_NAME);
+ })
+ .forTypes(PackageType.LINUX_DEB)
+ .addBundlePropertyVerifier("Depends", PREREQ_PACKAGE_NAME)
+ .forTypes(PackageType.LINUX_RPM)
+ .addBundlePropertyVerifier("Requires", PREREQ_PACKAGE_NAME)
+ .run();
+ });
}
}
--- a/test/jdk/tools/jpackage/linux/ReleaseTest.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/linux/ReleaseTest.java Tue Sep 24 13:41:16 2019 -0400
@@ -21,8 +21,8 @@
* questions.
*/
+import jdk.jpackage.test.PackageType;
import jdk.jpackage.test.PackageTest;
-import jdk.jpackage.test.PackageType;
import jdk.jpackage.test.Test;
@@ -49,23 +49,25 @@
*/
public class ReleaseTest {
- public static void main(String[] args) throws Exception {
+ public static void main(String[] args) {
final String RELEASE = "Rc3";
- new PackageTest()
- .forTypes(PackageType.LINUX)
- .configureHelloApp()
- .addInitializer(cmd -> {
- cmd.addArguments("--linux-app-release", RELEASE);
- })
- .forTypes(PackageType.LINUX_RPM)
- .addBundlePropertyVerifier("Release", RELEASE)
- .forTypes(PackageType.LINUX_DEB)
- .addBundlePropertyVerifier("Version", (propName, propValue) -> {
- Test.assertTrue(propValue.endsWith("-" + RELEASE),
- String.format("Check value of %s property [%s] ends with %s",
- propName, propValue, RELEASE));
- })
- .run();
+ Test.run(args, () -> {
+ new PackageTest()
+ .forTypes(PackageType.LINUX)
+ .configureHelloApp()
+ .addInitializer(cmd -> {
+ cmd.addArguments("--linux-app-release", RELEASE);
+ })
+ .forTypes(PackageType.LINUX_RPM)
+ .addBundlePropertyVerifier("Release", RELEASE)
+ .forTypes(PackageType.LINUX_DEB)
+ .addBundlePropertyVerifier("Version", (propName, propValue) -> {
+ Test.assertTrue(propValue.endsWith("-" + RELEASE),
+ String.format("Check value of %s property [%s] ends with %s",
+ propName, propValue, RELEASE));
+ })
+ .run();
+ });
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/tools/jpackage/linux/ShortcutHintTest.java Tue Sep 24 13:41:16 2019 -0400
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+import java.util.Map;
+import java.nio.file.Path;
+import jdk.jpackage.test.FileAssociations;
+import jdk.jpackage.test.PackageType;
+import jdk.jpackage.test.PackageTest;
+import jdk.jpackage.test.Test;
+
+/**
+ * Test --linux-shortcut parameter. Output of the test should be
+ * shortcuthinttest_1.0-1_amd64.deb or shortcuthinttest-1.0-1.amd64.rpm package
+ * bundle. The output package should provide the same functionality as the
+ * default package and also create a desktop shortcut.
+ *
+ * Finding a shortcut of the application launcher through GUI depends on desktop
+ * environment.
+ *
+ * deb:
+ * Search online for `Ways To Open A Ubuntu Application` for instructions.
+ *
+ * rpm:
+ *
+ */
+
+/*
+ * @test
+ * @summary jpackage with --linux-shortcut
+ * @library ../helpers
+ * @requires (os.family == "linux")
+ * @modules jdk.jpackage/jdk.jpackage.internal
+ * @run main/othervm/timeout=360 -Xmx512m ShortcutHintTest
+ * @run main/othervm/timeout=360 -Xmx512m ShortcutHintTest testCustomIcon
+ * @run main/othervm/timeout=360 -Xmx512m ShortcutHintTest testFileAssociations
+ * @run main/othervm/timeout=360 -Xmx512m ShortcutHintTest testAdditionaltLaunchers
+ */
+public class ShortcutHintTest {
+
+ public static void main(String[] args) {
+ Test.run(args, () -> {
+ if (args.length != 0) {
+ Test.getTestClass().getDeclaredMethod(args[0]).invoke(null);
+ return;
+ }
+
+ createTest(null).addInitializer(cmd -> {
+ cmd.addArgument("--linux-shortcut");
+ }).run();
+ });
+ }
+
+ private static PackageTest createTest(String name) {
+ PackageTest reply = new PackageTest()
+ .forTypes(PackageType.LINUX)
+ .configureHelloApp()
+ .addBundleDesktopIntegrationVerifier(true);
+ if (name != null) {
+ reply.addInitializer(cmd -> cmd.setArgumentValue("--name",
+ String.format("%s8%s", Test.getTestClass().getSimpleName(),
+ name)));
+ }
+ return reply;
+ }
+
+ /**
+ * Adding `--icon` to jpackage command line should create desktop shortcut
+ * even though `--linux-shortcut` is omitted.
+ */
+ static void testCustomIcon() {
+ createTest(new Object() {
+ }.getClass().getEnclosingMethod().getName()).addInitializer(cmd -> {
+ cmd.setFakeRuntime();
+ cmd.addArguments("--icon", Test.TEST_SRC_ROOT.resolve(
+ "apps/dukeplug.png"));
+ }).run();
+ }
+
+ /**
+ * Adding `--file-associations` to jpackage command line should create
+ * desktop shortcut even though `--linux-shortcut` is omitted.
+ */
+ static void testFileAssociations() {
+ createTest(new Object() {
+ }.getClass().getEnclosingMethod().getName()).addInitializer(cmd -> {
+ cmd.setFakeRuntime();
+
+ FileAssociations fa = new FileAssociations(
+ "ShortcutHintTest_testFileAssociations");
+ fa.createFile();
+ cmd.addArguments("--file-associations", fa.getPropertiesFile());
+ }).run();
+ }
+
+ /**
+ * Additional launcher with icon should create desktop shortcut even though
+ * `--linux-shortcut` is omitted.
+ */
+ static void testAdditionaltLaunchers() {
+ createTest(new Object() {
+ }.getClass().getEnclosingMethod().getName()).addInitializer(cmd -> {
+ cmd.setFakeRuntime();
+
+ final String launcherName = "Foo";
+ final Path propsFile = Test.workDir().resolve(
+ launcherName + ".properties");
+
+ cmd.addArguments("--add-launcher", String.format("%s=%s",
+ launcherName, propsFile));
+
+ Test.createPropertiesFile(propsFile, Map.entry("icon",
+ Test.TEST_SRC_ROOT.resolve("apps/dukeplug.png").toString()));
+ }).run();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/tools/jpackage/manage_packages.sh Tue Sep 24 13:41:16 2019 -0400
@@ -0,0 +1,185 @@
+#!/bin/bash
+
+#
+# Script to install/uninstall packages produced by jpackage jtreg
+# tests doing platform specific packaging.
+#
+# The script will install/uninstall all packages from the files
+# found in the current directory or the one specified with command line option.
+#
+# When jtreg jpackage tests are executed with jpackage.test.output
+# Java property set, produced package files (msi, exe, deb, rpm, etc.) will
+# be saved in the directory specified with this property.
+#
+# Usage example:
+# # Set directory where to save package files from jtreg jpackage tests
+# JTREG_OUTPUT_DIR=/tmp/jpackage_jtreg_packages
+#
+# # Run tests and fill $JTREG_OUTPUT_DIR directory with package files
+# jtreg -Djpackage.test.output=$JTREG_OUTPUT_DIR ...
+#
+# # Install all packages
+# manage_pachages.sh -d $JTREG_OUTPUT_DIR
+#
+# # Uninstall all packages
+# manage_pachages.sh -d $JTREG_OUTPUT_DIR -u
+#
+
+#
+# When using with MSI installers, Cygwin shell from which this script is
+# executed should be started as administrator. Otherwise silent installation
+# won't work.
+#
+
+# Fail fast
+set -e; set -o pipefail;
+
+
+help_usage ()
+{
+ echo "Usage: `basename $0` [OPTION]"
+ echo "Options:"
+ echo " -h - print this message"
+ echo " -v - verbose output"
+ echo " -d <dir> - path to directory where to look for package files"
+ echo " -u - uninstall packages instead of the default install"
+ echo " -t - dry run, print commands but don't execute them"
+}
+
+error ()
+{
+ echo "$@" > /dev/stderr
+}
+
+fatal ()
+{
+ error "$@"
+ exit 1
+}
+
+fatal_with_help_usage ()
+{
+ error "$@"
+ help_usage
+ exit 1
+}
+
+
+# Directory where to look for package files.
+package_dir=$PWD
+
+# Script debug.
+verbose=
+
+# Operation mode.
+mode=install
+
+dryrun=
+
+while getopts "vhd:ut" argname; do
+ case "$argname" in
+ v) verbose=yes;;
+ t) dryrun=yes;;
+ u) mode=uninstall;;
+ d) package_dir="$OPTARG";;
+ h) help_usage; exit 0;;
+ ?) help_usage; exit 1;;
+ esac
+done
+shift $(( OPTIND - 1 ))
+
+[ -d "$package_dir" ] || fatal_with_help_usage "Package directory [$package_dir] is not a directory"
+
+[ -z "$verbose" ] || set -x
+
+
+function find_packages_of_type ()
+{
+ # sort output alphabetically
+ find "$package_dir" -maxdepth 1 -type f -name '*.'"$1" | sort
+}
+
+function find_packages ()
+{
+ local package_suffixes=(deb rpm msi exe)
+ for suffix in "${package_suffixes[@]}"; do
+ if [ "$mode" == "uninstall" ]; then
+ packages=$(find_packages_of_type $suffix | tac)
+ else
+ packages=$(find_packages_of_type $suffix)
+ fi
+ if [ -n "$packages" ]; then
+ package_type=$suffix
+ break;
+ fi
+ done
+}
+
+
+# RPM
+install_cmd_rpm ()
+{
+ echo sudo rpm --install "$@"
+}
+uninstall_cmd_rpm ()
+{
+ local package_name=$(rpm -qp --queryformat '%{Name}' "$@")
+ echo sudo rpm -e "$package_name"
+}
+
+# DEB
+install_cmd_deb ()
+{
+ echo sudo dpkg -i "$@"
+}
+uninstall_cmd_deb ()
+{
+ local package_name=$(dpkg-deb -f "$@" Package)
+ echo sudo dpkg -r "$package_name"
+}
+
+# MSI
+install_cmd_msi ()
+{
+ echo msiexec /qn /norestart /i $(cygpath -w "$@")
+}
+uninstall_cmd_msi ()
+{
+ echo msiexec /qn /norestart /x $(cygpath -w "$@")
+}
+
+# EXE
+install_cmd_exe ()
+{
+ echo "$@"
+}
+uninstall_cmd_exe ()
+{
+ error No implemented
+}
+
+
+# Find packages
+packages=
+find_packages
+if [ -z "$packages" ]; then
+ echo "No packages found in $package_dir directory"
+ exit
+fi
+
+# Build list of commands to execute
+declare -a commands
+for p in $packages; do
+ commands[${#commands[@]}]=$(${mode}_cmd_${package_type} "$p")
+done
+
+if [ -z "$dryrun" ]; then
+ # Run commands
+ for cmd in "${commands[@]}"; do
+ echo Running: $cmd
+ $cmd || true;
+ done
+else
+ # Print commands
+ for cmd in "${commands[@]}"; do echo $cmd; done
+fi
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/tools/jpackage/run_tests.sh Tue Sep 24 13:41:16 2019 -0400
@@ -0,0 +1,278 @@
+#!/bin/bash
+
+#
+# Script to run jpackage tests.
+#
+
+
+# Fail fast
+set -e; set -o pipefail;
+
+
+# Link obtained from https://openjdk.java.net/jtreg/ page
+jtreg_bundle=https://ci.adoptopenjdk.net/view/Dependencies/job/jtreg/lastSuccessfulBuild/artifact/jtreg-4.2.0-tip.tar.gz
+workdir=/tmp/jpackage_jtreg_testing
+jtreg_jar=$workdir/jtreg/lib/jtreg.jar
+
+# Names of shared packaging tests to run
+share_package_test_names="
+ FileAssociationsTest
+ InstallDirTest
+ LicenseTest
+ SimplePackageTest
+ RuntimePackageTest
+ AdditionalLaunchersTest
+ AppImagePackageTest
+"
+mapfile -t packaging_tests_share < <(for t in $share_package_test_names; do echo test/jdk/tools/jpackage/share/$t.java; done)
+packaging_tests_windows=test/jdk/tools/jpackage/windows
+packaging_tests_linux=test/jdk/tools/jpackage/linux
+packaging_tests_mac=test/jdk/tools/jpackage/macosx
+
+case "$(uname -s)" in
+ Darwin)
+ tests=( "$packaging_tests_mac" );;
+ Linux)
+ tests=( "$packaging_tests_linux" );;
+ CYGWIN*|MINGW32*|MSYS*)
+ tests=( "$packaging_tests_windows" );;
+ *)
+ fatal Failed to detect OS type;;
+esac
+tests+=(${packaging_tests_share[@]})
+
+
+help_usage ()
+{
+ echo "Usage: `basename $0` [options] [test_names]"
+ echo "Options:"
+ echo " -h - print this message"
+ echo " -v - verbose output"
+ echo " -c - keep jtreg cache"
+ echo " -d - dry run. Print jtreg command line, but don't execute it"
+ echo " -t <jdk> - path to JDK to be tested [ mandatory ]"
+ echo " -j <openjdk> - path to local copy of openjdk repo with jpackage jtreg tests"
+ echo " Optional, default is openjdk repo where this script resides"
+ echo " -o <outputdir> - path to folder where to copy artifacts for testing."
+ echo " Optional, default is the current directory."
+ echo ' -r <runtimedir> - value for `jpackage.test.runtime-image` property.'
+ echo " Optional, for jtreg tests debug purposes only."
+ echo ' -l <logfile> - value for `jpackage.test.logfile` property.'
+ echo " Optional, for jtreg tests debug purposes only."
+ echo " -m <mode> - mode to run jtreg tests."
+ echo ' Should be one of `create`, `update`, `verify-install` or `verify-uninstall`.'
+ echo ' Optional, default mode is `update`.'
+ echo ' - `create`'
+ echo ' Remove all package bundles from the output directory before running jtreg tests.'
+ echo ' - `update`'
+ echo ' Run jtreg tests and overrite existing package bundles in the output directory.'
+ echo ' - `verify-install`'
+ echo ' Verify installed packages created with the previous run of the script.'
+ echo ' - `verify-uninstall`'
+ echo ' Verify packages created with the previous run of the script were uninstalled cleanly.'
+ echo ' - `print-default-tests`'
+ echo ' Print default tests list and exit.'
+}
+
+error ()
+{
+ echo "$@" > /dev/stderr
+}
+
+fatal ()
+{
+ error "$@"
+ exit 1
+}
+
+fatal_with_help_usage ()
+{
+ error "$@"
+ help_usage
+ exit 1
+}
+
+if command -v cygpath &> /dev/null; then
+to_native_path ()
+{
+ cygpath -m "$@"
+}
+else
+to_native_path ()
+{
+ echo "$@"
+}
+fi
+
+exec_command ()
+{
+ if [ -n "$dry_run" ]; then
+ echo "$@"
+ else
+ eval "$@"
+ fi
+}
+
+expand_test_selector ()
+{
+ if [ -d "$open_jdk_with_jpackage_jtreg_tests/$1" ]; then
+ for java in $(find "$open_jdk_with_jpackage_jtreg_tests/$1" -maxdepth 1 -name '*.java'); do
+ ! grep -q '@test' "$java" || echo "$1/$(basename "$java")"
+ done
+ else
+ echo "$1"
+ fi
+}
+
+
+# Path to JDK to be tested.
+test_jdk=
+
+# Path to local copy of open jdk repo with jpackage jtreg tests
+# hg clone http://hg.openjdk.java.net/jdk/sandbox
+# cd sandbox; hg update -r JDK-8200758-branch
+open_jdk_with_jpackage_jtreg_tests=$(dirname $0)/../../../../
+
+# Directory where to save artifacts for testing.
+output_dir=$PWD
+
+# Script and jtreg debug.
+verbose=
+jtreg_verbose="-verbose:fail,error,summary"
+
+keep_jtreg_cache=
+
+# Mode in which to run jtreg tests
+mode=update
+
+# JVM extra arguments
+declare -a vm_args
+
+while getopts "vhdct:j:o:r:m:l:" argname; do
+ case "$argname" in
+ v) verbose=yes;;
+ d) dry_run=yes;;
+ c) keep_jtreg_cache=yes;;
+ t) test_jdk="$OPTARG";;
+ j) open_jdk_with_jpackage_jtreg_tests="$OPTARG";;
+ o) output_dir="$OPTARG";;
+ r) runtime_dir="$OPTARG";;
+ l) logfile="$OPTARG";;
+ m) mode="$OPTARG";;
+ h) help_usage; exit 0;;
+ ?) help_usage; exit 1;;
+ esac
+done
+shift $(( OPTIND - 1 ))
+
+[ -z "$verbose" ] || { set -x; jtreg_verbose=-va; }
+
+if [ -z "$open_jdk_with_jpackage_jtreg_tests" ]; then
+ fatal_with_help_usage "Path to openjdk repo with jpackage jtreg tests not specified"
+fi
+
+if [ "$mode" = "print-default-tests" ]; then
+ exec_command for t in ${tests[@]}";" do expand_test_selector '$t;' done
+ exit
+fi
+
+if [ -z "$test_jdk" ]; then
+ fatal_with_help_usage Path to test JDK not specified
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ echo JAVA_HOME environment variable not set, will use java from test JDK [$test_jdk] to run jtreg
+ JAVA_HOME="$test_jdk"
+fi
+if [ ! -e "$JAVA_HOME/bin/java" ]; then
+ fatal JAVA_HOME variable is set to [$JAVA_HOME] value, but $JAVA_HOME/bin/java not found.
+fi
+
+if [ -n "$runtime_dir" ]; then
+ if [ ! -d "$runtime_dir" ]; then
+ fatal 'Value of `-r` option is set to non-existing directory'.
+ fi
+ vm_args+=("-Djpackage.test.runtime-image=$(to_native_path "$(cd "$runtime_dir" && pwd)")")
+fi
+
+if [ -n "$logfile" ]; then
+ if [ ! -d "$(dirname "$logfile")" ]; then
+ fatal 'Value of `-l` option specified a file in non-existing directory'.
+ fi
+ logfile="$(cd "$(dirname "$logfile")" && pwd)/$(basename "$logfile")"
+ vm_args+=("-Djpackage.test.logfile=$(to_native_path "$logfile")")
+fi
+
+if [ "$mode" = create ]; then
+ true
+elif [ "$mode" = update ]; then
+ true
+elif [ "$mode" = verify-install ]; then
+ vm_args+=("-Djpackage.test.action=$mode")
+elif [ "$mode" = verify-uninstall ]; then
+ vm_args+=("-Djpackage.test.action=$mode")
+else
+ fatal_with_help_usage 'Invalid value of -m option:' [$mode]
+fi
+
+
+# All remaining command line arguments are tests to run that should override the defaults
+[ $# -eq 0 ] || tests=($@)
+
+
+installJtreg ()
+{
+ # Install jtreg if missing
+ if [ ! -f "$jtreg_jar" ]; then
+ exec_command mkdir -p "$workdir"
+ exec_command "(" cd "$workdir" "&&" wget "$jtreg_bundle" "&&" tar -xzf "$(basename $jtreg_bundle)" ";" rm -f "$(basename $jtreg_bundle)" ")"
+ fi
+}
+
+
+preRun ()
+{
+ local xargs_args=(-t --no-run-if-empty rm)
+ if [ -n "$dry_run" ]; then
+ xargs_args=(--no-run-if-empty echo rm)
+ fi
+
+ if [ ! -d "$output_dir" ]; then
+ exec_command mkdir -p "$output_dir"
+ fi
+ [ ! -d "$output_dir" ] || output_dir=$(cd "$output_dir" && pwd)
+
+ # Clean output directory
+ [ "$mode" != "create" ] || find $output_dir -maxdepth 1 -type f -name '*.exe' -or -name '*.msi' -or -name '*.rpm' -or -name '*.deb' | xargs "${xargs_args[@]}"
+}
+
+
+run ()
+{
+ local jtreg_cmdline=(\
+ $JAVA_HOME/bin/java -jar $(to_native_path "$jtreg_jar") \
+ "-Djpackage.test.output=$(to_native_path "$output_dir")" \
+ "${vm_args[@]}" \
+ -nr \
+ "$jtreg_verbose" \
+ -retain:all \
+ -automatic \
+ -ignore:run \
+ -testjdk:"$(to_native_path $test_jdk)" \
+ -dir:"$(to_native_path $open_jdk_with_jpackage_jtreg_tests)" \
+ -reportDir:"$(to_native_path $workdir/run/results)" \
+ -workDir:"$(to_native_path $workdir/run/support)" \
+ "${tests[@]}" \
+ )
+
+ # Clear previous results
+ [ -n "$keep_jtreg_cache" ] || exec_command rm -rf "$workdir"/run
+
+ # Run jpackage jtreg tests to create artifacts for testing
+ exec_command ${jtreg_cmdline[@]}
+}
+
+
+installJtreg
+preRun
+run
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/tools/jpackage/share/AdditionalLaunchersTest.java Tue Sep 24 13:41:16 2019 -0400
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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.
+ */
+
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.List;
+import java.util.Optional;
+import java.lang.invoke.MethodHandles;
+import jdk.jpackage.test.HelloApp;
+import jdk.jpackage.test.PackageTest;
+import jdk.jpackage.test.PackageType;
+import jdk.jpackage.test.FileAssociations;
+import jdk.jpackage.test.Test;
+
+/**
+ * Test --add-launcher parameter. Output of the test should be
+ * additionallauncherstest*.* installer. The output installer should provide the
+ * same functionality as the default installer (see description of the default
+ * installer in SimplePackageTest.java) plus install three extra application
+ * launchers.
+ */
+
+/*
+ * @test
+ * @summary jpackage with --add-launcher
+ * @library ../helpers
+ * @modules jdk.jpackage/jdk.jpackage.internal
+ * @run main/othervm/timeout=360 -Xmx512m AdditionalLaunchersTest
+ */
+public class AdditionalLaunchersTest {
+
+ public static void main(String[] args) {
+ Test.run(args, () -> {
+ FileAssociations fa = new FileAssociations(
+ MethodHandles.lookup().lookupClass().getSimpleName());
+
+ // Configure a bunch of additional launchers and also setup
+ // file association to make sure it will be linked only to the main
+ // launcher.
+
+ PackageTest packageTest = new PackageTest().configureHelloApp()
+ .addInitializer(cmd -> {
+ fa.createFile();
+ cmd.addArguments("--file-associations", fa.getPropertiesFile());
+ cmd.addArguments("--arguments", "Duke", "--arguments", "is",
+ "--arguments", "the", "--arguments", "King");
+ });
+
+ packageTest.addHelloAppFileAssociationsVerifier(fa);
+
+ new AdditionalLauncher("Baz2").setArguments().applyTo(packageTest);
+ new AdditionalLauncher("foo").setArguments("yep!").applyTo(packageTest);
+
+ AdditionalLauncher barLauncher = new AdditionalLauncher("Bar").setArguments(
+ "one", "two", "three");
+ packageTest.forTypes(PackageType.LINUX).addInitializer(cmd -> {
+ barLauncher.setIcon(Test.TEST_SRC_ROOT.resolve("apps/dukeplug.png"));
+ });
+ barLauncher.applyTo(packageTest);
+
+ packageTest.run();
+ });
+ }
+
+ private static Path replaceFileName(Path path, String newFileName) {
+ String fname = path.getFileName().toString();
+ int lastDotIndex = fname.lastIndexOf(".");
+ if (lastDotIndex != -1) {
+ fname = newFileName + fname.substring(lastDotIndex);
+ }
+ return path.getParent().resolve(fname);
+ }
+
+ static class AdditionalLauncher {
+
+ AdditionalLauncher(String name) {
+ this.name = name;
+ }
+
+ AdditionalLauncher setArguments(String... args) {
+ arguments = List.of(args);
+ return this;
+ }
+
+ AdditionalLauncher setIcon(Path iconPath) {
+ icon = iconPath;
+ return this;
+ }
+
+ void applyTo(PackageTest test) {
+ final Path propsFile = Test.workDir().resolve(name + ".properties");
+
+ test.addInitializer(cmd -> {
+ cmd.addArguments("--add-launcher", String.format("%s=%s", name,
+ propsFile));
+
+ Map<String, String> properties = new HashMap<>();
+ if (arguments != null) {
+ properties.put("arguments", String.join(" ",
+ arguments.toArray(String[]::new)));
+ }
+
+ if (icon != null) {
+ properties.put("icon", icon.toAbsolutePath().toString());
+ }
+
+ Test.createPropertiesFile(propsFile, properties);
+ });
+ test.addInstallVerifier(cmd -> {
+ Path launcherPath = replaceFileName(
+ cmd.launcherInstallationPath(), name);
+
+ Test.assertExecutableFileExists(launcherPath, true);
+
+ if (cmd.isFakeRuntimeInstalled(String.format(
+ "Not running %s launcher", launcherPath))) {
+ return;
+ }
+ HelloApp.executeAndVerifyOutput(launcherPath,
+ Optional.ofNullable(arguments).orElse(List.of()).toArray(
+ String[]::new));
+ });
+ test.addUninstallVerifier(cmd -> {
+ Path launcherPath = replaceFileName(
+ cmd.launcherInstallationPath(), name);
+
+ Test.assertExecutableFileExists(launcherPath, false);
+ });
+ }
+
+ private List<String> arguments;
+ private Path icon;
+ private final String name;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/tools/jpackage/share/AppImagePackageTest.java Tue Sep 24 13:41:16 2019 -0400
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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.
+ */
+
+import java.nio.file.Path;
+import jdk.jpackage.test.Test;
+import jdk.jpackage.test.PackageTest;
+import jdk.jpackage.test.PackageType;
+import jdk.jpackage.test.JPackageCommand;
+
+/**
+ * Test --app-image parameter. The output installer should provide the same
+ * functionality as the default installer (see description of the default
+ * installer in SimplePackageTest.java)
+ */
+
+/*
+ * @test
+ * @summary jpackage with --app-image
+ * @library ../helpers
+ * @modules jdk.jpackage/jdk.jpackage.internal
+ * @run main/othervm/timeout=360 -Xmx512m AppImagePackageTest
+ */
+public class AppImagePackageTest {
+
+ public static void main(String[] args) {
+ Test.run(args, () -> {
+ Path appimageOutput = Path.of("appimage");
+
+ JPackageCommand appImageCmd = JPackageCommand.helloAppImage()
+ .setArgumentValue("--dest", appimageOutput)
+ .addArguments("--package-type", "app-image");
+
+ PackageTest packageTest = new PackageTest();
+ if (packageTest.getAction() == PackageTest.Action.CREATE) {
+ appImageCmd.execute();
+ }
+
+ packageTest.addInitializer(cmd -> {
+ Path appimageInput = appimageOutput.resolve(appImageCmd.name());
+
+ if (PackageType.MAC.contains(cmd.packageType())) {
+ // Why so complicated on macOS?
+ appimageInput = Path.of(appimageInput.toString() + ".app");
+ cmd.addArguments("--identifier", appImageCmd.name());
+ }
+
+ cmd.addArguments("--app-image", appimageInput);
+ cmd.removeArgument("--input");
+ }).addBundleDesktopIntegrationVerifier(false).run();
+ });
+ }
+}
--- a/test/jdk/tools/jpackage/share/FileAssociationsTest.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/share/FileAssociationsTest.java Tue Sep 24 13:41:16 2019 -0400
@@ -21,32 +21,26 @@
* questions.
*/
-import java.awt.Desktop;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Arrays;
-import jdk.jpackage.test.HelloApp;
+import jdk.jpackage.test.Test;
import jdk.jpackage.test.PackageTest;
-import jdk.jpackage.test.Test;
+import jdk.jpackage.test.FileAssociations;
/**
- * Test --file-associations parameter.
- * Output of the test should be fileassociationstest*.* installer.
- * The output installer should provide the same functionality as the default
- * installer (see description of the default installer in SimplePackageTest.java)
- * plus configure file associations.
- * After installation files with ".jptest1" suffix should be associated with
- * the test app.
+ * Test --file-associations parameter. Output of the test should be
+ * fileassociationstest*.* installer. The output installer should provide the
+ * same functionality as the default installer (see description of the default
+ * installer in SimplePackageTest.java) plus configure file associations. After
+ * installation files with ".jptest1" and ".jptest2" suffixes should be
+ * associated with the test app.
*
* Suggested test scenario is to create empty file with ".jptest1" suffix,
* double click on it and make sure that test application was launched in
- * response to double click event with the path to test .jptest1 file
- * on the commend line.
+ * response to double click event with the path to test .jptest1 file on the
+ * commend line. The same applies to ".jptest2" suffix.
*
- * On Linux use "echo > foo.jptest1" and not "touch foo.jptest1" to create
- * test file as empty files are always interpreted as plain text and will not
- * be opened with the test app. This is a known bug.
+ * On Linux use "echo > foo.jptest1" and not "touch foo.jptest1" to create test
+ * file as empty files are always interpreted as plain text and will not be
+ * opened with the test app. This is a known bug.
*/
/*
@@ -57,67 +51,22 @@
* @run main/othervm/timeout=360 -Xmx512m FileAssociationsTest
*/
public class FileAssociationsTest {
- public static void main(String[] args) throws Exception {
- new PackageTest().configureHelloApp()
- .addInitializer(cmd -> {
- initFaPropsFile();
- cmd.addArguments("--file-associations", FA_PROPS_FILE.toString());
- })
- .addInstallVerifier(cmd -> {
- Path testFile = null;
- try {
- testFile = Test.createTempFile("." + FA_SUFFIX);
- // Write something in test file.
- // On Ubuntu and Oracle Linux empty files are considered
- // plain text. Seems like a system bug.
- //
- // [asemenyu@spacewalk ~]$ rm gg.jptest1
- // $ touch foo.jptest1
- // $ xdg-mime query filetype foo.jptest1
- // text/plain
- // $ echo > foo.jptest1
- // $ xdg-mime query filetype foo.jptest1
- // application/x-jpackage-jptest1
- //
- Files.write(testFile, Arrays.asList(""));
+ public static void main(String[] args) {
+ Test.run(args, () -> {
+ PackageTest packageTest = new PackageTest();
- final Path appOutput = Path.of(HelloApp.OUTPUT_FILENAME);
- Files.deleteIfExists(appOutput);
-
- Test.trace(String.format("Use desktop to open [%s] file", testFile));
- Desktop.getDesktop().open(testFile.toFile());
- Test.waitForFileCreated(appOutput, 7);
-
- // Wait a little bit after file has been created to
- // make sure there are no pending writes into it.
- Thread.sleep(3000);
- HelloApp.verifyOutputFile(appOutput, testFile.toString());
- } catch (IOException | InterruptedException ex) {
- throw new RuntimeException(ex);
- } finally {
- if (testFile != null) {
- try {
- Files.deleteIfExists(testFile);
- } catch (IOException ex) {
- throw new RuntimeException(ex);
- }
- }
- }
- })
- .run();
+ applyFileAssociations(packageTest, new FileAssociations("jptest1"));
+ applyFileAssociations(packageTest,
+ new FileAssociations("jptest2").setFilename("fa2"));
+ packageTest.run();
+ });
}
- private static void initFaPropsFile() {
- try {
- Files.write(FA_PROPS_FILE, Arrays.asList(
- "extension=" + FA_SUFFIX,
- "mime-type=application/x-jpackage-" + FA_SUFFIX,
- "description=jpackage test extention"));
- } catch (IOException ex) {
- throw new RuntimeException(ex);
- }
+ private static void applyFileAssociations(PackageTest test,
+ FileAssociations fa) {
+ test.addInitializer(cmd -> {
+ fa.createFile();
+ cmd.addArguments("--file-associations", fa.getPropertiesFile());
+ }).addHelloAppFileAssociationsVerifier(fa);
}
-
- private final static String FA_SUFFIX = "jptest1";
- private final static Path FA_PROPS_FILE = Test.workDir().resolve("fa.properties");
}
--- a/test/jdk/tools/jpackage/share/InstallDirTest.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/share/InstallDirTest.java Tue Sep 24 13:41:16 2019 -0400
@@ -25,6 +25,7 @@
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
+import jdk.jpackage.test.Test;
import jdk.jpackage.test.PackageTest;
import jdk.jpackage.test.PackageType;
@@ -57,32 +58,32 @@
*/
public class InstallDirTest {
- public static void main(String[] args) throws Exception {
- final Map<PackageType, String> INSTALL_DIRS = new Supplier<Map<PackageType, String>>() {
+ public static void main(String[] args) {
+ final Map<PackageType, Path> INSTALL_DIRS = new Supplier<Map<PackageType, Path>>() {
@Override
- public Map<PackageType, String> get() {
- Map<PackageType, String> reply = new HashMap<>();
- reply.put(PackageType.WIN_MSI, Path.of("TestVendor",
- "InstallDirTest1234").toString());
+ public Map<PackageType, Path> get() {
+ Map<PackageType, Path> reply = new HashMap<>();
+ reply.put(PackageType.WIN_MSI, Path.of(
+ "TestVendor\\InstallDirTest1234"));
reply.put(PackageType.WIN_EXE, reply.get(PackageType.WIN_MSI));
- reply.put(PackageType.LINUX_DEB,
- Path.of("/opt", "jpackage").toString());
+ reply.put(PackageType.LINUX_DEB, Path.of("/opt/jpackage"));
reply.put(PackageType.LINUX_RPM,
reply.get(PackageType.LINUX_DEB));
- reply.put(PackageType.MAC_PKG, Path.of("/Application",
- "jpackage").toString());
+ reply.put(PackageType.MAC_PKG, Path.of("/Application/jpackage"));
reply.put(PackageType.MAC_DMG, reply.get(PackageType.MAC_PKG));
return reply;
}
}.get();
- new PackageTest().configureHelloApp()
- .addInitializer(cmd -> {
- cmd.addArguments("--install-dir", INSTALL_DIRS.get(
- cmd.packageType()));
- }).run();
+ Test.run(args, () -> {
+ new PackageTest().configureHelloApp()
+ .addInitializer(cmd -> {
+ cmd.addArguments("--install-dir", INSTALL_DIRS.get(
+ cmd.packageType()));
+ }).run();
+ });
}
}
--- a/test/jdk/tools/jpackage/share/LicenseTest.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/share/LicenseTest.java Tue Sep 24 13:41:16 2019 -0400
@@ -24,10 +24,13 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.io.File;
+import java.util.List;
+import java.util.Arrays;
+import java.util.function.Function;
+import java.util.stream.Collectors;
import jdk.jpackage.test.JPackageCommand;
+import jdk.jpackage.test.PackageType;
import jdk.jpackage.test.PackageTest;
-import jdk.jpackage.test.PackageType;
import jdk.jpackage.test.LinuxHelper;
import jdk.jpackage.test.Executor;
import jdk.jpackage.test.Test;
@@ -64,42 +67,42 @@
* @run main/othervm/timeout=360 -Xmx512m LicenseTest
*/
public class LicenseTest {
- public static void main(String[] args) throws Exception {
- new PackageTest().configureHelloApp()
- .addInitializer(cmd -> {
- cmd.addArguments("--license-file", LICENSE_FILE.toString());
- })
- .forTypes(PackageType.LINUX_DEB)
- .addBundleVerifier(cmd -> {
- verifyLicenseFileInLinuxPackage(cmd, debLicenseFile(cmd));
- })
- .addInstallVerifier(cmd -> {
- verifyLicenseFileInstalledLinux(debLicenseFile(cmd));
- })
- .addUninstallVerifier(cmd -> {
- verifyLicenseFileNotInstalledLinux(debLicenseFile(cmd));
- })
- .forTypes(PackageType.LINUX_RPM)
- .addBundleVerifier(cmd -> {
- verifyLicenseFileInLinuxPackage(cmd,rpmLicenseFile(cmd));
- })
- .addInstallVerifier(cmd -> {
- verifyLicenseFileInstalledLinux(rpmLicenseFile(cmd));
- })
- .addUninstallVerifier(cmd -> {
- verifyLicenseFileNotInstalledLinux(rpmLicenseFile(cmd));
- })
- .run();
- }
+ public static void main(String[] args) {
+ Test.run(args, () -> {
+ new PackageTest().configureHelloApp()
+ .addInitializer(cmd -> {
+ cmd.addArguments("--license-file", LICENSE_FILE);
+ })
+ .forTypes(PackageType.LINUX_DEB)
+ .addBundleVerifier(cmd -> {
+ verifyLicenseFileInLinuxPackage(cmd, debLicenseFile(cmd));
+ })
+ .addInstallVerifier(cmd -> {
+ verifyLicenseFileInstalledDebian(debLicenseFile(cmd));
+ })
+ .addUninstallVerifier(cmd -> {
+ verifyLicenseFileNotInstalledLinux(debLicenseFile(cmd));
+ })
+ .forTypes(PackageType.LINUX_RPM)
+ .addBundleVerifier(cmd -> {
+ verifyLicenseFileInLinuxPackage(cmd,rpmLicenseFile(cmd));
+ })
+ .addInstallVerifier(cmd -> {
+ verifyLicenseFileInstalledRpm(rpmLicenseFile(cmd));
+ })
+ .addUninstallVerifier(cmd -> {
+ verifyLicenseFileNotInstalledLinux(rpmLicenseFile(cmd));
+ })
+ .run();
+ });
+ }
private static Path rpmLicenseFile(JPackageCommand cmd) {
final Path licenseRoot = Path.of(
new Executor()
.setExecutable("rpm")
.addArguments("--eval", "%{_defaultlicensedir}")
- .saveFirstLineOfOutput()
- .execute()
- .assertExitCodeIsZero().getFirstLineOfOutput());
+ .executeAndGetFirstLineOfOutput());
final Path licensePath = licenseRoot.resolve(String.format("%s-%s",
LinuxHelper.getPackageName(cmd), cmd.version())).resolve(
LICENSE_FILE.getFileName());
@@ -120,7 +123,7 @@
expectedLicensePath, LinuxHelper.getPackageName(cmd)));
}
- private static void verifyLicenseFileInstalledLinux(Path licenseFile) {
+ private static void verifyLicenseFileInstalledRpm(Path licenseFile) {
Test.assertTrue(Files.isReadable(licenseFile), String.format(
"Check license file [%s] is readable", licenseFile));
try {
@@ -133,6 +136,35 @@
}
}
+ private static void verifyLicenseFileInstalledDebian(Path licenseFile) {
+ Test.assertTrue(Files.isReadable(licenseFile), String.format(
+ "Check license file [%s] is readable", licenseFile));
+
+ Function<List<String>, List<String>> stripper = (lines) -> Arrays.asList(
+ String.join("\n", lines).stripTrailing().split("\n"));
+
+ try {
+ List<String> actualLines = Files.readAllLines(licenseFile).stream().dropWhile(
+ line -> !line.startsWith("License:")).collect(
+ Collectors.toList());
+ // Remove leading `License:` followed by the whitespace from the first text line.
+ actualLines.set(0, actualLines.get(0).split("\\s+", 2)[1]);
+
+ actualLines = stripper.apply(actualLines);
+
+ Test.assertNotEquals(0, String.join("\n", actualLines).length(),
+ "Check stripped license text is not empty");
+
+ Test.assertTrue(actualLines.equals(
+ stripper.apply(Files.readAllLines(LICENSE_FILE))),
+ String.format(
+ "Check subset of package license file [%s] is a match of the source license file [%s]",
+ licenseFile, LICENSE_FILE));
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
private static void verifyLicenseFileNotInstalledLinux(Path licenseFile) {
Test.assertDirectoryExists(licenseFile.getParent(), false);
}
--- a/test/jdk/tools/jpackage/share/RuntimePackageTest.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/share/RuntimePackageTest.java Tue Sep 24 13:41:16 2019 -0400
@@ -21,7 +21,11 @@
* questions.
*/
+import java.nio.file.Path;
+import java.util.Optional;
+import jdk.jpackage.test.Test;
import jdk.jpackage.test.PackageTest;
+import jdk.jpackage.test.JPackageCommand;
/**
* Test --runtime-image parameter.
@@ -41,21 +45,25 @@
* @summary jpackage with --runtime-image
* @library ../helpers
* @comment Temporary disable for Linux and OSX until functionality implemented
- * @requires (os.family == "windows")
+ * @requires (os.family != "mac")
* @modules jdk.jpackage/jdk.jpackage.internal
- * @run main/othervm -Xmx512m RuntimePackageTest
+ * @run main/othervm/timeout=360 -Xmx512m RuntimePackageTest
*/
public class RuntimePackageTest {
public static void main(String[] args) {
- new PackageTest()
- .addInitializer(cmd -> {
- cmd.addArguments("--runtime-image", System.getProperty("java.home"));
- // Remove --input parameter from jpackage command line as we don't
- // create input directory in the test and jpackage fails
- // if --input references non existant directory.
- cmd.setArgumentValue("--input", null);
- })
- .run();
+ Test.run(args, () -> {
+ new PackageTest()
+ .addInitializer(cmd -> {
+ cmd.addArguments("--runtime-image", Optional.ofNullable(
+ JPackageCommand.DEFAULT_RUNTIME_IMAGE).orElse(Path.of(
+ System.getProperty("java.home"))));
+ // Remove --input parameter from jpackage command line as we don't
+ // create input directory in the test and jpackage fails
+ // if --input references non existant directory.
+ cmd.removeArgument("--input");
+ })
+ .run();
+ });
}
}
--- a/test/jdk/tools/jpackage/share/SimplePackageTest.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/share/SimplePackageTest.java Tue Sep 24 13:41:16 2019 -0400
@@ -21,6 +21,7 @@
* questions.
*/
+import jdk.jpackage.test.Test;
import jdk.jpackage.test.PackageTest;
/**
@@ -45,7 +46,12 @@
*/
public class SimplePackageTest {
- public static void main(String[] args) throws Exception {
- new PackageTest().configureHelloApp().run();
+ public static void main(String[] args) {
+ Test.run(args, () -> {
+ new PackageTest()
+ .configureHelloApp()
+ .addBundleDesktopIntegrationVerifier(false)
+ .run();
+ });
}
}
--- a/test/jdk/tools/jpackage/share/manage_packages.sh Mon Sep 16 19:24:32 2019 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,185 +0,0 @@
-#!/bin/bash
-
-#
-# Script to install/uninstall packages produced by jpackage jtreg
-# tests doing platform specific packaging.
-#
-# The script will install/uninstall all packages from the files
-# found in the current directory or the one specified with command line option.
-#
-# When jtreg jpackage tests are executed with jpackage.test.output
-# Java property set, produced package files (msi, exe, deb, rpm, etc.) will
-# be saved in the directory specified with this property.
-#
-# Usage example:
-# # Set directory where to save package files from jtreg jpackage tests
-# JTREG_OUTPUT_DIR=/tmp/jpackage_jtreg_packages
-#
-# # Run tests and fill $JTREG_OUTPUT_DIR directory with package files
-# jtreg -Djpackage.test.output=$JTREG_OUTPUT_DIR ...
-#
-# # Install all packages
-# manage_pachages.sh -d $JTREG_OUTPUT_DIR
-#
-# # Uninstall all packages
-# manage_pachages.sh -d $JTREG_OUTPUT_DIR -u
-#
-
-#
-# When using with MSI installers, Cygwin shell from which this script is
-# executed should be started as administrator. Otherwise silent installation
-# won't work.
-#
-
-# Fail fast
-set -e; set -o pipefail;
-
-
-help_usage ()
-{
- echo "Usage: `basename $0` [OPTION]"
- echo "Options:"
- echo " -h - print this message"
- echo " -v - verbose output"
- echo " -d <dir> - path to directory where to look for package files"
- echo " -u - uninstall packages instead of the default install"
- echo " -t - dry run, print commands but don't execute them"
-}
-
-error ()
-{
- echo "$@" > /dev/stderr
-}
-
-fatal ()
-{
- error "$@"
- exit 1
-}
-
-fatal_with_help_usage ()
-{
- error "$@"
- help_usage
- exit 1
-}
-
-
-# Directory where to look for package files.
-package_dir=$PWD
-
-# Script debug.
-verbose=
-
-# Operation mode.
-mode=install
-
-dryrun=
-
-while getopts "vhd:ut" argname; do
- case "$argname" in
- v) verbose=yes;;
- t) dryrun=yes;;
- u) mode=uninstall;;
- d) package_dir="$OPTARG";;
- h) help_usage; exit 0;;
- ?) help_usage; exit 1;;
- esac
-done
-shift $(( OPTIND - 1 ))
-
-[ -d "$package_dir" ] || fatal_with_help_usage "Package directory [$package_dir] is not a directory"
-
-[ -z "$verbose" ] || set -x
-
-
-function find_packages_of_type ()
-{
- # sort output alphabetically
- find "$package_dir" -maxdepth 1 -type f -name '*.'"$1" | sort
-}
-
-function find_packages ()
-{
- local package_suffixes=(deb rpm msi exe)
- for suffix in "${package_suffixes[@]}"; do
- if [ "$mode" == "uninstall" ]; then
- packages=$(find_packages_of_type $suffix | tac)
- else
- packages=$(find_packages_of_type $suffix)
- fi
- if [ -n "$packages" ]; then
- package_type=$suffix
- break;
- fi
- done
-}
-
-
-# RPM
-install_cmd_rpm ()
-{
- echo sudo rpm --install "$@"
-}
-uninstall_cmd_rpm ()
-{
- local package_name=$(rpm -qp --queryformat '%{Name}' "$@")
- echo sudo rpm -e "$package_name"
-}
-
-# DEB
-install_cmd_deb ()
-{
- echo sudo dpkg -i "$@"
-}
-uninstall_cmd_deb ()
-{
- local package_name=$(dpkg-deb -f "$@" Package)
- echo sudo dpkg -r "$package_name"
-}
-
-# MSI
-install_cmd_msi ()
-{
- echo msiexec /qn /norestart /i $(cygpath -w "$@")
-}
-uninstall_cmd_msi ()
-{
- echo msiexec /qn /norestart /x $(cygpath -w "$@")
-}
-
-# EXE
-install_cmd_exe ()
-{
- echo "$@"
-}
-uninstall_cmd_exe ()
-{
- error No implemented
-}
-
-
-# Find packages
-packages=
-find_packages
-if [ -z "$packages" ]; then
- echo "No packages found in $package_dir directory"
- exit
-fi
-
-# Build list of commands to execute
-declare -a commands
-for p in $packages; do
- commands[${#commands[@]}]=$(${mode}_cmd_${package_type} "$p")
-done
-
-if [ -z "$dryrun" ]; then
- # Run commands
- for cmd in "${commands[@]}"; do
- echo Running: $cmd
- $cmd || true;
- done
-else
- # Print commands
- for cmd in "${commands[@]}"; do echo $cmd; done
-fi
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/tools/jpackage/test_jpackage.sh Tue Sep 24 13:41:16 2019 -0400
@@ -0,0 +1,68 @@
+#!/bin/bash
+
+#
+# Complete testing of jpackage platform-specific packaging.
+#
+# The script does the following:
+# 1. Create packages.
+# 2. Install created packages.
+# 3. Verifies packages are installed.
+# 4. Uninstall created packages.
+# 5. Verifies packages are uninstalled.
+#
+# For the list of accepted command line arguments see `run_tests.sh` script.
+#
+
+# Fail fast
+set -e; set -o pipefail;
+
+# Script debug
+dry_run=${JPACKAGE_TEST_DRY_RUN}
+
+# Default directory where jpackage should write bundle files
+output_dir=~/jpackage_bundles
+
+
+set_args ()
+{
+ args=()
+ local arg_is_output_dir=
+ local arg_is_mode=
+ local output_dir_set=
+ for arg in "$@"; do
+ if [ "$arg" == "-o" ]; then
+ arg_is_output_dir=yes
+ output_dir_set=yes
+ elif [ "$arg" == "-m" ]; then
+ arg_is_mode=yes
+ continue
+ elif [ -n "$arg_is_output_dir" ]; then
+ arg_is_output_dir=
+ output_dir="$arg"
+ elif [ -n "$arg_is_mode" ]; then
+ arg_is_mode=
+ continue
+ fi
+
+ args+=( "$arg" )
+ done
+ [ -n "$output_dir_set" ] || args=( -o "$output_dir" "${args[@]}" )
+}
+
+
+exec_command ()
+{
+ if [ -n "$dry_run" ]; then
+ echo "$@"
+ else
+ eval "$@"
+ fi
+}
+
+set_args "$@"
+basedir="$(dirname $0)"
+exec_command "$basedir/run_tests.sh" -m create "${args[@]}"
+exec_command "$basedir/manage_packages.sh" -d "$output_dir"
+exec_command "$basedir/run_tests.sh" -m verify-install "${args[@]}"
+exec_command "$basedir/manage_packages.sh" -d "$output_dir" -u
+exec_command "$basedir/run_tests.sh" -m verify-uninstall "${args[@]}"
--- a/test/jdk/tools/jpackage/windows/WinConsoleTest.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/windows/WinConsoleTest.java Tue Sep 24 13:41:16 2019 -0400
@@ -37,24 +37,26 @@
* @library ../helpers
* @requires (os.family == "windows")
* @modules jdk.jpackage/jdk.jpackage.internal
- * @run main/othervm -Xmx512m WinConsoleTest
+ * @run main/othervm/timeout=360 -Xmx512m WinConsoleTest
*/
public class WinConsoleTest {
- public static void main(String[] args) throws IOException {
- JPackageCommand cmd = JPackageCommand.helloAppImage();
- final Path launcherPath = cmd.appImage().resolve(
- cmd.launcherPathInAppImage());
+ public static void main(String[] args) {
+ Test.run(args, () -> {
+ JPackageCommand cmd = JPackageCommand.helloAppImage();
+ final Path launcherPath = cmd.appImage().resolve(
+ cmd.launcherPathInAppImage());
- IOUtils.deleteRecursive(cmd.outputDir().toFile());
- cmd.execute().assertExitCodeIsZero();
- HelloApp.executeAndVerifyOutput(launcherPath);
- checkSubsystem(launcherPath, false);
+ IOUtils.deleteRecursive(cmd.outputDir().toFile());
+ cmd.execute().assertExitCodeIsZero();
+ HelloApp.executeLauncherAndVerifyOutput(cmd);
+ checkSubsystem(launcherPath, false);
- IOUtils.deleteRecursive(cmd.outputDir().toFile());
- cmd.addArgument("--win-console").execute().assertExitCodeIsZero();
- HelloApp.executeAndVerifyOutput(launcherPath);
- checkSubsystem(launcherPath, true);
+ IOUtils.deleteRecursive(cmd.outputDir().toFile());
+ cmd.addArgument("--win-console").execute().assertExitCodeIsZero();
+ HelloApp.executeLauncherAndVerifyOutput(cmd);
+ checkSubsystem(launcherPath, true);
+ });
}
private static void checkSubsystem(Path path, boolean isConsole) throws
--- a/test/jdk/tools/jpackage/windows/WinDirChooserTest.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/windows/WinDirChooserTest.java Tue Sep 24 13:41:16 2019 -0400
@@ -21,6 +21,7 @@
* questions.
*/
+import jdk.jpackage.test.Test;
import jdk.jpackage.test.PackageTest;
import jdk.jpackage.test.PackageType;
@@ -38,14 +39,16 @@
* @library ../helpers
* @requires (os.family == "windows")
* @modules jdk.jpackage/jdk.jpackage.internal
- * @run main/othervm -Xmx512m WinDirChooserTest
+ * @run main/othervm/timeout=360 -Xmx512m WinDirChooserTest
*/
public class WinDirChooserTest {
public static void main(String[] args) {
- new PackageTest()
- .forTypes(PackageType.WINDOWS)
- .configureHelloApp()
- .addInitializer(cmd -> cmd.addArgument("--win-dir-chooser")).run();
+ Test.run(args, () -> {
+ new PackageTest()
+ .forTypes(PackageType.WINDOWS)
+ .configureHelloApp()
+ .addInitializer(cmd -> cmd.addArgument("--win-dir-chooser")).run();
+ });
}
}
--- a/test/jdk/tools/jpackage/windows/WinMenuGroupTest.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/windows/WinMenuGroupTest.java Tue Sep 24 13:41:16 2019 -0400
@@ -21,6 +21,7 @@
* questions.
*/
+import jdk.jpackage.test.Test;
import jdk.jpackage.test.PackageTest;
import jdk.jpackage.test.PackageType;
@@ -40,16 +41,18 @@
* @library ../helpers
* @requires (os.family == "windows")
* @modules jdk.jpackage/jdk.jpackage.internal
- * @run main/othervm -Xmx512m WinMenuGroupTest
+ * @run main/othervm/timeout=360 -Xmx512m WinMenuGroupTest
*/
public class WinMenuGroupTest {
public static void main(String[] args) {
- new PackageTest()
- .forTypes(PackageType.WINDOWS)
- .configureHelloApp()
- .addInitializer(cmd -> cmd.addArguments(
- "--win-menu", "--win-menu-group", "WinMenuGroupTest_MenuGroup"))
- .run();
+ Test.run(args, () -> {
+ new PackageTest()
+ .forTypes(PackageType.WINDOWS)
+ .configureHelloApp()
+ .addInitializer(cmd -> cmd.addArguments(
+ "--win-menu", "--win-menu-group", "WinMenuGroupTest_MenuGroup"))
+ .run();
+ });
}
}
--- a/test/jdk/tools/jpackage/windows/WinMenuTest.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/windows/WinMenuTest.java Tue Sep 24 13:41:16 2019 -0400
@@ -21,6 +21,7 @@
* questions.
*/
+import jdk.jpackage.test.Test;
import jdk.jpackage.test.PackageTest;
import jdk.jpackage.test.PackageType;
@@ -37,14 +38,16 @@
* @library ../helpers
* @requires (os.family == "windows")
* @modules jdk.jpackage/jdk.jpackage.internal
- * @run main/othervm -Xmx512m WinMenuTest
+ * @run main/othervm/timeout=360 -Xmx512m WinMenuTest
*/
public class WinMenuTest {
public static void main(String[] args) {
- new PackageTest()
- .forTypes(PackageType.WINDOWS)
- .configureHelloApp()
- .addInitializer(cmd -> cmd.addArgument("--win-menu")).run();
+ Test.run(args, () -> {
+ new PackageTest()
+ .forTypes(PackageType.WINDOWS)
+ .configureHelloApp()
+ .addInitializer(cmd -> cmd.addArgument("--win-menu")).run();
+ });
}
}
--- a/test/jdk/tools/jpackage/windows/WinPerUserInstallTest.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/windows/WinPerUserInstallTest.java Tue Sep 24 13:41:16 2019 -0400
@@ -21,6 +21,7 @@
* questions.
*/
+import jdk.jpackage.test.Test;
import jdk.jpackage.test.PackageTest;
import jdk.jpackage.test.PackageType;
@@ -39,18 +40,20 @@
* @library ../helpers
* @requires (os.family == "windows")
* @modules jdk.jpackage/jdk.jpackage.internal
- * @run main/othervm -Xmx512m WinPerUserInstallTest
+ * @run main/othervm/timeout=360 -Xmx512m WinPerUserInstallTest
*/
public class WinPerUserInstallTest {
public static void main(String[] args) {
- new PackageTest()
- .forTypes(PackageType.WINDOWS)
- .configureHelloApp()
- .addInitializer(cmd -> cmd.addArguments(
- "--win-menu",
- "--win-menu-group", "WinPerUserInstallTest_MenuGroup",
- "--win-per-user-install"))
- .run();
+ Test.run(args, () -> {
+ new PackageTest()
+ .forTypes(PackageType.WINDOWS)
+ .configureHelloApp()
+ .addInitializer(cmd -> cmd.addArguments(
+ "--win-menu",
+ "--win-menu-group", "WinPerUserInstallTest_MenuGroup",
+ "--win-per-user-install"))
+ .run();
+ });
}
}
--- a/test/jdk/tools/jpackage/windows/WinShortcutTest.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/windows/WinShortcutTest.java Tue Sep 24 13:41:16 2019 -0400
@@ -21,6 +21,7 @@
* questions.
*/
+import jdk.jpackage.test.Test;
import jdk.jpackage.test.PackageTest;
import jdk.jpackage.test.PackageType;
@@ -38,15 +39,17 @@
* @library ../helpers
* @requires (os.family == "windows")
* @modules jdk.jpackage/jdk.jpackage.internal
- * @run main/othervm -Xmx512m WinShortcutTest
+ * @run main/othervm/timeout=360 -Xmx512m WinShortcutTest
*/
public class WinShortcutTest {
public static void main(String[] args) {
- new PackageTest()
- .forTypes(PackageType.WINDOWS)
- .configureHelloApp()
- .addInitializer(cmd -> cmd.addArgument("--win-shortcut"))
- .run();
+ Test.run(args, () -> {
+ new PackageTest()
+ .forTypes(PackageType.WINDOWS)
+ .configureHelloApp()
+ .addInitializer(cmd -> cmd.addArgument("--win-shortcut"))
+ .run();
+ });
}
}
--- a/test/jdk/tools/jpackage/windows/WinUpgradeUUIDTest.java Mon Sep 16 19:24:32 2019 -0400
+++ b/test/jdk/tools/jpackage/windows/WinUpgradeUUIDTest.java Tue Sep 24 13:41:16 2019 -0400
@@ -21,6 +21,7 @@
* questions.
*/
+import jdk.jpackage.test.Test;
import jdk.jpackage.test.PackageTest;
import jdk.jpackage.test.PackageType;
@@ -41,29 +42,31 @@
* @library ../helpers
* @requires (os.family == "windows")
* @modules jdk.jpackage/jdk.jpackage.internal
- * @run main/othervm -Xmx512m WinUpgradeUUIDTest
+ * @run main/othervm/timeout=360 -Xmx512m WinUpgradeUUIDTest
*/
public class WinUpgradeUUIDTest {
public static void main(String[] args) {
- PackageTest test = init();
- if (test.getAction() != PackageTest.Action.VERIFY_INSTALLED) {
- test.run();
- }
+ Test.run(args, () -> {
+ PackageTest test = init();
+ if (test.getAction() != PackageTest.Action.VERIFY_INSTALL) {
+ test.run();
+ }
- test = init();
- test.addInitializer(cmd -> {
- cmd.setArgumentValue("--app-version", "2.0");
- cmd.setArgumentValue("--arguments", "bar");
+ test = init();
+ test.addInitializer(cmd -> {
+ cmd.setArgumentValue("--app-version", "2.0");
+ cmd.setArgumentValue("--arguments", "bar");
+ });
+ test.run();
});
- test.run();
}
private static PackageTest init() {
return new PackageTest()
- .forTypes(PackageType.WINDOWS)
- .configureHelloApp()
- .addInitializer(cmd -> cmd.addArguments("--win-upgrade-uuid",
- "F0B18E75-52AD-41A2-BC86-6BE4FCD50BEB"));
+ .forTypes(PackageType.WINDOWS)
+ .configureHelloApp()
+ .addInitializer(cmd -> cmd.addArguments("--win-upgrade-uuid",
+ "F0B18E75-52AD-41A2-BC86-6BE4FCD50BEB"));
}
}