< prev index next >

src/jdk.incubator.jpackage/macosx/classes/jdk/incubator/jpackage/internal/MacAppImageBuilder.java

Print this page




  68     private static final String LIBRARY_NAME = "libapplauncher.dylib";
  69     private static final String TEMPLATE_BUNDLE_ICON = "java.icns";
  70     private static final String OS_TYPE_CODE = "APPL";
  71     private static final String TEMPLATE_INFO_PLIST_LITE =
  72             "Info-lite.plist.template";
  73     private static final String TEMPLATE_RUNTIME_INFO_PLIST =
  74             "Runtime-Info.plist.template";
  75 
  76     private final Path root;
  77     private final Path contentsDir;
  78     private final Path appDir;
  79     private final Path javaModsDir;
  80     private final Path resourcesDir;
  81     private final Path macOSDir;
  82     private final Path runtimeDir;
  83     private final Path runtimeRoot;
  84     private final Path mdir;
  85 
  86     private static List<String> keyChains;
  87 





  88     public static final BundlerParamInfo<Boolean>
  89             MAC_CONFIGURE_LAUNCHER_IN_PLIST = new StandardBundlerParam<>(
  90                     "mac.configure-launcher-in-plist",
  91                     Boolean.class,
  92                     params -> Boolean.FALSE,
  93                     (s, p) -> Boolean.valueOf(s));
  94 
  95     public static final BundlerParamInfo<String> MAC_CF_BUNDLE_NAME =
  96             new StandardBundlerParam<>(
  97                     Arguments.CLIOptions.MAC_BUNDLE_NAME.getId(),
  98                     String.class,
  99                     params -> null,
 100                     (s, p) -> s);
 101 
 102     public static final BundlerParamInfo<String> MAC_CF_BUNDLE_IDENTIFIER =
 103             new StandardBundlerParam<>(
 104                     Arguments.CLIOptions.MAC_BUNDLE_IDENTIFIER.getId(),
 105                     String.class,
 106                     params -> {
 107                         // Get identifier from app image if user provided


 145                 File f = ICON.fetchFrom(params);
 146                 if (f != null && !f.getName().toLowerCase().endsWith(".icns")) {
 147                     Log.error(MessageFormat.format(
 148                             I18N.getString("message.icon-not-icns"), f));
 149                     return null;
 150                 }
 151                 return f;
 152             },
 153             (s, p) -> new File(s));
 154 
 155     public static final StandardBundlerParam<Boolean> SIGN_BUNDLE  =
 156             new StandardBundlerParam<>(
 157             Arguments.CLIOptions.MAC_SIGN.getId(),
 158             Boolean.class,
 159             params -> false,
 160             // valueOf(null) is false, we actually do want null in some cases
 161             (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ?
 162                     null : Boolean.valueOf(s)
 163         );
 164 
















 165     public MacAppImageBuilder(Map<String, Object> params, Path imageOutDir)
 166             throws IOException {
 167         super(params, imageOutDir.resolve(APP_NAME.fetchFrom(params)
 168                 + ".app/Contents/runtime/Contents/Home"));
 169 
 170         Objects.requireNonNull(imageOutDir);
 171 
 172         this.root = imageOutDir.resolve(APP_NAME.fetchFrom(params) + ".app");
 173         this.contentsDir = root.resolve("Contents");
 174         this.appDir = contentsDir.resolve("app");
 175         this.javaModsDir = appDir.resolve("mods");
 176         this.resourcesDir = contentsDir.resolve("Resources");
 177         this.macOSDir = contentsDir.resolve("MacOS");
 178         this.runtimeDir = contentsDir.resolve("runtime");
 179         this.runtimeRoot = runtimeDir.resolve("Contents/Home");
 180         this.mdir = runtimeRoot.resolve("lib");
 181         Files.createDirectories(appDir);
 182         Files.createDirectories(resourcesDir);
 183         Files.createDirectories(macOSDir);
 184         Files.createDirectories(runtimeDir);


 351         // JDK 9, 10, and 11 have extra '/jli/' subdir
 352         Path jli = runtimeRoot.resolve("lib/libjli.dylib");
 353         if (!Files.exists(jli)) {
 354             jli = runtimeRoot.resolve("lib/jli/libjli.dylib");
 355         }
 356 
 357         Files.copy(jli, runtimeMacOSDir.resolve("libjli.dylib"));
 358     }
 359 
 360     private void sign(Map<String, ? super Object> params) throws IOException {
 361         if (Optional.ofNullable(
 362                 SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.TRUE)) {
 363             try {
 364                 addNewKeychain(params);
 365             } catch (InterruptedException e) {
 366                 Log.error(e.getMessage());
 367             }
 368             String signingIdentity =
 369                     DEVELOPER_ID_APP_SIGNING_KEY.fetchFrom(params);
 370             if (signingIdentity != null) {

 371                 signAppBundle(params, root, signingIdentity,
 372                         BUNDLE_ID_SIGNING_PREFIX.fetchFrom(params), null, null);


 373             }
 374             restoreKeychainList(params);
 375         }
 376     }
 377 


























 378     private String getLauncherName(Map<String, ? super Object> params) {
 379         if (APP_NAME.fetchFrom(params) != null) {
 380             return APP_NAME.fetchFrom(params);
 381         } else {
 382             return MAIN_CLASS.fetchFrom(params);
 383         }
 384     }
 385 
 386     public static String getLauncherCfgName(
 387             Map<String, ? super Object> params) {
 388         return "Contents/app/" + APP_NAME.fetchFrom(params) + ".cfg";
 389     }
 390 
 391     private void copyClassPathEntries(Path javaDirectory,
 392             Map<String, ? super Object> params) throws IOException {
 393         List<RelativeFileSet> resourcesList =
 394                 APP_RESOURCES_LIST.fetchFrom(params);
 395         if (resourcesList == null) {
 396             throw new RuntimeException(
 397                     I18N.getString("message.null-classpath"));


 745         String keyChain = SIGNING_KEYCHAIN.fetchFrom(params);
 746 
 747         // sign all dylibs and jars
 748         try (Stream<Path> stream = Files.walk(appLocation)) {
 749             stream.peek(path -> { // fix permissions
 750                 try {
 751                     Set<PosixFilePermission> pfp =
 752                             Files.getPosixFilePermissions(path);
 753                     if (!pfp.contains(PosixFilePermission.OWNER_WRITE)) {
 754                         pfp = EnumSet.copyOf(pfp);
 755                         pfp.add(PosixFilePermission.OWNER_WRITE);
 756                         Files.setPosixFilePermissions(path, pfp);
 757                     }
 758                 } catch (IOException e) {
 759                     Log.verbose(e);
 760                 }
 761             }).filter(p -> Files.isRegularFile(p)
 762                       && !(p.toString().contains("/Contents/MacOS/libjli.dylib")
 763                       || p.toString().endsWith(appExecutable)
 764                       || p.toString().contains("/Contents/runtime")
 765                       || p.toString().contains("/Contents/Frameworks"))).forEach(p -> {

 766                 //noinspection ThrowableResultOfMethodCallIgnored
 767                 if (toThrow.get() != null) return;
 768 
 769                 // If p is a symlink then skip the signing process.
 770                 if (Files.isSymbolicLink(p)) {
 771                     if (VERBOSE.fetchFrom(params)) {
 772                         Log.verbose(MessageFormat.format(I18N.getString(
 773                                 "message.ignoring.symlink"), p.toString()));
 774                     }
 775                 } else {
 776                     if (p.toString().endsWith(LIBRARY_NAME)) {
 777                         if (isFileSigned(p)) {
 778                             return;
 779                         }
 780                     }
 781 
 782                     List<String> args = new ArrayList<>();
 783                     args.addAll(Arrays.asList("codesign",
 784                             "-s", signingIdentity, // sign with this key




 785                             "--prefix", identifierPrefix,
 786                             // use the identifier as a prefix
 787                             "-vvvv"));
 788                     if (entitlementsFile != null &&
 789                             (p.toString().endsWith(".jar")
 790                             || p.toString().endsWith(".dylib"))) {
 791                         args.add("--entitlements");
 792                         args.add(entitlementsFile); // entitlements
 793                     } else if (inheritedEntitlements != null &&
 794                             Files.isExecutable(p)) {
 795                         args.add("--entitlements");
 796                         args.add(inheritedEntitlements);
 797                         // inherited entitlements for executable processes
 798                     }
 799                     if (keyChain != null && !keyChain.isEmpty()) {
 800                         args.add("--keychain");
 801                         args.add(keyChain);
 802                     }
 803                     args.add(p.toString());
 804 
 805                     try {
 806                         Set<PosixFilePermission> oldPermissions =


 819             });
 820         }
 821         IOException ioe = toThrow.get();
 822         if (ioe != null) {
 823             throw ioe;
 824         }
 825 
 826         // sign all runtime and frameworks
 827         Consumer<? super Path> signIdentifiedByPList = path -> {
 828             //noinspection ThrowableResultOfMethodCallIgnored
 829             if (toThrow.get() != null) return;
 830 
 831             try {
 832                 List<String> args = new ArrayList<>();
 833                 args.addAll(Arrays.asList("codesign",
 834                         "-f",
 835                         "-s", signingIdentity, // sign with this key
 836                         "--prefix", identifierPrefix,
 837                         // use the identifier as a prefix
 838                         "-vvvv"));













 839                 if (keyChain != null && !keyChain.isEmpty()) {
 840                     args.add("--keychain");
 841                     args.add(keyChain);
 842                 }
 843                 args.add(path.toString());
 844                 ProcessBuilder pb = new ProcessBuilder(args);
 845                 IOUtils.exec(pb);
 846 

 847                 args = new ArrayList<>();
 848                 args.addAll(Arrays.asList("codesign",
 849                         "-s", signingIdentity, // sign with this key




 850                         "--prefix", identifierPrefix,
 851                         // use the identifier as a prefix
 852                         "-vvvv"));
 853                 if (keyChain != null && !keyChain.isEmpty()) {
 854                     args.add("--keychain");
 855                     args.add(keyChain);
 856                 }
 857                 args.add(path.toString()
 858                         + "/Contents/_CodeSignature/CodeResources");
 859                 pb = new ProcessBuilder(args);
 860                 IOUtils.exec(pb);
 861             } catch (IOException e) {
 862                 toThrow.set(e);
 863             }
 864         };
 865 
 866         Path javaPath = appLocation.resolve("Contents/runtime");
 867         if (Files.isDirectory(javaPath)) {
 868             signIdentifiedByPList.accept(javaPath);
 869 
 870             ioe = toThrow.get();
 871             if (ioe != null) {
 872                 throw ioe;
 873             }
 874         }
 875         Path frameworkPath = appLocation.resolve("Contents/Frameworks");
 876         if (Files.isDirectory(frameworkPath)) {
 877             Files.list(frameworkPath)
 878                     .forEach(signIdentifiedByPList);
 879 
 880             ioe = toThrow.get();
 881             if (ioe != null) {
 882                 throw ioe;
 883             }
 884         }
 885 
 886         // sign the app itself
 887         List<String> args = new ArrayList<>();
 888         args.addAll(Arrays.asList("codesign",
 889                 "-s", signingIdentity, // sign with this key
 890                 "-vvvv")); // super verbose output




 891         if (entitlementsFile != null) {
 892             args.add("--entitlements");
 893             args.add(entitlementsFile); // entitlements
 894         }
 895         if (keyChain != null && !keyChain.isEmpty()) {
 896             args.add("--keychain");
 897             args.add(keyChain);
 898         }
 899         args.add(appLocation.toString());
 900 
 901         ProcessBuilder pb =
 902                 new ProcessBuilder(args.toArray(new String[args.size()]));
 903         IOUtils.exec(pb);
 904     }
 905 
 906     private static boolean isFileSigned(Path file) {
 907         ProcessBuilder pb =
 908                 new ProcessBuilder("codesign", "--verify", file.toString());
 909 
 910         try {




  68     private static final String LIBRARY_NAME = "libapplauncher.dylib";
  69     private static final String TEMPLATE_BUNDLE_ICON = "java.icns";
  70     private static final String OS_TYPE_CODE = "APPL";
  71     private static final String TEMPLATE_INFO_PLIST_LITE =
  72             "Info-lite.plist.template";
  73     private static final String TEMPLATE_RUNTIME_INFO_PLIST =
  74             "Runtime-Info.plist.template";
  75 
  76     private final Path root;
  77     private final Path contentsDir;
  78     private final Path appDir;
  79     private final Path javaModsDir;
  80     private final Path resourcesDir;
  81     private final Path macOSDir;
  82     private final Path runtimeDir;
  83     private final Path runtimeRoot;
  84     private final Path mdir;
  85 
  86     private static List<String> keyChains;
  87 
  88     private final static String DEFAULT_ENTITLEMENTS =
  89             "Mac.entitlements";
  90     private final static String DEFAULT_INHERIT_ENTITLEMENTS =
  91             "Mac_Inherit.entitlements";
  92 
  93     public static final BundlerParamInfo<Boolean>
  94             MAC_CONFIGURE_LAUNCHER_IN_PLIST = new StandardBundlerParam<>(
  95                     "mac.configure-launcher-in-plist",
  96                     Boolean.class,
  97                     params -> Boolean.FALSE,
  98                     (s, p) -> Boolean.valueOf(s));
  99 
 100     public static final BundlerParamInfo<String> MAC_CF_BUNDLE_NAME =
 101             new StandardBundlerParam<>(
 102                     Arguments.CLIOptions.MAC_BUNDLE_NAME.getId(),
 103                     String.class,
 104                     params -> null,
 105                     (s, p) -> s);
 106 
 107     public static final BundlerParamInfo<String> MAC_CF_BUNDLE_IDENTIFIER =
 108             new StandardBundlerParam<>(
 109                     Arguments.CLIOptions.MAC_BUNDLE_IDENTIFIER.getId(),
 110                     String.class,
 111                     params -> {
 112                         // Get identifier from app image if user provided


 150                 File f = ICON.fetchFrom(params);
 151                 if (f != null && !f.getName().toLowerCase().endsWith(".icns")) {
 152                     Log.error(MessageFormat.format(
 153                             I18N.getString("message.icon-not-icns"), f));
 154                     return null;
 155                 }
 156                 return f;
 157             },
 158             (s, p) -> new File(s));
 159 
 160     public static final StandardBundlerParam<Boolean> SIGN_BUNDLE  =
 161             new StandardBundlerParam<>(
 162             Arguments.CLIOptions.MAC_SIGN.getId(),
 163             Boolean.class,
 164             params -> false,
 165             // valueOf(null) is false, we actually do want null in some cases
 166             (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ?
 167                     null : Boolean.valueOf(s)
 168         );
 169 
 170 /*
 171     public static final StandardBundlerParam<File> MAC_ENTITLEMENTS  =
 172             new StandardBundlerParam<>(
 173             Arguments.CLIOptions.MAC_ENTITLEMENTS.getId(),
 174             File.class,
 175             params -> null,
 176             (s, p) -> new File(s));
 177 
 178     public static final StandardBundlerParam<File> MAC_INHERIT_ENTITLEMENTS  =
 179             new StandardBundlerParam<>(
 180             Arguments.CLIOptions.MAC_INHERIT_ENTITLEMENTS.getId(),
 181             File.class,
 182             params -> null,
 183             (s, p) -> new File(s));
 184 */
 185 
 186     public MacAppImageBuilder(Map<String, Object> params, Path imageOutDir)
 187             throws IOException {
 188         super(params, imageOutDir.resolve(APP_NAME.fetchFrom(params)
 189                 + ".app/Contents/runtime/Contents/Home"));
 190 
 191         Objects.requireNonNull(imageOutDir);
 192 
 193         this.root = imageOutDir.resolve(APP_NAME.fetchFrom(params) + ".app");
 194         this.contentsDir = root.resolve("Contents");
 195         this.appDir = contentsDir.resolve("app");
 196         this.javaModsDir = appDir.resolve("mods");
 197         this.resourcesDir = contentsDir.resolve("Resources");
 198         this.macOSDir = contentsDir.resolve("MacOS");
 199         this.runtimeDir = contentsDir.resolve("runtime");
 200         this.runtimeRoot = runtimeDir.resolve("Contents/Home");
 201         this.mdir = runtimeRoot.resolve("lib");
 202         Files.createDirectories(appDir);
 203         Files.createDirectories(resourcesDir);
 204         Files.createDirectories(macOSDir);
 205         Files.createDirectories(runtimeDir);


 372         // JDK 9, 10, and 11 have extra '/jli/' subdir
 373         Path jli = runtimeRoot.resolve("lib/libjli.dylib");
 374         if (!Files.exists(jli)) {
 375             jli = runtimeRoot.resolve("lib/jli/libjli.dylib");
 376         }
 377 
 378         Files.copy(jli, runtimeMacOSDir.resolve("libjli.dylib"));
 379     }
 380 
 381     private void sign(Map<String, ? super Object> params) throws IOException {
 382         if (Optional.ofNullable(
 383                 SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.TRUE)) {
 384             try {
 385                 addNewKeychain(params);
 386             } catch (InterruptedException e) {
 387                 Log.error(e.getMessage());
 388             }
 389             String signingIdentity =
 390                     DEVELOPER_ID_APP_SIGNING_KEY.fetchFrom(params);
 391             if (signingIdentity != null) {
 392                 prepareEntitlements(params);
 393                 signAppBundle(params, root, signingIdentity,
 394                         BUNDLE_ID_SIGNING_PREFIX.fetchFrom(params),
 395                         getConfig_Entitlements(params).toString(),
 396                         getConfig_Inherit_Entitlements(params).toString());
 397             }
 398             restoreKeychainList(params);
 399         }
 400     }
 401 
 402     private File getConfig_Entitlements(Map<String, ? super Object> params) {
 403         return new File(CONFIG_ROOT.fetchFrom(params),
 404                 getLauncherName(params) + ".entitlements");
 405     }
 406 
 407     private File getConfig_Inherit_Entitlements(
 408             Map<String, ? super Object> params) {
 409         return new File(CONFIG_ROOT.fetchFrom(params), 
 410                 getLauncherName(params) + "_Inherit.entitlements");
 411     }
 412 
 413     private void prepareEntitlements(Map<String, ? super Object> params)
 414             throws IOException {
 415         createResource(DEFAULT_ENTITLEMENTS, params)
 416                 .setCategory(I18N.getString("resource.mac-entitlements"))
 417                 // .setExternal(MAC_ENTITLEMENTS.fetchFrom(params))
 418                 .saveToFile(getConfig_Entitlements(params));
 419 
 420         createResource(DEFAULT_INHERIT_ENTITLEMENTS, params)
 421                 .setCategory(I18N.getString(
 422                         "resource.mac-inherit-entitlements"))
 423                 // .setExternal(MAC_INHERIT_ENTITLEMENTS.fetchFrom(params))
 424                 .saveToFile(getConfig_Inherit_Entitlements(params));
 425     }
 426 
 427 
 428     private String getLauncherName(Map<String, ? super Object> params) {
 429         if (APP_NAME.fetchFrom(params) != null) {
 430             return APP_NAME.fetchFrom(params);
 431         } else {
 432             return MAIN_CLASS.fetchFrom(params);
 433         }
 434     }
 435 
 436     public static String getLauncherCfgName(
 437             Map<String, ? super Object> params) {
 438         return "Contents/app/" + APP_NAME.fetchFrom(params) + ".cfg";
 439     }
 440 
 441     private void copyClassPathEntries(Path javaDirectory,
 442             Map<String, ? super Object> params) throws IOException {
 443         List<RelativeFileSet> resourcesList =
 444                 APP_RESOURCES_LIST.fetchFrom(params);
 445         if (resourcesList == null) {
 446             throw new RuntimeException(
 447                     I18N.getString("message.null-classpath"));


 795         String keyChain = SIGNING_KEYCHAIN.fetchFrom(params);
 796 
 797         // sign all dylibs and jars
 798         try (Stream<Path> stream = Files.walk(appLocation)) {
 799             stream.peek(path -> { // fix permissions
 800                 try {
 801                     Set<PosixFilePermission> pfp =
 802                             Files.getPosixFilePermissions(path);
 803                     if (!pfp.contains(PosixFilePermission.OWNER_WRITE)) {
 804                         pfp = EnumSet.copyOf(pfp);
 805                         pfp.add(PosixFilePermission.OWNER_WRITE);
 806                         Files.setPosixFilePermissions(path, pfp);
 807                     }
 808                 } catch (IOException e) {
 809                     Log.verbose(e);
 810                 }
 811             }).filter(p -> Files.isRegularFile(p)
 812                       && !(p.toString().contains("/Contents/MacOS/libjli.dylib")
 813                       || p.toString().endsWith(appExecutable)
 814                       || p.toString().contains("/Contents/runtime")
 815                       || p.toString().contains("/Contents/Frameworks"))
 816                      ).forEach(p -> {
 817                 //noinspection ThrowableResultOfMethodCallIgnored
 818                 if (toThrow.get() != null) return;
 819 
 820                 // If p is a symlink then skip the signing process.
 821                 if (Files.isSymbolicLink(p)) {
 822                     if (VERBOSE.fetchFrom(params)) {
 823                         Log.verbose(MessageFormat.format(I18N.getString(
 824                                 "message.ignoring.symlink"), p.toString()));
 825                     }
 826                 } else {
 827                     if (p.toString().endsWith(LIBRARY_NAME)) {
 828                         if (isFileSigned(p)) {
 829                             return;
 830                         }
 831                     }

 832                     List<String> args = new ArrayList<>();
 833                     args.addAll(Arrays.asList("codesign",
 834                             "--timestamp",
 835                             "--options", "runtime",
 836                             "--deep",
 837                             "--force",
 838                             "-s", signingIdentity,
 839                             "--prefix", identifierPrefix,

 840                             "-vvvv"));
 841                     if (entitlementsFile != null &&
 842                             (p.toString().endsWith(".jar")
 843                             || p.toString().endsWith(".dylib"))) {
 844                         args.add("--entitlements");
 845                         args.add(entitlementsFile); // entitlements
 846                     } else if (inheritedEntitlements != null &&
 847                             Files.isExecutable(p)) {
 848                         args.add("--entitlements");
 849                         args.add(inheritedEntitlements);
 850                         // inherited entitlements for executable processes
 851                     }
 852                     if (keyChain != null && !keyChain.isEmpty()) {
 853                         args.add("--keychain");
 854                         args.add(keyChain);
 855                     }
 856                     args.add(p.toString());
 857 
 858                     try {
 859                         Set<PosixFilePermission> oldPermissions =


 872             });
 873         }
 874         IOException ioe = toThrow.get();
 875         if (ioe != null) {
 876             throw ioe;
 877         }
 878 
 879         // sign all runtime and frameworks
 880         Consumer<? super Path> signIdentifiedByPList = path -> {
 881             //noinspection ThrowableResultOfMethodCallIgnored
 882             if (toThrow.get() != null) return;
 883 
 884             try {
 885                 List<String> args = new ArrayList<>();
 886                 args.addAll(Arrays.asList("codesign",
 887                         "-f",
 888                         "-s", signingIdentity, // sign with this key
 889                         "--prefix", identifierPrefix,
 890                         // use the identifier as a prefix
 891                         "-vvvv"));
 892 
 893                 if (entitlementsFile != null &&
 894                         (path.toString().endsWith(".jar")
 895                         || path.toString().endsWith(".dylib"))) {
 896                     args.add("--entitlements");
 897                     args.add(entitlementsFile); // entitlements
 898                 } else if (inheritedEntitlements != null &&
 899                         Files.isExecutable(path)) {
 900                     args.add("--entitlements");
 901                     args.add(inheritedEntitlements);
 902                     // inherited entitlements for executable processes
 903                 }
 904 
 905                 if (keyChain != null && !keyChain.isEmpty()) {
 906                     args.add("--keychain");
 907                     args.add(keyChain);
 908                 }
 909                 args.add(path.toString());
 910                 ProcessBuilder pb = new ProcessBuilder(args);
 911                 IOUtils.exec(pb);
 912 
 913 
 914                 args = new ArrayList<>();
 915                 args.addAll(Arrays.asList("codesign",
 916                         "--timestamp",
 917                         "--options", "runtime",
 918                         "--deep",
 919                         "--force",
 920                         "-s", signingIdentity,
 921                         "--prefix", identifierPrefix,

 922                         "-vvvv"));
 923                 if (keyChain != null && !keyChain.isEmpty()) {
 924                     args.add("--keychain");
 925                     args.add(keyChain);
 926                 }
 927                 args.add(path.toString()
 928                         + "/Contents/_CodeSignature/CodeResources");
 929                 pb = new ProcessBuilder(args);
 930                 IOUtils.exec(pb);
 931             } catch (IOException e) {
 932                 toThrow.set(e);
 933             }
 934         };
 935 
 936         Path javaPath = appLocation.resolve("Contents/runtime");
 937         if (Files.isDirectory(javaPath)) {
 938             signIdentifiedByPList.accept(javaPath);
 939 
 940             ioe = toThrow.get();
 941             if (ioe != null) {
 942                 throw ioe;
 943             }
 944         }
 945         Path frameworkPath = appLocation.resolve("Contents/Frameworks");
 946         if (Files.isDirectory(frameworkPath)) {
 947             Files.list(frameworkPath)
 948                     .forEach(signIdentifiedByPList);
 949 
 950             ioe = toThrow.get();
 951             if (ioe != null) {
 952                 throw ioe;
 953             }
 954         }
 955 
 956         // sign the app itself
 957         List<String> args = new ArrayList<>();
 958         args.addAll(Arrays.asList("codesign",
 959                 "--timestamp",
 960                 "--options", "runtime",
 961                 "--deep",
 962                 "--force",
 963                 "-s", signingIdentity,
 964                 "-vvvv"));
 965         if (entitlementsFile != null) {
 966             args.add("--entitlements");
 967             args.add(entitlementsFile); // entitlements
 968         }
 969         if (keyChain != null && !keyChain.isEmpty()) {
 970             args.add("--keychain");
 971             args.add(keyChain);
 972         }
 973         args.add(appLocation.toString());
 974 
 975         ProcessBuilder pb =
 976                 new ProcessBuilder(args.toArray(new String[args.size()]));
 977         IOUtils.exec(pb);
 978     }
 979 
 980     private static boolean isFileSigned(Path file) {
 981         ProcessBuilder pb =
 982                 new ProcessBuilder("codesign", "--verify", file.toString());
 983 
 984         try {


< prev index next >