--- old/modules/jdk.packager/src/main/java/com/oracle/tools/packager/IOUtils.java 2018-01-19 17:51:37.000000000 -0800 +++ new/modules/jdk.packager/src/main/java/com/oracle/tools/packager/IOUtils.java 2018-01-19 17:51:36.000000000 -0800 @@ -219,7 +219,7 @@ } @SuppressWarnings("unchecked") - public static int execute(Object ... args) throws IOException, InterruptedException { + private static Process startProcess(Object... args) throws IOException { final ArrayList argsList = new ArrayList<>(); for (Object a : args) { if (a instanceof List) { @@ -228,7 +228,30 @@ argsList.add((String)a); } } - final Process p = Runtime.getRuntime().exec(argsList.toArray(new String[argsList.size()])); + + return Runtime.getRuntime().exec(argsList.toArray(new String[argsList.size()])); + } + + private static void logErrorStream(Process p) { + final BufferedReader err = new BufferedReader(new InputStreamReader(p.getErrorStream())); + Thread t = new Thread(() -> { + try { + String line; + while ((line = err.readLine()) != null) { + Log.error(line); + } + } catch (IOException ioe) { + Log.verbose(ioe); + } + }); + t.setDaemon(true); + t.start(); + } + + @SuppressWarnings("unchecked") + public static int execute(Object ... args) throws IOException, InterruptedException { + final Process p = startProcess(args); + final BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream())); Thread t = new Thread(() -> { try { @@ -242,20 +265,38 @@ }); t.setDaemon(true); t.start(); - final BufferedReader err = new BufferedReader(new InputStreamReader(p.getErrorStream())); - t = new Thread(() -> { + + logErrorStream(p); + return p.waitFor(); + } + + public static int getProcessOutput(List result, Object... args) + throws IOException, InterruptedException { + final Process p = startProcess(args); + + List list = new ArrayList<>(); + final BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream())); + Thread t = new Thread(() -> { try { String line; - while ((line = err.readLine()) != null) { - Log.error(line); + while ((line = in.readLine()) != null) { + list.add(line); } } catch (IOException ioe) { - Log.verbose(ioe); + com.oracle.tools.packager.Log.verbose(ioe); } }); t.setDaemon(true); t.start(); - return p.waitFor(); + + logErrorStream(p); + + int ret = p.waitFor(); + + result.clear(); + result.addAll(list); + + return ret; } //no good test if we are running pre-JRE7 --- old/modules/jdk.packager/src/main/java/com/oracle/tools/packager/Platform.java 2018-01-19 17:51:37.000000000 -0800 +++ new/modules/jdk.packager/src/main/java/com/oracle/tools/packager/Platform.java 2018-01-19 17:51:37.000000000 -0800 @@ -76,7 +76,7 @@ majorVersion = Integer.parseInt(parts[0]); if (parts.length > 1) { - minorVersion = Integer.parseInt(parts[0]); + minorVersion = Integer.parseInt(parts[1]); } else { minorVersion = -1; --- old/modules/jdk.packager/src/main/java/com/oracle/tools/packager/mac/MacAppStoreBundler.java 2018-01-19 17:51:38.000000000 -0800 +++ new/modules/jdk.packager/src/main/java/com/oracle/tools/packager/mac/MacAppStoreBundler.java 2018-01-19 17:51:38.000000000 -0800 @@ -144,6 +144,11 @@ try { appImageDir.mkdirs(); + try { + MacAppImageBuilder.addNewKeychain(p); + } catch (InterruptedException e) { + Log.error(e.getMessage()); + } // first, make sure we don't use the local signing key p.put(DEVELOPER_ID_APP_SIGNING_KEY.getID(), null); File appLocation = prepareAppBundle(p); @@ -156,6 +161,8 @@ String inheritEntitlements = getConfig_Inherit_Entitlements(p).toString(); MacAppImageBuilder.signAppBundle(p, appLocation.toPath(), signingIdentity, identifierPrefix, entitlementsFile, inheritEntitlements); + MacAppImageBuilder.restoreKeychainList(p); + ProcessBuilder pb; // create the final pkg file --- old/modules/jdk.packager/src/main/java/com/oracle/tools/packager/mac/MacPkgBundler.java 2018-01-19 17:51:39.000000000 -0800 +++ new/modules/jdk.packager/src/main/java/com/oracle/tools/packager/mac/MacPkgBundler.java 2018-01-19 17:51:38.000000000 -0800 @@ -30,6 +30,7 @@ import com.oracle.tools.packager.Log; import com.oracle.tools.packager.ConfigException; import com.oracle.tools.packager.IOUtils; +import com.oracle.tools.packager.Platform; import com.oracle.tools.packager.RelativeFileSet; import com.oracle.tools.packager.UnsupportedPlatformException; @@ -396,6 +397,11 @@ private File createPKG(Map params, File outdir, File appLocation) { //generic find attempt try { + if (Platform.getMajorVersion() > 10 || + (Platform.getMajorVersion() == 10 && Platform.getMinorVersion() >= 12)) { + // we need this for OS X 10.12+ + Log.info(I18N.getString("message.signing.pkg")); + } String daemonLocation = DAEMON_IMAGE_BUILD_ROOT.fetchFrom(params) + "/" + APP_NAME.fetchFrom(params) + ".daemon"; File appPKG = getPackages_AppPackage(params); --- old/modules/jdk.packager/src/main/java/jdk/packager/internal/legacy/builders/mac/MacAppImageBuilder.java 2018-01-19 17:51:39.000000000 -0800 +++ new/modules/jdk.packager/src/main/java/jdk/packager/internal/legacy/builders/mac/MacAppImageBuilder.java 2018-01-19 17:51:39.000000000 -0800 @@ -28,6 +28,7 @@ import com.oracle.tools.packager.BundlerParamInfo; import com.oracle.tools.packager.IOUtils; import com.oracle.tools.packager.Log; +import com.oracle.tools.packager.Platform; import com.oracle.tools.packager.RelativeFileSet; import com.oracle.tools.packager.StandardBundlerParam; import com.oracle.tools.packager.mac.MacResources; @@ -92,6 +93,8 @@ private final Map params; + private static List keyChains; + private static Map getMacCategories() { Map map = new HashMap<>(); map.put("Business", "public.app-category.business"); @@ -415,10 +418,16 @@ // maybe sign if (Optional.ofNullable(SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.TRUE)) { + try { + addNewKeychain(params); + } catch (InterruptedException e) { + Log.error(e.getMessage()); + } String signingIdentity = DEVELOPER_ID_APP_SIGNING_KEY.fetchFrom(params); if (signingIdentity != null) { signAppBundle(params, root, signingIdentity, BUNDLE_ID_SIGNING_PREFIX.fetchFrom(params), null, null); } + restoreKeychainList(params); } } @@ -719,6 +728,79 @@ } } + public static void addNewKeychain(Map params) + throws IOException, InterruptedException { + if (Platform.getMajorVersion() < 10 || + (Platform.getMajorVersion() == 10 && Platform.getMinorVersion() < 12)) { + // we need this for OS X 10.12+ + return; + } + + String keyChain = SIGNING_KEYCHAIN.fetchFrom(params); + if (keyChain == null || keyChain.isEmpty()) { + return; + } + + // get current keychain list + String keyChainPath = new File (keyChain).getAbsolutePath().toString(); + List keychainList = new ArrayList<>(); + int ret = IOUtils.getProcessOutput(keychainList, "security", "list-keychains"); + if (ret != 0) { + Log.error(I18N.getString("message.keychain.error")); + return; + } + + boolean contains = keychainList.stream().anyMatch( + str -> str.trim().equals("\""+keyChainPath.trim()+"\"")); + if (contains) { + // keychain is already added in the search list + return; + } + + keyChains = new ArrayList<>(); + // remove " + keychainList.forEach((String s) -> { + String path = s.trim(); + if (path.startsWith("\"") && path.endsWith("\"")) { + path = path.substring(1, path.length()-1); + } + keyChains.add(path); + }); + + List args = new ArrayList<>(); + args.add("security"); + args.add("list-keychains"); + args.add("-s"); + + args.addAll(keyChains); + args.add(keyChain); + + ProcessBuilder pb = new ProcessBuilder(args); + IOUtils.exec(pb, VERBOSE.fetchFrom(params)); + } + + public static void restoreKeychainList(Map params) throws IOException{ + if (Platform.getMajorVersion() < 10 || + (Platform.getMajorVersion() == 10 && Platform.getMinorVersion() < 12)) { + // we need this for OS X 10.12+ + return; + } + + if (keyChains == null || keyChains.isEmpty()) { + return; + } + + List args = new ArrayList<>(); + args.add("security"); + args.add("list-keychains"); + args.add("-s"); + + args.addAll(keyChains); + + ProcessBuilder pb = new ProcessBuilder(args); + IOUtils.exec(pb, VERBOSE.fetchFrom(params)); + } + public static void signAppBundle(Map params, Path appLocation, String signingIdentity, String identifierPrefix, String entitlementsFile, String inheritedEntitlements) throws IOException { AtomicReference toThrow = new AtomicReference<>(); String appExecutable = "/Contents/MacOS/" + APP_NAME.fetchFrom(params); --- old/modules/jdk.packager/src/main/resources/com/oracle/tools/packager/mac/MacPkgBundler.properties 2018-01-19 17:51:40.000000000 -0800 +++ new/modules/jdk.packager/src/main/resources/com/oracle/tools/packager/mac/MacPkgBundler.properties 2018-01-19 17:51:40.000000000 -0800 @@ -33,3 +33,4 @@ message.preparing-distribution-dist=Preparing distribution.dist\: {0} message.config-save-location=Config files are saved to {0}. Use them to customize package. message.intermediate-image-location=[DEBUG] Intermediate application bundle image\: {0} +message.signing.pkg=Warning: For signing PKG, you might need to set "Always Trust" for your certificate using "Keychain Access" tool. --- old/modules/jdk.packager/src/main/resources/jdk/packager/internal/legacy/builders/mac/MacAppImageBuilder.properties 2018-01-19 17:51:41.000000000 -0800 +++ new/modules/jdk.packager/src/main/resources/jdk/packager/internal/legacy/builders/mac/MacAppImageBuilder.properties 2018-01-19 17:51:40.000000000 -0800 @@ -70,4 +70,5 @@ message.using-custom-resource-from-file=Using custom package resource {0} (loaded from file {1}) message.using-custom-resource-from-classpath=Using custom package resource {0} (loaded from {1}) message.using-default-resource-from-classpath=Using default package resource {0} (add {1} to the class path to customize) -message.ignoring.symlink=Warning: codesign is skipping the symlink {0} \ No newline at end of file +message.ignoring.symlink=Warning: codesign is skipping the symlink {0} +message.keychain.error=Error: unable to get keychain list. \ No newline at end of file