57 * The primary entry point, processArguments():
58 * Processes and validates command line arguments, constructing DeployParams.
59 * Validates the DeployParams, and generate the BundleParams.
60 * Generates List of Bundlers from BundleParams valid for this platform.
61 * Executes each Bundler in the list.
62 */
63 public class Arguments {
64 private static final ResourceBundle I18N = ResourceBundle.getBundle(
65 "jdk.jpackage.internal.resources.MainResources");
66
67 private static final String IMAGE_MODE = "image";
68 private static final String INSTALLER_MODE = "installer";
69
70 private static final String FA_EXTENSIONS = "extension";
71 private static final String FA_CONTENT_TYPE = "mime-type";
72 private static final String FA_DESCRIPTION = "description";
73 private static final String FA_ICON = "icon";
74
75 public static final BundlerParamInfo<Boolean> CREATE_IMAGE =
76 new StandardBundlerParam<>(
77 I18N.getString("param.create-image.name"),
78 I18N.getString("param.create-image.description"),
79 IMAGE_MODE,
80 Boolean.class,
81 p -> Boolean.FALSE,
82 (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ?
83 true : Boolean.valueOf(s));
84
85 public static final BundlerParamInfo<Boolean> CREATE_INSTALLER =
86 new StandardBundlerParam<>(
87 I18N.getString("param.create-installer.name"),
88 I18N.getString("param.create-installer.description"),
89 INSTALLER_MODE,
90 Boolean.class,
91 p -> Boolean.FALSE,
92 (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ?
93 true : Boolean.valueOf(s));
94
95 // regexp for parsing args (for example, for secondary launchers)
96 private static Pattern pattern = Pattern.compile(
97 "(?:(?:([\"'])(?:\\\\\\1|.)*?(?:\\1|$))|(?:\\\\[\"'\\s]|[^\\s]))++");
98
99 private DeployParams deployParams = null;
100 private BundlerType bundleType = null;
101
102 private int pos = 0;
103 private List<String> argList = null;
104
105 private List<CLIOptions> allOptions = null;
106
107 private ArrayList<String> files = null;
108
109 private String input = null;
110 private String output = null;
111
112 private boolean hasMainJar = false;
113 private boolean hasMainClass = false;
114 private boolean hasMainModule = false;
115 private boolean hasTargetFormat = false;
116 private boolean hasAppImage = false;
117 public boolean userProvidedBuildRoot = false;
118
119 private String buildRoot = null;
120 private String mainJarPath = null;
121
122 private static boolean runtimeInstaller = false;
123
124 private List<jdk.jpackage.internal.Bundler> platformBundlers = null;
125
126 private List<SecondaryLauncherArguments> secondaryLaunchers = null;
127
128 private static Map<String, CLIOptions> argIds = new HashMap<>();
129 private static Map<String, CLIOptions> argShortIds = new HashMap<>();
130
131 {
132 // init maps for parsing arguments
133 EnumSet<CLIOptions> options = EnumSet.allOf(CLIOptions.class);
134
135 options.forEach(option -> {
136 argIds.put(option.getIdWithPrefix(), option);
137 if (option.getShortIdWithPrefix() != null) {
138 argShortIds.put(option.getShortIdWithPrefix(), option);
139 }
140 });
141 }
142
143 public Arguments(String[] args) throws PackagerException {
144 initArgumentList(args);
145 }
146
147 // CLIOptions is public for DeployParamsTest
148 public enum CLIOptions {
149 CREATE_IMAGE(IMAGE_MODE, OptionCategories.MODE, () -> {
150 context().bundleType = BundlerType.IMAGE;
151 context().deployParams.setTargetFormat("image");
152 setOptionValue(IMAGE_MODE, true);
153 }),
154
155 CREATE_INSTALLER(INSTALLER_MODE, OptionCategories.MODE, () -> {
156 setOptionValue(INSTALLER_MODE, true);
157 context().bundleType = BundlerType.INSTALLER;
158 String format = "installer";
159 context().deployParams.setTargetFormat(format);
160 }),
161
162 RUNTIME_INSTALLER("runtime-installer",
163 OptionCategories.PROPERTY, () -> {
164 runtimeInstaller = true;
165 setOptionValue("runtime-installer", true);
166 }),
167
168 INSTALLER_TYPE("installer-type", OptionCategories.PROPERTY, () -> {
169 String type = popArg();
170 if (BundlerType.INSTALLER.equals(context().bundleType)) {
171 context().deployParams.setTargetFormat(type);
172 context().hasTargetFormat = true;
173 }
174 setOptionValue("installer-type", type);
175 }),
176
177 INPUT ("input", "i", OptionCategories.PROPERTY, () -> {
178 context().input = popArg();
179 setOptionValue("input", context().input);
180 }),
181
182 OUTPUT ("output", "o", OptionCategories.PROPERTY, () -> {
183 context().output = popArg();
184 context().deployParams.setOutput(new File(context().output));
185 }),
186
187 DESCRIPTION ("description", "d", OptionCategories.PROPERTY),
188
189 VENDOR ("vendor", OptionCategories.PROPERTY),
190
191 APPCLASS ("main-class", "c", OptionCategories.PROPERTY, () -> {
192 context().hasMainClass = true;
193 setOptionValue("main-class", popArg());
194 }),
195
196 NAME ("name", "n", OptionCategories.PROPERTY),
197
198 IDENTIFIER ("identifier", OptionCategories.PROPERTY),
199
200 VERBOSE ("verbose", OptionCategories.PROPERTY, () -> {
201 setOptionValue("verbose", true);
202 Log.setVerbose(true);
203 }),
204
205 OVERWRITE ("overwrite", OptionCategories.PROPERTY, () -> {
206 setOptionValue("overwrite", true);
207 }),
208
209 RESOURCE_DIR("resource-dir",
210 OptionCategories.PROPERTY, () -> {
211 String resourceDir = popArg();
212 setOptionValue("resource-dir", resourceDir);
213 }),
214
215 FILES ("files", "f", OptionCategories.PROPERTY, () -> {
216 context().files = new ArrayList<>();
217 String files = popArg();
218 context().files.addAll(
219 Arrays.asList(files.split(File.pathSeparator)));
220 }),
221
222 ARGUMENTS ("arguments", "a", OptionCategories.PROPERTY, () -> {
223 List<String> arguments = getArgumentList(popArg());
224 setOptionValue("arguments", arguments);
225 }),
226
227 STRIP_NATIVE_COMMANDS ("strip-native-commands",
228 OptionCategories.PROPERTY, () -> {
229 setOptionValue("strip-native-commands", true);
230 }),
231
232 ICON ("icon", OptionCategories.PROPERTY),
233 CATEGORY ("category", OptionCategories.PROPERTY),
234 COPYRIGHT ("copyright", OptionCategories.PROPERTY),
235
236 LICENSE_FILE ("license-file", OptionCategories.PROPERTY),
237
238 VERSION ("app-version", OptionCategories.PROPERTY),
239
240 JVM_ARGS ("jvm-args", OptionCategories.PROPERTY, () -> {
241 List<String> args = getArgumentList(popArg());
242 args.forEach(a -> setOptionValue("jvm-args", a));
243 }),
244
245 FILE_ASSOCIATIONS ("file-associations",
246 OptionCategories.PROPERTY, () -> {
247 Map<String, ? super Object> args = new HashMap<>();
248
249 // load .properties file
250 Map<String, String> initialMap = getPropertiesFromFile(popArg());
251
252 String ext = initialMap.get(FA_EXTENSIONS);
253 if (ext != null) {
262 String desc = initialMap.get(FA_DESCRIPTION);
263 if (desc != null) {
264 args.put(StandardBundlerParam.FA_DESCRIPTION.getID(), desc);
265 }
266
267 String icon = initialMap.get(FA_ICON);
268 if (icon != null) {
269 args.put(StandardBundlerParam.FA_ICON.getID(), icon);
270 }
271
272 ArrayList<Map<String, ? super Object>> associationList =
273 new ArrayList<Map<String, ? super Object>>();
274
275 associationList.add(args);
276
277 // check that we really add _another_ value to the list
278 setOptionValue("file-associations", associationList);
279
280 }),
281
282 SECONDARY_LAUNCHER ("secondary-launcher",
283 OptionCategories.PROPERTY, () -> {
284 context().secondaryLaunchers.add(
285 new SecondaryLauncherArguments(popArg()));
286 }),
287
288 BUILD_ROOT ("build-root", OptionCategories.PROPERTY, () -> {
289 context().buildRoot = popArg();
290 context().userProvidedBuildRoot = true;
291 setOptionValue("build-root", context().buildRoot);
292 }),
293
294 INSTALL_DIR ("install-dir", OptionCategories.PROPERTY),
295
296 PREDEFINED_APP_IMAGE ("app-image", OptionCategories.PROPERTY, ()-> {
297 setOptionValue("app-image", popArg());
298 context().hasAppImage = true;
299 }),
300
301 PREDEFINED_RUNTIME_IMAGE ("runtime-image", OptionCategories.PROPERTY),
302
303 MAIN_JAR ("main-jar", "j", OptionCategories.PROPERTY, () -> {
304 context().mainJarPath = popArg();
305 context().hasMainJar = true;
306 setOptionValue("main-jar", context().mainJarPath);
307 }),
308
309 MODULE ("module", "m", OptionCategories.MODULAR, () -> {
310 context().hasMainModule = true;
311 setOptionValue("module", popArg());
312 }),
313
314 ADD_MODULES ("add-modules", OptionCategories.MODULAR),
315
316 MODULE_PATH ("module-path", "p", OptionCategories.MODULAR),
317
318 MAC_SIGN ("mac-sign", "s", OptionCategories.PLATFORM_MAC, () -> {
319 setOptionValue("mac-sign", true);
320 }),
321
322 MAC_BUNDLE_NAME ("mac-bundle-name", OptionCategories.PLATFORM_MAC),
323
362
363 WIN_REGISTRY_NAME ("win-registry-name", OptionCategories.PLATFORM_WIN),
364
365 WIN_UPGRADE_UUID ("win-upgrade-uuid",
366 OptionCategories.PLATFORM_WIN),
367
368 WIN_CONSOLE_HINT ("win-console", OptionCategories.PLATFORM_WIN, () -> {
369 setOptionValue("win-console", true);
370 }),
371
372 LINUX_BUNDLE_NAME ("linux-bundle-name",
373 OptionCategories.PLATFORM_LINUX),
374
375 LINUX_DEB_MAINTAINER ("linux-deb-maintainer",
376 OptionCategories.PLATFORM_LINUX),
377
378 LINUX_RPM_LICENSE_TYPE ("linux-rpm-license-type",
379 OptionCategories.PLATFORM_LINUX),
380
381 LINUX_PACKAGE_DEPENDENCIES ("linux-package-deps",
382 OptionCategories.PLATFORM_LINUX);
383
384 private final String id;
385 private final String shortId;
386 private final OptionCategories category;
387 private final ArgAction action;
388 private static Arguments argContext;
389
390 private CLIOptions(String id, OptionCategories category) {
391 this(id, null, category, null);
392 }
393
394 private CLIOptions(String id, String shortId,
395 OptionCategories category) {
396 this(id, shortId, category, null);
397 }
398
399 private CLIOptions(String id,
400 OptionCategories category, ArgAction action) {
401 this(id, null, category, action);
402 }
487 MODULAR,
488 PROPERTY,
489 PLATFORM_MAC,
490 PLATFORM_WIN,
491 PLATFORM_LINUX;
492 }
493
494 private void initArgumentList(String[] args) throws PackagerException {
495 argList = new ArrayList<String>(args.length);
496 for (String arg : args) {
497 argList.add(arg);
498 }
499 Log.debug ("\njpackage argument list: \n" + argList + "\n");
500 pos = 0;
501
502 deployParams = new DeployParams();
503 bundleType = BundlerType.NONE;
504
505 allOptions = new ArrayList<>();
506
507 secondaryLaunchers = new ArrayList<>();
508 }
509
510 public boolean processArguments() throws Exception {
511 try {
512
513 // init context of arguments
514 CLIOptions.setContext(this);
515
516 // parse cmd line
517 String arg;
518 CLIOptions option;
519 for (; CLIOptions.hasNextArg(); CLIOptions.nextArg()) {
520 arg = CLIOptions.getArg();
521 if ((option = toCLIOption(arg)) != null) {
522 // found a CLI option
523 allOptions.add(option);
524 option.execute();
525 } else {
526 throw new PackagerException("ERR_InvalidOption", arg);
527 }
536 // try to get main-class from manifest
537 String mainClass = getMainClassFromManifest();
538 if (mainClass != null) {
539 CLIOptions.setOptionValue(
540 CLIOptions.APPCLASS.getId(), mainClass);
541 }
542 }
543
544 // display warning for arguments that are not supported
545 // for current configuration.
546
547 validateArguments();
548
549 addResources(deployParams, input, files);
550
551 deployParams.setBundleType(bundleType);
552
553 List<Map<String, ? super Object>> launchersAsMap =
554 new ArrayList<>();
555
556 for (SecondaryLauncherArguments sl : secondaryLaunchers) {
557 launchersAsMap.add(sl.getLauncherMap());
558 }
559
560 deployParams.addBundleArgument(
561 StandardBundlerParam.SECONDARY_LAUNCHERS.getID(),
562 launchersAsMap);
563
564 // at this point deployParams should be already configured
565
566 deployParams.validate();
567
568 BundleParams bp = deployParams.getBundleParams();
569
570 // validate name(s)
571 ArrayList<String> usedNames = new ArrayList<String>();
572 usedNames.add(bp.getName()); // add main app name
573
574 for (SecondaryLauncherArguments sl : secondaryLaunchers) {
575 Map<String, ? super Object> slMap = sl.getLauncherMap();
576 String slName =
577 (String) slMap.get(Arguments.CLIOptions.NAME.getId());
578 if (slName == null) {
579 throw new PackagerException("ERR_NoSecondaryLauncherName");
580 }
581 // same rules apply to secondary launcher names as app name
582 DeployParams.validateName(slName, false);
583 for (String usedName : usedNames) {
584 if (slName.equals(usedName)) {
585 throw new PackagerException("ERR_NoUniqueName");
586 }
587 }
588 usedNames.add(slName);
589 }
590 if (runtimeInstaller && bp.getName() == null) {
591 throw new PackagerException("ERR_NoJreInstallerName");
592 }
593
594 return generateBundle(bp.getBundleParamsAsMap());
595 } catch (Exception e) {
596 if (Log.isVerbose()) {
597 throw e;
598 } else {
599 Log.error(e.getMessage());
600 if (e.getCause() != null && e.getCause() != e) {
601 Log.error(e.getCause().getMessage());
602 }
603 return false;
604 }
605 }
606 }
607
608 private void validateArguments() {
609 CLIOptions mode = allOptions.get(0);
610 for (CLIOptions option : allOptions) {
611 if(!ValidOptions.checkIfSupported(mode, option)) {
612 String key = "warning.unsupported.option";
613 if (ValidOptions.checkIfOtherSupported(mode, option)) {
614 key = "warning.unsupported.mode.option";
615 }
616 Log.info(MessageFormat.format(I18N.getString(key),
617 option.getId(), mode));
618 }
619 }
620 }
621
622 private List<jdk.jpackage.internal.Bundler> getPlatformBundlers() {
623
624 if (platformBundlers != null) {
625 return platformBundlers;
626 }
627
628 platformBundlers = new ArrayList<>();
629 for (jdk.jpackage.internal.Bundler bundler :
630 Bundlers.createBundlersInstance().getBundlers(
631 bundleType.toString())) {
632 if (hasTargetFormat && deployParams.getTargetFormat() != null &&
633 !deployParams.getTargetFormat().equalsIgnoreCase(
634 bundler.getID())) {
635 continue;
636 }
637 if (bundler.supported(runtimeInstaller)) {
638 platformBundlers.add(bundler);
639 }
640 }
641
642 return platformBundlers;
643 }
644
645 private boolean generateBundle(Map<String,? super Object> params)
646 throws PackagerException {
647
648 boolean bundleCreated = false;
649
650 // the build-root needs to be fetched from the params early,
651 // to prevent each copy of the params (such as may be used for
652 // secondary launchers) from generating a separate build-root when
653 // the default is used (the default is a new temp directory)
654 // The bundler.cleanup() below would not otherwise be able to
655 // clean these extra (and unneeded) temp directories.
656 StandardBundlerParam.BUILD_ROOT.fetchFrom(params);
657
658 for (jdk.jpackage.internal.Bundler bundler : getPlatformBundlers()) {
659 Map<String, ? super Object> localParams = new HashMap<>(params);
660 try {
661 if (bundler.validate(localParams)) {
662 File result =
663 bundler.execute(localParams, deployParams.outdir);
664 if (!userProvidedBuildRoot) {
665 bundler.cleanup(localParams);
666 }
667 if (result == null) {
668 throw new PackagerException("MSG_BundlerFailed",
669 bundler.getID(), bundler.getName());
670 }
671 bundleCreated = true; // at least one bundle was created
672 }
673 } catch (UnsupportedPlatformException e) {
674 throw new PackagerException(e,
675 "MSG_BundlerPlatformException",
676 bundler.getName());
677 } catch (ConfigException e) {
678 Log.debug(e);
|
57 * The primary entry point, processArguments():
58 * Processes and validates command line arguments, constructing DeployParams.
59 * Validates the DeployParams, and generate the BundleParams.
60 * Generates List of Bundlers from BundleParams valid for this platform.
61 * Executes each Bundler in the list.
62 */
63 public class Arguments {
64 private static final ResourceBundle I18N = ResourceBundle.getBundle(
65 "jdk.jpackage.internal.resources.MainResources");
66
67 private static final String IMAGE_MODE = "image";
68 private static final String INSTALLER_MODE = "installer";
69
70 private static final String FA_EXTENSIONS = "extension";
71 private static final String FA_CONTENT_TYPE = "mime-type";
72 private static final String FA_DESCRIPTION = "description";
73 private static final String FA_ICON = "icon";
74
75 public static final BundlerParamInfo<Boolean> CREATE_IMAGE =
76 new StandardBundlerParam<>(
77 IMAGE_MODE,
78 Boolean.class,
79 p -> Boolean.FALSE,
80 (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ?
81 true : Boolean.valueOf(s));
82
83 public static final BundlerParamInfo<Boolean> CREATE_INSTALLER =
84 new StandardBundlerParam<>(
85 INSTALLER_MODE,
86 Boolean.class,
87 p -> Boolean.FALSE,
88 (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ?
89 true : Boolean.valueOf(s));
90
91 // regexp for parsing args (for example, for additional launchers)
92 private static Pattern pattern = Pattern.compile(
93 "(?:(?:([\"'])(?:\\\\\\1|.)*?(?:\\1|$))|(?:\\\\[\"'\\s]|[^\\s]))++");
94
95 private DeployParams deployParams = null;
96 private BundlerType bundleType = null;
97
98 private int pos = 0;
99 private List<String> argList = null;
100
101 private List<CLIOptions> allOptions = null;
102
103 private ArrayList<String> files = null;
104
105 private String input = null;
106 private String output = null;
107
108 private boolean hasMainJar = false;
109 private boolean hasMainClass = false;
110 private boolean hasMainModule = false;
111 private boolean hasTargetFormat = false;
112 private boolean hasAppImage = false;
113 public boolean userProvidedBuildRoot = false;
114
115 private String buildRoot = null;
116 private String mainJarPath = null;
117
118 private static boolean runtimeInstaller = false;
119
120 private List<jdk.jpackage.internal.Bundler> platformBundlers = null;
121
122 private List<AddLauncherArguments> addLaunchers = null;
123
124 private static Map<String, CLIOptions> argIds = new HashMap<>();
125 private static Map<String, CLIOptions> argShortIds = new HashMap<>();
126
127 {
128 // init maps for parsing arguments
129 EnumSet<CLIOptions> options = EnumSet.allOf(CLIOptions.class);
130
131 options.forEach(option -> {
132 argIds.put(option.getIdWithPrefix(), option);
133 if (option.getShortIdWithPrefix() != null) {
134 argShortIds.put(option.getShortIdWithPrefix(), option);
135 }
136 });
137 }
138
139 public Arguments(String[] args) throws PackagerException {
140 initArgumentList(args);
141 }
142
143 // CLIOptions is public for DeployParamsTest
144 public enum CLIOptions {
145 CREATE_IMAGE(IMAGE_MODE, OptionCategories.MODE, () -> {
146 context().bundleType = BundlerType.IMAGE;
147 context().deployParams.setTargetFormat("image");
148 setOptionValue(IMAGE_MODE, true);
149 }),
150
151 CREATE_INSTALLER(INSTALLER_MODE, OptionCategories.MODE, () -> {
152 setOptionValue(INSTALLER_MODE, true);
153 context().bundleType = BundlerType.INSTALLER;
154 String format = "installer";
155 context().deployParams.setTargetFormat(format);
156 }),
157
158 INSTALLER_TYPE("installer-type", OptionCategories.PROPERTY, () -> {
159 String type = popArg();
160 if (BundlerType.INSTALLER.equals(context().bundleType)) {
161 context().deployParams.setTargetFormat(type);
162 context().hasTargetFormat = true;
163 }
164 setOptionValue("installer-type", type);
165 }),
166
167 INPUT ("input", "i", OptionCategories.PROPERTY, () -> {
168 context().input = popArg();
169 setOptionValue("input", context().input);
170 }),
171
172 OUTPUT ("output", "o", OptionCategories.PROPERTY, () -> {
173 context().output = popArg();
174 context().deployParams.setOutput(new File(context().output));
175 }),
176
177 DESCRIPTION ("description", "d", OptionCategories.PROPERTY),
178
179 VENDOR ("vendor", OptionCategories.PROPERTY),
180
181 APPCLASS ("main-class", OptionCategories.PROPERTY, () -> {
182 context().hasMainClass = true;
183 setOptionValue("main-class", popArg());
184 }),
185
186 NAME ("name", "n", OptionCategories.PROPERTY),
187
188 IDENTIFIER ("identifier", OptionCategories.PROPERTY),
189
190 VERBOSE ("verbose", OptionCategories.PROPERTY, () -> {
191 setOptionValue("verbose", true);
192 Log.setVerbose(true);
193 }),
194
195 RESOURCE_DIR("resource-dir",
196 OptionCategories.PROPERTY, () -> {
197 String resourceDir = popArg();
198 setOptionValue("resource-dir", resourceDir);
199 }),
200
201 FILES ("files", "f", OptionCategories.PROPERTY, () -> {
202 context().files = new ArrayList<>();
203 String files = popArg();
204 context().files.addAll(
205 Arrays.asList(files.split(File.pathSeparator)));
206 }),
207
208 ARGUMENTS ("arguments", OptionCategories.PROPERTY, () -> {
209 List<String> arguments = getArgumentList(popArg());
210 setOptionValue("arguments", arguments);
211 }),
212
213 ICON ("icon", OptionCategories.PROPERTY),
214
215 COPYRIGHT ("copyright", OptionCategories.PROPERTY),
216
217 LICENSE_FILE ("license-file", OptionCategories.PROPERTY),
218
219 VERSION ("app-version", OptionCategories.PROPERTY),
220
221 JVM_ARGS ("jvm-args", OptionCategories.PROPERTY, () -> {
222 List<String> args = getArgumentList(popArg());
223 args.forEach(a -> setOptionValue("jvm-args", a));
224 }),
225
226 FILE_ASSOCIATIONS ("file-associations",
227 OptionCategories.PROPERTY, () -> {
228 Map<String, ? super Object> args = new HashMap<>();
229
230 // load .properties file
231 Map<String, String> initialMap = getPropertiesFromFile(popArg());
232
233 String ext = initialMap.get(FA_EXTENSIONS);
234 if (ext != null) {
243 String desc = initialMap.get(FA_DESCRIPTION);
244 if (desc != null) {
245 args.put(StandardBundlerParam.FA_DESCRIPTION.getID(), desc);
246 }
247
248 String icon = initialMap.get(FA_ICON);
249 if (icon != null) {
250 args.put(StandardBundlerParam.FA_ICON.getID(), icon);
251 }
252
253 ArrayList<Map<String, ? super Object>> associationList =
254 new ArrayList<Map<String, ? super Object>>();
255
256 associationList.add(args);
257
258 // check that we really add _another_ value to the list
259 setOptionValue("file-associations", associationList);
260
261 }),
262
263 ADD_LAUNCHER ("add-launcher",
264 OptionCategories.PROPERTY, () -> {
265 context().addLaunchers.add(
266 new AddLauncherArguments(popArg()));
267 }),
268
269 TEMP_ROOT ("temp-root", OptionCategories.PROPERTY, () -> {
270 context().buildRoot = popArg();
271 context().userProvidedBuildRoot = true;
272 setOptionValue("temp-root", context().buildRoot);
273 }),
274
275 INSTALL_DIR ("install-dir", OptionCategories.PROPERTY),
276
277 PREDEFINED_APP_IMAGE ("app-image", OptionCategories.PROPERTY, ()-> {
278 setOptionValue("app-image", popArg());
279 context().hasAppImage = true;
280 }),
281
282 PREDEFINED_RUNTIME_IMAGE ("runtime-image", OptionCategories.PROPERTY),
283
284 MAIN_JAR ("main-jar", OptionCategories.PROPERTY, () -> {
285 context().mainJarPath = popArg();
286 context().hasMainJar = true;
287 setOptionValue("main-jar", context().mainJarPath);
288 }),
289
290 MODULE ("module", "m", OptionCategories.MODULAR, () -> {
291 context().hasMainModule = true;
292 setOptionValue("module", popArg());
293 }),
294
295 ADD_MODULES ("add-modules", OptionCategories.MODULAR),
296
297 MODULE_PATH ("module-path", "p", OptionCategories.MODULAR),
298
299 MAC_SIGN ("mac-sign", "s", OptionCategories.PLATFORM_MAC, () -> {
300 setOptionValue("mac-sign", true);
301 }),
302
303 MAC_BUNDLE_NAME ("mac-bundle-name", OptionCategories.PLATFORM_MAC),
304
343
344 WIN_REGISTRY_NAME ("win-registry-name", OptionCategories.PLATFORM_WIN),
345
346 WIN_UPGRADE_UUID ("win-upgrade-uuid",
347 OptionCategories.PLATFORM_WIN),
348
349 WIN_CONSOLE_HINT ("win-console", OptionCategories.PLATFORM_WIN, () -> {
350 setOptionValue("win-console", true);
351 }),
352
353 LINUX_BUNDLE_NAME ("linux-bundle-name",
354 OptionCategories.PLATFORM_LINUX),
355
356 LINUX_DEB_MAINTAINER ("linux-deb-maintainer",
357 OptionCategories.PLATFORM_LINUX),
358
359 LINUX_RPM_LICENSE_TYPE ("linux-rpm-license-type",
360 OptionCategories.PLATFORM_LINUX),
361
362 LINUX_PACKAGE_DEPENDENCIES ("linux-package-deps",
363 OptionCategories.PLATFORM_LINUX),
364
365 LINUX_MENU_GROUP ("linux-menu-group", OptionCategories.PLATFORM_LINUX);
366
367 private final String id;
368 private final String shortId;
369 private final OptionCategories category;
370 private final ArgAction action;
371 private static Arguments argContext;
372
373 private CLIOptions(String id, OptionCategories category) {
374 this(id, null, category, null);
375 }
376
377 private CLIOptions(String id, String shortId,
378 OptionCategories category) {
379 this(id, shortId, category, null);
380 }
381
382 private CLIOptions(String id,
383 OptionCategories category, ArgAction action) {
384 this(id, null, category, action);
385 }
470 MODULAR,
471 PROPERTY,
472 PLATFORM_MAC,
473 PLATFORM_WIN,
474 PLATFORM_LINUX;
475 }
476
477 private void initArgumentList(String[] args) throws PackagerException {
478 argList = new ArrayList<String>(args.length);
479 for (String arg : args) {
480 argList.add(arg);
481 }
482 Log.debug ("\njpackage argument list: \n" + argList + "\n");
483 pos = 0;
484
485 deployParams = new DeployParams();
486 bundleType = BundlerType.NONE;
487
488 allOptions = new ArrayList<>();
489
490 addLaunchers = new ArrayList<>();
491 }
492
493 public boolean processArguments() throws Exception {
494 try {
495
496 // init context of arguments
497 CLIOptions.setContext(this);
498
499 // parse cmd line
500 String arg;
501 CLIOptions option;
502 for (; CLIOptions.hasNextArg(); CLIOptions.nextArg()) {
503 arg = CLIOptions.getArg();
504 if ((option = toCLIOption(arg)) != null) {
505 // found a CLI option
506 allOptions.add(option);
507 option.execute();
508 } else {
509 throw new PackagerException("ERR_InvalidOption", arg);
510 }
519 // try to get main-class from manifest
520 String mainClass = getMainClassFromManifest();
521 if (mainClass != null) {
522 CLIOptions.setOptionValue(
523 CLIOptions.APPCLASS.getId(), mainClass);
524 }
525 }
526
527 // display warning for arguments that are not supported
528 // for current configuration.
529
530 validateArguments();
531
532 addResources(deployParams, input, files);
533
534 deployParams.setBundleType(bundleType);
535
536 List<Map<String, ? super Object>> launchersAsMap =
537 new ArrayList<>();
538
539 for (AddLauncherArguments sl : addLaunchers) {
540 launchersAsMap.add(sl.getLauncherMap());
541 }
542
543 deployParams.addBundleArgument(
544 StandardBundlerParam.ADD_LAUNCHERS.getID(),
545 launchersAsMap);
546
547 // at this point deployParams should be already configured
548
549 deployParams.validate();
550
551 BundleParams bp = deployParams.getBundleParams();
552
553 // validate name(s)
554 ArrayList<String> usedNames = new ArrayList<String>();
555 usedNames.add(bp.getName()); // add main app name
556
557 for (AddLauncherArguments sl : addLaunchers) {
558 Map<String, ? super Object> slMap = sl.getLauncherMap();
559 String slName =
560 (String) slMap.get(Arguments.CLIOptions.NAME.getId());
561 if (slName == null) {
562 throw new PackagerException("ERR_NoAddLauncherName");
563 }
564 // same rules apply to additional launcher names as app name
565 DeployParams.validateName(slName, false);
566 for (String usedName : usedNames) {
567 if (slName.equals(usedName)) {
568 throw new PackagerException("ERR_NoUniqueName");
569 }
570 }
571 usedNames.add(slName);
572 }
573 if (runtimeInstaller && bp.getName() == null) {
574 throw new PackagerException("ERR_NoJreInstallerName");
575 }
576
577 return generateBundle(bp.getBundleParamsAsMap());
578 } catch (Exception e) {
579 if (Log.isVerbose()) {
580 throw e;
581 } else {
582 Log.error(e.getMessage());
583 if (e.getCause() != null && e.getCause() != e) {
584 Log.error(e.getCause().getMessage());
585 }
586 return false;
587 }
588 }
589 }
590
591 private void validateArguments() throws PackagerException {
592 CLIOptions mode = allOptions.get(0);
593 boolean imageOnly = (mode == CLIOptions.CREATE_IMAGE);
594 boolean hasAppImage = allOptions.contains(
595 CLIOptions.PREDEFINED_APP_IMAGE);
596 boolean hasRuntime = allOptions.contains(
597 CLIOptions.PREDEFINED_RUNTIME_IMAGE);
598 boolean installerOnly = !imageOnly && hasAppImage;
599 boolean runtimeInstall = !imageOnly && hasRuntime && !hasAppImage &&
600 !hasMainModule && !hasMainJar;
601
602 for (CLIOptions option : allOptions) {
603 if (!ValidOptions.checkIfSupported(option)) {
604 // includes option valid only on different platform
605 throw new PackagerException("ERR_UnsupportedOption",
606 option.getIdWithPrefix());
607 }
608 if (imageOnly) {
609 if (!ValidOptions.checkIfImageSupported(option)) {
610 throw new PackagerException("ERR_NotImageOption",
611 option.getIdWithPrefix());
612 }
613 } else if (installerOnly || runtimeInstall) {
614 if (!ValidOptions.checkIfInstallerSupported(option)) {
615 String key = runtimeInstaller ?
616 "ERR_NoInstallerEntryPoint" : "ERR_NotInstallerOption";
617 throw new PackagerException(key, option.getIdWithPrefix());
618 }
619 }
620 }
621 if (installerOnly && hasRuntime) {
622 // note --runtime-image is only for image or runtime installer.
623 throw new PackagerException("ERR_NotInstallerOption",
624 CLIOptions.PREDEFINED_RUNTIME_IMAGE.getIdWithPrefix());
625 }
626 if (hasMainJar && hasMainModule) {
627 throw new PackagerException("ERR_BothMainJarAndModule");
628 }
629 if (imageOnly && !hasMainJar && !hasMainModule) {
630 throw new PackagerException("ERR_NoEntryPoint");
631 }
632 }
633
634 private List<jdk.jpackage.internal.Bundler> getPlatformBundlers() {
635
636 if (platformBundlers != null) {
637 return platformBundlers;
638 }
639
640 platformBundlers = new ArrayList<>();
641 for (jdk.jpackage.internal.Bundler bundler :
642 Bundlers.createBundlersInstance().getBundlers(
643 bundleType.toString())) {
644 if (hasTargetFormat && deployParams.getTargetFormat() != null &&
645 !deployParams.getTargetFormat().equalsIgnoreCase(
646 bundler.getID())) {
647 continue;
648 }
649 if (bundler.supported(runtimeInstaller)) {
650 platformBundlers.add(bundler);
651 }
652 }
653
654 return platformBundlers;
655 }
656
657 private boolean generateBundle(Map<String,? super Object> params)
658 throws PackagerException {
659
660 boolean bundleCreated = false;
661
662 // the temp-root needs to be fetched from the params early,
663 // to prevent each copy of the params (such as may be used for
664 // additional launchers) from generating a separate temp-root when
665 // the default is used (the default is a new temp directory)
666 // The bundler.cleanup() below would not otherwise be able to
667 // clean these extra (and unneeded) temp directories.
668 StandardBundlerParam.TEMP_ROOT.fetchFrom(params);
669 List<jdk.jpackage.internal.Bundler> bundlers = getPlatformBundlers();
670 if (bundlers.isEmpty()) {
671 throw new PackagerException("ERR_InvalidInstallerType",
672 deployParams.getTargetFormat());
673 }
674 for (jdk.jpackage.internal.Bundler bundler : bundlers) {
675 Map<String, ? super Object> localParams = new HashMap<>(params);
676 try {
677 if (bundler.validate(localParams)) {
678 File result =
679 bundler.execute(localParams, deployParams.outdir);
680 if (!userProvidedBuildRoot) {
681 bundler.cleanup(localParams);
682 }
683 if (result == null) {
684 throw new PackagerException("MSG_BundlerFailed",
685 bundler.getID(), bundler.getName());
686 }
687 bundleCreated = true; // at least one bundle was created
688 }
689 } catch (UnsupportedPlatformException e) {
690 throw new PackagerException(e,
691 "MSG_BundlerPlatformException",
692 bundler.getName());
693 } catch (ConfigException e) {
694 Log.debug(e);
|