--- old/modules/fxpackager/src/main/java/com/oracle/tools/packager/mac/MacAppBundler.java 2015-03-30 15:11:06.000000000 -0600 +++ new/modules/fxpackager/src/main/java/com/oracle/tools/packager/mac/MacAppBundler.java 2015-03-30 15:11:05.000000000 -0600 @@ -24,7 +24,7 @@ */ package com.oracle.tools.packager.mac; -import com.oracle.tools.packager.AbstractBundler; +import com.oracle.tools.packager.AbstractImageBundler; import com.oracle.tools.packager.BundlerParamInfo; import com.oracle.tools.packager.EnumeratedBundlerParam; import com.oracle.tools.packager.JreUtils; @@ -49,7 +49,7 @@ import static com.oracle.tools.packager.mac.MacBaseInstallerBundler.SIGNING_KEY_USER; import static com.oracle.tools.packager.mac.MacBaseInstallerBundler.getPredefinedImage; -public class MacAppBundler extends AbstractBundler { +public class MacAppBundler extends AbstractImageBundler { private static final ResourceBundle I18N = ResourceBundle.getBundle(MacAppBundler.class.getName()); @@ -61,7 +61,8 @@ private final static String LIBRARY_NAME = "libpackager.dylib"; private static final String TEMPLATE_BUNDLE_ICON = "GenericApp.icns"; private static final String OS_TYPE_CODE = "APPL"; - private static final String TEMPLATE_INFO_PLIST = "Info.plist.template"; + private static final String TEMPLATE_INFO_PLIST_LEGACY = "Info.plist.template"; + private static final String TEMPLATE_INFO_PLIST_LITE = "Info-lite.plist.template"; private static Map getMacCategories() { Map map = new HashMap<>(); @@ -110,6 +111,15 @@ return map; } + public static final BundlerParamInfo MAC_CONFIGURE_LAUNCHER_IN_PLIST = + new StandardBundlerParam<>( + I18N.getString("param.configure-launcher-in-plist"), + I18N.getString("param.configure-launcher-in-plist.description"), + "mac.configure-launcher-in-plist", + Boolean.class, + params -> Boolean.FALSE, + (s, p) -> Boolean.valueOf(s)); + public static final EnumeratedBundlerParam MAC_CATEGORY = new EnumeratedBundlerParam<>( I18N.getString("param.category-name"), @@ -177,7 +187,7 @@ URL.class, params -> MacResources.class.getResource(EXECUTABLE_NAME), (s, p) -> { - try { + try { return new URL(s); } catch (MalformedURLException e) { Log.info(e.toString()); @@ -273,6 +283,17 @@ baseResourceLoader = MacResources.class; } + @Override + protected String getCacheLocation(Map params) { + Boolean systemWide = SYSTEM_WIDE.fetchFrom(params); + if (systemWide == null || systemWide) { + return "/Library/Application Support/" + IDENTIFIER.fetchFrom(params) + "/cache/"; + } else { + return "$CACHEDIR/"; + } + } + + public static boolean validCFBundleVersion(String v) { // CFBundleVersion (String - iOS, OS X) specifies the build version // number of the bundle, which identifies an iteration (released or @@ -413,6 +434,8 @@ public File doBundle(Map p, File outputDirectory, boolean dependentTask) { File rootDirectory = null; + Map originalParams = new HashMap<>(p); + if (!outputDirectory.isDirectory() && !outputDirectory.mkdirs()) { throw new RuntimeException(MessageFormat.format(I18N.getString("error.cannot-create-output-dir"), outputDirectory.getAbsolutePath())); } @@ -472,6 +495,15 @@ MacResources.class.getResource(LIBRARY_NAME), new File(macOSDirectory, LIBRARY_NAME)); + // maybe generate launcher config + if (!MAC_CONFIGURE_LAUNCHER_IN_PLIST.fetchFrom(p)) { + if (LAUNCHER_CFG_FORMAT.fetchFrom(p).equals(CFG_FORMAT_PROPERTIES)) { + writeCfgFile(p, rootDirectory); + } else { + writeCfgFile(p, new File(rootDirectory, getLauncherCfgName(p)), "$APPDIR/PlugIns/Java.runtime"); + } + } + executableFile.setExecutable(true, false); // Copy runtime to PlugIns folder @@ -480,7 +512,7 @@ // Copy class path entries to Java folder copyClassPathEntries(javaDirectory, p); -//TODO: Need to support adding native libraries. + //TODO: Need to support adding native libraries. // Copy library path entries to MacOS folder //copyLibraryPathEntries(macOSDirectory); @@ -498,10 +530,17 @@ } } - // Generate Info.plist IOUtils.copyFile(getConfig_InfoPlist(p), new File(contentsDirectory, "Info.plist")); + + // create the secondary launchers, if any + List> entryPoints = StandardBundlerParam.SECONDARY_LAUNCHERS.fetchFrom(p); + for (Map entryPoint : entryPoints) { + Map tmp = new HashMap<>(originalParams); + tmp.putAll(entryPoint); + createLauncherForEntryPoint(tmp, rootDirectory); + } // maybe sign if (Optional.ofNullable(SIGN_BUNDLE.fetchFrom(p)).orElse(Boolean.TRUE)) { @@ -528,12 +567,8 @@ public void cleanupConfigFiles(Map params) { //Since building the app can be bypassed, make sure configRoot was set if (CONFIG_ROOT.fetchFrom(params) != null) { - if (getConfig_Icon(params) != null) { - getConfig_Icon(params).delete(); - } - if (getConfig_InfoPlist(params) != null) { - getConfig_InfoPlist(params).delete(); - } + getConfig_Icon(params).delete(); + getConfig_InfoPlist(params).delete(); } } @@ -835,8 +870,11 @@ Writer w = new BufferedWriter(new FileWriter(file)); w.write(preprocessTextResource( MAC_BUNDLER_PREFIX + getConfig_InfoPlist(params).getName(), - I18N.getString("resource.bundle-config-file"), TEMPLATE_INFO_PLIST, data, - VERBOSE.fetchFrom(params), + I18N.getString("resource.bundle-config-file"), + MAC_CONFIGURE_LAUNCHER_IN_PLIST.fetchFrom(params) + ? TEMPLATE_INFO_PLIST_LEGACY + : TEMPLATE_INFO_PLIST_LITE, + data, VERBOSE.fetchFrom(params), DROP_IN_RESOURCES_ROOT.fetchFrom(params))); w.close(); @@ -1049,4 +1087,90 @@ public File execute(Map params, File outputParentDir) { return doBundle(params, outputParentDir, false); } + + private void createLauncherForEntryPoint(Map p, File rootDirectory) throws IOException { + prepareConfigFiles(p); + + if (LAUNCHER_CFG_FORMAT.fetchFrom(p).equals(CFG_FORMAT_PROPERTIES)) { + writeCfgFile(p, rootDirectory); + } else { + writeCfgFile(p, new File(rootDirectory, getLauncherCfgName(p)), "$APPDIR/PlugIns/Java.runtime"); + } + + // Copy executable root folder + File executableFile = new File(rootDirectory, "Contents/MacOS/" + getLauncherName(p)); + IOUtils.copyFromURL( + RAW_EXECUTABLE_URL.fetchFrom(p), + executableFile); + executableFile.setExecutable(true, false); + + } + + public static String getLauncherCfgName(Map p) { + return "Contents/Java/" + APP_NAME.fetchFrom(p) +".cfg"; + } + + private void writeCfgFile(Map params, File rootDir) throws FileNotFoundException { + File pkgInfoFile = new File(rootDir, getLauncherCfgName(params)); + + pkgInfoFile.delete(); + + PrintStream out = new PrintStream(pkgInfoFile); + if (MAC_RUNTIME.fetchFrom(params) == null) { + out.println("app.runtime="); + } else { + out.println("app.runtime=$APPDIR/PlugIns/Java.runtime"); + } + out.println("app.mainjar=" + MAIN_JAR.fetchFrom(params).getIncludedFiles().iterator().next()); + out.println("app.version=" + VERSION.fetchFrom(params)); + //for future AU support (to be able to find app in the registry) + out.println("app.id=" + IDENTIFIER.fetchFrom(params)); + out.println("app.preferences.id=" + PREFERENCES_ID.fetchFrom(params)); + out.println("app.identifier=" + IDENTIFIER.fetchFrom(params)); + + out.println("app.mainclass=" + + MAIN_CLASS.fetchFrom(params).replaceAll("\\.", "/")); + out.println("app.classpath=" + CLASSPATH.fetchFrom(params)); + + List jvmargs = JVM_OPTIONS.fetchFrom(params); + int idx = 1; + for (String a : jvmargs) { + out.println("jvmarg."+idx+"="+a); + idx++; + } + Map jvmProps = JVM_PROPERTIES.fetchFrom(params); + for (Map.Entry entry : jvmProps.entrySet()) { + out.println("jvmarg."+idx+"=-D"+entry.getKey()+"="+entry.getValue()); + idx++; + } + + String preloader = PRELOADER_CLASS.fetchFrom(params); + if (preloader != null) { + out.println("jvmarg."+idx+"=-Djavafx.preloader="+preloader); + } + + Map overridableJVMOptions = USER_JVM_OPTIONS.fetchFrom(params); + idx = 1; + for (Map.Entry arg: overridableJVMOptions.entrySet()) { + if (arg.getKey() == null || arg.getValue() == null) { + Log.info(I18N.getString("message.jvm-user-arg-is-null")); + } + else { + out.println("jvmuserarg."+idx+".name="+arg.getKey()); + out.println("jvmuserarg."+idx+".value="+arg.getValue()); + } + idx++; + } + + // add command line args + List args = ARGUMENTS.fetchFrom(params); + idx = 1; + for (String a : args) { + out.println("arg."+idx+"="+a); + idx++; + } + + out.close(); + } + }