9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.oracle.tools.packager.mac;
27
28 import com.oracle.tools.packager.BundlerParamInfo;
29 import com.oracle.tools.packager.JreUtils;
30 import com.oracle.tools.packager.RelativeFileSet;
31 import com.oracle.tools.packager.StandardBundlerParam;
32 import com.oracle.tools.packager.Log;
33 import com.oracle.tools.packager.ConfigException;
34 import com.oracle.tools.packager.IOUtils;
35 import com.oracle.tools.packager.UnsupportedPlatformException;
36
37 import java.io.File;
38 import java.io.FileNotFoundException;
39 import java.io.IOException;
40 import java.text.MessageFormat;
41 import java.util.ArrayList;
42 import java.util.Arrays;
43 import java.util.Collection;
44 import java.util.LinkedHashSet;
45 import java.util.List;
46 import java.util.Map;
47 import java.util.Optional;
48 import java.util.ResourceBundle;
49
50 import static com.oracle.tools.packager.StandardBundlerParam.*;
51 import static com.oracle.tools.packager.mac.MacAppBundler.*;
52
53 public class MacAppStoreBundler extends MacBaseInstallerBundler {
54
55 private static final ResourceBundle I18N =
94 public MacAppStoreBundler() {
95 super();
96 baseResourceLoader = MacResources.class;
97 }
98
99 //@Override
100 public File bundle(Map<String, ? super Object> p, File outdir) {
101 Log.info(MessageFormat.format(I18N.getString("message.building-bundle"), APP_NAME.fetchFrom(p)));
102 if (!outdir.isDirectory() && !outdir.mkdirs()) {
103 throw new RuntimeException(MessageFormat.format(I18N.getString("error.cannot-create-output-dir"), outdir.getAbsolutePath()));
104 }
105 if (!outdir.canWrite()) {
106 throw new RuntimeException(MessageFormat.format(I18N.getString("error.cannot-write-to-output-dir"), outdir.getAbsolutePath()));
107 }
108
109 // first, load in some overrides
110 // icns needs @2 versions, so load in the @2 default
111 p.put(DEFAULT_ICNS_ICON.getID(), TEMPLATE_BUNDLE_ICON_HIDPI);
112
113 // next we need to change the jdk/jre stripping to strip gstreamer
114 p.put(MAC_RULES.getID(), createMacAppStoreRuntimeRules(p));
115
116 // now we create the app
117 File appImageDir = APP_IMAGE_BUILD_ROOT.fetchFrom(p);
118 try {
119 appImageDir.mkdirs();
120
121 // first, make sure we don't use the local signing key
122 p.put(DEVELOPER_ID_APP_SIGNING_KEY.getID(), null);
123 File appLocation = prepareAppBundle(p);
124
125 prepareEntitlements(p);
126
127 String signingIdentity = MAC_APP_STORE_APP_SIGNING_KEY.fetchFrom(p);
128 String identifierPrefix = BUNDLE_ID_SIGNING_PREFIX.fetchFrom(p);
129 String entitlementsFile = getConfig_Entitlements(p).toString();
130 String inheritEntitlements = getConfig_Inherit_Entitlements(p).toString();
131
132 signAppBundle(p, appLocation, signingIdentity, identifierPrefix, entitlementsFile, inheritEntitlements);
133 ProcessBuilder pb;
134
135 // create the final pkg file
136 File finalPKG = new File(outdir, INSTALLER_NAME.fetchFrom(p)
137 + INSTALLER_SUFFIX.fetchFrom(p)
138 + ".pkg");
139 outdir.mkdirs();
140
141 List<String> buildOptions = new ArrayList<>();
142 buildOptions.add("productbuild");
143 buildOptions.add("--component");
144 buildOptions.add(appLocation.toString());
145 buildOptions.add("/Applications");
146 buildOptions.add("--sign");
147 buildOptions.add(MAC_APP_STORE_PKG_SIGNING_KEY.fetchFrom(p));
148 buildOptions.add("--product");
149 buildOptions.add(appLocation + "/Contents/Info.plist");
150 String keychainName = SIGNING_KEYCHAIN.fetchFrom(p);
151 if (keychainName != null && !keychainName.isEmpty()) {
152 buildOptions.add("--keychain");
220 VERBOSE.fetchFrom(params),
221 DROP_IN_RESOURCES_ROOT.fetchFrom(params));
222 }
223 fetchResource(getInheritEntitlementsFileName(params),
224 I18N.getString("resource.mac-app-store-inherit-entitlements"),
225 DEFAULT_INHERIT_ENTITLEMENTS,
226 getConfig_Inherit_Entitlements(params),
227 VERBOSE.fetchFrom(params),
228 DROP_IN_RESOURCES_ROOT.fetchFrom(params));
229 }
230
231 private String getEntitlementsFileName(Map<String, ? super Object> params) {
232 return MAC_BUNDLER_PREFIX+ APP_NAME.fetchFrom(params) +".entitlements";
233 }
234
235 private String getInheritEntitlementsFileName(Map<String, ? super Object> params) {
236 return MAC_BUNDLER_PREFIX+ APP_NAME.fetchFrom(params) +"_Inherit.entitlements";
237 }
238
239
240 public static JreUtils.Rule[] createMacAppStoreRuntimeRules(Map<String, ? super Object> params) {
241 //Subsetting of JRE is restricted.
242 //JRE README defines what is allowed to strip:
243 // http://www.oracle.com/technetwork/java/javase/jre-8-readme-2095710.html
244 //
245
246 List<JreUtils.Rule> rules = new ArrayList<>();
247
248 rules.addAll(Arrays.asList(createMacRuntimeRules(params)));
249
250 File baseDir;
251
252 if (params.containsKey(MAC_RUNTIME.getID())) {
253 Object o = params.get(MAC_RUNTIME.getID());
254 if (o instanceof RelativeFileSet) {
255
256 baseDir = ((RelativeFileSet) o).getBaseDirectory();
257 } else {
258 baseDir = new File(o.toString());
259 }
260 } else {
261 baseDir = new File(System.getProperty("java.home"));
262 }
263
264 // we accept either pointing at the directories typically installed at:
265 // /Libraries/Java/JavaVirtualMachine/jdk1.8.0_40/
266 // * .
267 // * Contents/Home
268 // * Contents/Home/jre
269 // /Library/Internet\ Plug-Ins/JavaAppletPlugin.plugin/
270 // * .
271 // * /Contents/Home
272 // version may change, and if we don't detect any Contents/Home or Contents/Home/jre we will
273 // presume we are at a root.
274
275
276 try {
277 String path = baseDir.getCanonicalPath();
278 if (path.endsWith("/Contents/Home/jre")) {
279 baseDir = baseDir.getParentFile().getParentFile().getParentFile();
280 } else if (path.endsWith("/Contents/Home")) {
281 baseDir = baseDir.getParentFile().getParentFile();
282 }
283 } catch (IOException e) {
284 throw new RuntimeException(e);
285 }
286
287 if (!baseDir.exists()) {
288 throw new RuntimeException(I18N.getString("error.non-existent-runtime"),
289 new ConfigException(I18N.getString("error.non-existent-runtime"),
290 I18N.getString("error.non-existent-runtime.advice")));
291 }
292
293 if (new File(baseDir, "Contents/Home/lib/libjfxmedia_qtkit.dylib").exists()
294 || new File(baseDir, "Contents/Home/jre/lib/libjfxmedia_qtkit.dylib").exists())
295 {
296 rules.add(JreUtils.Rule.suffixNeg("/lib/libjfxmedia_qtkit.dylib"));
297 } else {
298 rules.add(JreUtils.Rule.suffixNeg("/lib/libjfxmedia.dylib"));
299 }
300 return rules.toArray(new JreUtils.Rule[rules.size()]);
301 }
302
303 //////////////////////////////////////////////////////////////////////////////////
304 // Implement Bundler
305 //////////////////////////////////////////////////////////////////////////////////
306
307 @Override
308 public String getName() {
309 return I18N.getString("bundler.name");
310 }
311
312 @Override
313 public String getDescription() {
314 return I18N.getString("bundler.description");
315 }
316
317 @Override
318 public String getID() {
319 return "mac.appStore";
320 }
321
322 @Override
343 return results;
344 }
345
346 @Override
347 public boolean validate(Map<String, ? super Object> params) throws UnsupportedPlatformException, ConfigException {
348 try {
349 if (!System.getProperty("os.name").toLowerCase().contains("os x")) {
350 throw new UnsupportedPlatformException();
351 }
352
353 if (params == null) {
354 throw new ConfigException(
355 I18N.getString("error.parameters-null"),
356 I18N.getString("error.parameters-null.advice"));
357 }
358
359 // hdiutil is always available so there's no need to test for availability.
360 //run basic validation to ensure requirements are met
361
362 // Mac App Store apps cannot use the system runtime
363 if (params.containsKey(MAC_RUNTIME.getID()) && params.get(MAC_RUNTIME.getID()) == null) {
364 throw new ConfigException(
365 I18N.getString("error.no-system-runtime"),
366 I18N.getString("error.no-system-runtime.advice"));
367 }
368
369 //we need to change the jdk/jre stripping to strip qtkit code
370 params.put(MAC_RULES.getID(), createMacAppStoreRuntimeRules(params));
371
372 //we are not interested in return code, only possible exception
373 validateAppImageAndBundeler(params);
374
375 // reject explicitly set to not sign
376 if (!Optional.ofNullable(SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.TRUE)) {
377 throw new ConfigException(
378 I18N.getString("error.must-sign-app-store"),
379 I18N.getString("error.must-sign-app-store.advice"));
380 }
381
382 // make sure we have settings for signatures
383 if (MAC_APP_STORE_APP_SIGNING_KEY.fetchFrom(params) == null) {
384 throw new ConfigException(
385 I18N.getString("error.no-app-signing-key"),
386 I18N.getString("error.no-app-signing-key.advice"));
387 }
388 if (MAC_APP_STORE_PKG_SIGNING_KEY.fetchFrom(params) == null) {
389 throw new ConfigException(
390 I18N.getString("error.no-pkg-signing-key"),
|
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.oracle.tools.packager.mac;
27
28 import com.oracle.tools.packager.BundlerParamInfo;
29 import com.oracle.tools.packager.StandardBundlerParam;
30 import com.oracle.tools.packager.Log;
31 import com.oracle.tools.packager.ConfigException;
32 import com.oracle.tools.packager.IOUtils;
33 import com.oracle.tools.packager.UnsupportedPlatformException;
34 import jdk.packager.builders.mac.MacAppImageBuilder;
35
36 import java.io.File;
37 import java.io.FileNotFoundException;
38 import java.io.IOException;
39 import java.text.MessageFormat;
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.Collection;
43 import java.util.LinkedHashSet;
44 import java.util.List;
45 import java.util.Map;
46 import java.util.Optional;
47 import java.util.ResourceBundle;
48
49 import static com.oracle.tools.packager.StandardBundlerParam.*;
50 import static com.oracle.tools.packager.mac.MacAppBundler.*;
51
52 public class MacAppStoreBundler extends MacBaseInstallerBundler {
53
54 private static final ResourceBundle I18N =
93 public MacAppStoreBundler() {
94 super();
95 baseResourceLoader = MacResources.class;
96 }
97
98 //@Override
99 public File bundle(Map<String, ? super Object> p, File outdir) {
100 Log.info(MessageFormat.format(I18N.getString("message.building-bundle"), APP_NAME.fetchFrom(p)));
101 if (!outdir.isDirectory() && !outdir.mkdirs()) {
102 throw new RuntimeException(MessageFormat.format(I18N.getString("error.cannot-create-output-dir"), outdir.getAbsolutePath()));
103 }
104 if (!outdir.canWrite()) {
105 throw new RuntimeException(MessageFormat.format(I18N.getString("error.cannot-write-to-output-dir"), outdir.getAbsolutePath()));
106 }
107
108 // first, load in some overrides
109 // icns needs @2 versions, so load in the @2 default
110 p.put(DEFAULT_ICNS_ICON.getID(), TEMPLATE_BUNDLE_ICON_HIDPI);
111
112 // next we need to change the jdk/jre stripping to strip gstreamer
113 // p.put(MAC_RULES.getID(), createMacAppStoreRuntimeRules(p));
114
115 // now we create the app
116 File appImageDir = APP_IMAGE_BUILD_ROOT.fetchFrom(p);
117 try {
118 appImageDir.mkdirs();
119
120 // first, make sure we don't use the local signing key
121 p.put(DEVELOPER_ID_APP_SIGNING_KEY.getID(), null);
122 File appLocation = prepareAppBundle(p);
123
124 prepareEntitlements(p);
125
126 String signingIdentity = MAC_APP_STORE_APP_SIGNING_KEY.fetchFrom(p);
127 String identifierPrefix = BUNDLE_ID_SIGNING_PREFIX.fetchFrom(p);
128 String entitlementsFile = getConfig_Entitlements(p).toString();
129 String inheritEntitlements = getConfig_Inherit_Entitlements(p).toString();
130
131 MacAppImageBuilder.signAppBundle(p, appLocation.toPath(), signingIdentity, identifierPrefix, entitlementsFile, inheritEntitlements);
132 ProcessBuilder pb;
133
134 // create the final pkg file
135 File finalPKG = new File(outdir, INSTALLER_NAME.fetchFrom(p)
136 + INSTALLER_SUFFIX.fetchFrom(p)
137 + ".pkg");
138 outdir.mkdirs();
139
140 List<String> buildOptions = new ArrayList<>();
141 buildOptions.add("productbuild");
142 buildOptions.add("--component");
143 buildOptions.add(appLocation.toString());
144 buildOptions.add("/Applications");
145 buildOptions.add("--sign");
146 buildOptions.add(MAC_APP_STORE_PKG_SIGNING_KEY.fetchFrom(p));
147 buildOptions.add("--product");
148 buildOptions.add(appLocation + "/Contents/Info.plist");
149 String keychainName = SIGNING_KEYCHAIN.fetchFrom(p);
150 if (keychainName != null && !keychainName.isEmpty()) {
151 buildOptions.add("--keychain");
219 VERBOSE.fetchFrom(params),
220 DROP_IN_RESOURCES_ROOT.fetchFrom(params));
221 }
222 fetchResource(getInheritEntitlementsFileName(params),
223 I18N.getString("resource.mac-app-store-inherit-entitlements"),
224 DEFAULT_INHERIT_ENTITLEMENTS,
225 getConfig_Inherit_Entitlements(params),
226 VERBOSE.fetchFrom(params),
227 DROP_IN_RESOURCES_ROOT.fetchFrom(params));
228 }
229
230 private String getEntitlementsFileName(Map<String, ? super Object> params) {
231 return MAC_BUNDLER_PREFIX+ APP_NAME.fetchFrom(params) +".entitlements";
232 }
233
234 private String getInheritEntitlementsFileName(Map<String, ? super Object> params) {
235 return MAC_BUNDLER_PREFIX+ APP_NAME.fetchFrom(params) +"_Inherit.entitlements";
236 }
237
238
239 //////////////////////////////////////////////////////////////////////////////////
240 // Implement Bundler
241 //////////////////////////////////////////////////////////////////////////////////
242
243 @Override
244 public String getName() {
245 return I18N.getString("bundler.name");
246 }
247
248 @Override
249 public String getDescription() {
250 return I18N.getString("bundler.description");
251 }
252
253 @Override
254 public String getID() {
255 return "mac.appStore";
256 }
257
258 @Override
279 return results;
280 }
281
282 @Override
283 public boolean validate(Map<String, ? super Object> params) throws UnsupportedPlatformException, ConfigException {
284 try {
285 if (!System.getProperty("os.name").toLowerCase().contains("os x")) {
286 throw new UnsupportedPlatformException();
287 }
288
289 if (params == null) {
290 throw new ConfigException(
291 I18N.getString("error.parameters-null"),
292 I18N.getString("error.parameters-null.advice"));
293 }
294
295 // hdiutil is always available so there's no need to test for availability.
296 //run basic validation to ensure requirements are met
297
298 // Mac App Store apps cannot use the system runtime
299 //TODO
300
301 //we are not interested in return code, only possible exception
302 validateAppImageAndBundeler(params);
303
304 // reject explicitly set to not sign
305 if (!Optional.ofNullable(SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.TRUE)) {
306 throw new ConfigException(
307 I18N.getString("error.must-sign-app-store"),
308 I18N.getString("error.must-sign-app-store.advice"));
309 }
310
311 // make sure we have settings for signatures
312 if (MAC_APP_STORE_APP_SIGNING_KEY.fetchFrom(params) == null) {
313 throw new ConfigException(
314 I18N.getString("error.no-app-signing-key"),
315 I18N.getString("error.no-app-signing-key.advice"));
316 }
317 if (MAC_APP_STORE_PKG_SIGNING_KEY.fetchFrom(params) == null) {
318 throw new ConfigException(
319 I18N.getString("error.no-pkg-signing-key"),
|