62 */ |
62 */ |
63 public class Arguments { |
63 public class Arguments { |
64 private static final ResourceBundle I18N = ResourceBundle.getBundle( |
64 private static final ResourceBundle I18N = ResourceBundle.getBundle( |
65 "jdk.jpackage.internal.resources.MainResources"); |
65 "jdk.jpackage.internal.resources.MainResources"); |
66 |
66 |
67 private static final String APPIMAGE_MODE = "create-app-image"; |
67 private static final String IMAGE_PACKAGE_TYPE = "app-image"; |
68 private static final String INSTALLER_MODE = "create-installer"; |
|
69 |
|
70 private static final String FA_EXTENSIONS = "extension"; |
68 private static final String FA_EXTENSIONS = "extension"; |
71 private static final String FA_CONTENT_TYPE = "mime-type"; |
69 private static final String FA_CONTENT_TYPE = "mime-type"; |
72 private static final String FA_DESCRIPTION = "description"; |
70 private static final String FA_DESCRIPTION = "description"; |
73 private static final String FA_ICON = "icon"; |
71 private static final String FA_ICON = "icon"; |
74 |
72 |
75 static final BundlerParamInfo<Boolean> CREATE_APP_IMAGE = |
|
76 new StandardBundlerParam<>( |
|
77 APPIMAGE_MODE, |
|
78 Boolean.class, |
|
79 p -> Boolean.FALSE, |
|
80 (s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? |
|
81 true : Boolean.valueOf(s)); |
|
82 |
|
83 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) |
73 // regexp for parsing args (for example, for additional launchers) |
92 private static Pattern pattern = Pattern.compile( |
74 private static Pattern pattern = Pattern.compile( |
93 "(?:(?:([\"'])(?:\\\\\\1|.)*?(?:\\1|$))|(?:\\\\[\"'\\s]|[^\\s]))++"); |
75 "(?:(?:([\"'])(?:\\\\\\1|.)*?(?:\\1|$))|(?:\\\\[\"'\\s]|[^\\s]))++"); |
94 |
76 |
95 private DeployParams deployParams = null; |
77 private DeployParams deployParams = null; |
96 private BundlerType bundleType = null; |
78 private String packageType = null; |
97 |
79 |
98 private int pos = 0; |
80 private int pos = 0; |
99 private List<String> argList = null; |
81 private List<String> argList = null; |
100 |
82 |
101 private List<CLIOptions> allOptions = null; |
83 private List<CLIOptions> allOptions = null; |
104 private String output = null; |
86 private String output = null; |
105 |
87 |
106 private boolean hasMainJar = false; |
88 private boolean hasMainJar = false; |
107 private boolean hasMainClass = false; |
89 private boolean hasMainClass = false; |
108 private boolean hasMainModule = false; |
90 private boolean hasMainModule = false; |
109 private boolean hasTargetFormat = false; |
|
110 public boolean userProvidedBuildRoot = false; |
91 public boolean userProvidedBuildRoot = false; |
111 |
92 |
112 private String buildRoot = null; |
93 private String buildRoot = null; |
113 private String mainJarPath = null; |
94 private String mainJarPath = null; |
114 |
95 |
115 private static boolean runtimeInstaller = false; |
96 private static boolean runtimeInstaller = false; |
116 |
|
117 private List<jdk.jpackage.internal.Bundler> platformBundlers = null; |
|
118 |
97 |
119 private List<AddLauncherArguments> addLaunchers = null; |
98 private List<AddLauncherArguments> addLaunchers = null; |
120 |
99 |
121 private static Map<String, CLIOptions> argIds = new HashMap<>(); |
100 private static Map<String, CLIOptions> argIds = new HashMap<>(); |
122 private static Map<String, CLIOptions> argShortIds = new HashMap<>(); |
101 private static Map<String, CLIOptions> argShortIds = new HashMap<>(); |
138 } |
117 } |
139 Log.debug ("\njpackage argument list: \n" + argList + "\n"); |
118 Log.debug ("\njpackage argument list: \n" + argList + "\n"); |
140 pos = 0; |
119 pos = 0; |
141 |
120 |
142 deployParams = new DeployParams(); |
121 deployParams = new DeployParams(); |
143 bundleType = BundlerType.NONE; |
122 |
|
123 packageType = null; |
144 |
124 |
145 allOptions = new ArrayList<>(); |
125 allOptions = new ArrayList<>(); |
146 |
126 |
147 addLaunchers = new ArrayList<>(); |
127 addLaunchers = new ArrayList<>(); |
148 } |
128 } |
149 |
129 |
150 // CLIOptions is public for DeployParamsTest |
130 // CLIOptions is public for DeployParamsTest |
151 public enum CLIOptions { |
131 public enum CLIOptions { |
152 CREATE_APP_IMAGE(APPIMAGE_MODE, OptionCategories.MODE, () -> { |
132 PACKAGE_TYPE("package-type", OptionCategories.PROPERTY, () -> { |
153 context().bundleType = BundlerType.IMAGE; |
133 context().packageType = popArg(); |
154 context().deployParams.setTargetFormat("image"); |
134 context().deployParams.setTargetFormat(context().packageType); |
155 setOptionValue(APPIMAGE_MODE, true); |
|
156 }), |
|
157 |
|
158 CREATE_INSTALLER(INSTALLER_MODE, OptionCategories.MODE, () -> { |
|
159 setOptionValue(INSTALLER_MODE, true); |
|
160 context().bundleType = BundlerType.INSTALLER; |
|
161 String format = "installer"; |
|
162 context().deployParams.setTargetFormat(format); |
|
163 }), |
|
164 |
|
165 INSTALLER_TYPE("installer-type", OptionCategories.PROPERTY, () -> { |
|
166 String type = popArg(); |
|
167 if (BundlerType.INSTALLER.equals(context().bundleType)) { |
|
168 context().deployParams.setTargetFormat(type); |
|
169 context().hasTargetFormat = true; |
|
170 } |
|
171 setOptionValue("installer-type", type); |
|
172 }), |
135 }), |
173 |
136 |
174 INPUT ("input", "i", OptionCategories.PROPERTY, () -> { |
137 INPUT ("input", "i", OptionCategories.PROPERTY, () -> { |
175 context().input = popArg(); |
138 context().input = popArg(); |
176 setOptionValue("input", context().input); |
139 setOptionValue("input", context().input); |
497 } else { |
460 } else { |
498 throw new PackagerException("ERR_InvalidOption", arg); |
461 throw new PackagerException("ERR_InvalidOption", arg); |
499 } |
462 } |
500 } |
463 } |
501 |
464 |
502 if (allOptions.isEmpty() || !allOptions.get(0).isMode()) { |
|
503 // first argument should always be a mode. |
|
504 throw new PackagerException("ERR_MissingMode"); |
|
505 } |
|
506 |
|
507 if (hasMainJar && !hasMainClass) { |
465 if (hasMainJar && !hasMainClass) { |
508 // try to get main-class from manifest |
466 // try to get main-class from manifest |
509 String mainClass = getMainClassFromManifest(); |
467 String mainClass = getMainClassFromManifest(); |
510 if (mainClass != null) { |
468 if (mainClass != null) { |
511 CLIOptions.setOptionValue( |
469 CLIOptions.setOptionValue( |
512 CLIOptions.APPCLASS.getId(), mainClass); |
470 CLIOptions.APPCLASS.getId(), mainClass); |
513 } |
471 } |
514 } |
472 } |
515 |
473 |
516 // display warning for arguments that are not supported |
474 // display error for arguments that are not supported |
517 // for current configuration. |
475 // for current configuration. |
518 |
476 |
519 validateArguments(); |
477 validateArguments(); |
520 |
478 |
521 addResources(deployParams, input); |
479 addResources(deployParams, input); |
522 |
|
523 deployParams.setBundleType(bundleType); |
|
524 |
480 |
525 List<Map<String, ? super Object>> launchersAsMap = |
481 List<Map<String, ? super Object>> launchersAsMap = |
526 new ArrayList<>(); |
482 new ArrayList<>(); |
527 |
483 |
528 for (AddLauncherArguments sl : addLaunchers) { |
484 for (AddLauncherArguments sl : addLaunchers) { |
580 return false; |
537 return false; |
581 } |
538 } |
582 } |
539 } |
583 |
540 |
584 private void validateArguments() throws PackagerException { |
541 private void validateArguments() throws PackagerException { |
585 CLIOptions mode = allOptions.get(0); |
542 String packageType = deployParams.getTargetFormat(); |
586 boolean imageOnly = (mode == CLIOptions.CREATE_APP_IMAGE); |
543 String ptype = (packageType != null) ? packageType : "default"; |
|
544 boolean imageOnly = IMAGE_PACKAGE_TYPE.equals(packageType); |
587 boolean hasAppImage = allOptions.contains( |
545 boolean hasAppImage = allOptions.contains( |
588 CLIOptions.PREDEFINED_APP_IMAGE); |
546 CLIOptions.PREDEFINED_APP_IMAGE); |
589 boolean hasRuntime = allOptions.contains( |
547 boolean hasRuntime = allOptions.contains( |
590 CLIOptions.PREDEFINED_RUNTIME_IMAGE); |
548 CLIOptions.PREDEFINED_RUNTIME_IMAGE); |
591 boolean installerOnly = !imageOnly && hasAppImage; |
549 boolean installerOnly = !imageOnly && hasAppImage; |
592 boolean runtimeInstall = !imageOnly && hasRuntime && !hasAppImage && |
550 runtimeInstaller = !imageOnly && hasRuntime && !hasAppImage && |
593 !hasMainModule && !hasMainJar; |
551 !hasMainModule && !hasMainJar; |
594 |
552 |
595 for (CLIOptions option : allOptions) { |
553 for (CLIOptions option : allOptions) { |
596 if (!ValidOptions.checkIfSupported(option)) { |
554 if (!ValidOptions.checkIfSupported(option)) { |
597 // includes option valid only on different platform |
555 // includes option valid only on different platform |
598 throw new PackagerException("ERR_UnsupportedOption", |
556 throw new PackagerException("ERR_UnsupportedOption", |
599 option.getIdWithPrefix()); |
557 option.getIdWithPrefix()); |
600 } |
558 } |
601 if (imageOnly) { |
559 if (imageOnly) { |
602 if (!ValidOptions.checkIfImageSupported(option)) { |
560 if (!ValidOptions.checkIfImageSupported(option)) { |
603 throw new PackagerException("ERR_NotImageOption", |
561 throw new PackagerException("ERR_InvalidTypeOption", |
604 option.getIdWithPrefix()); |
562 option.getIdWithPrefix(), packageType); |
605 } |
563 } |
606 } else if (installerOnly || runtimeInstall) { |
564 } else if (installerOnly || runtimeInstaller) { |
607 if (!ValidOptions.checkIfInstallerSupported(option)) { |
565 if (!ValidOptions.checkIfInstallerSupported(option)) { |
608 String key = runtimeInstaller ? |
566 if (runtimeInstaller) { |
609 "ERR_NoInstallerEntryPoint" : "ERR_NotInstallerOption"; |
567 throw new PackagerException("ERR_NoInstallerEntryPoint", |
610 throw new PackagerException(key, option.getIdWithPrefix()); |
568 option.getIdWithPrefix()); |
|
569 } else { |
|
570 throw new PackagerException("ERR_InvalidTypeOption", |
|
571 option.getIdWithPrefix(), ptype); |
|
572 } |
611 } |
573 } |
612 } |
574 } |
613 } |
575 } |
614 if (installerOnly && hasRuntime) { |
576 if (installerOnly && hasRuntime) { |
615 // note --runtime-image is only for image or runtime installer. |
577 // note --runtime-image is only for image or runtime installer. |
616 throw new PackagerException("ERR_NotInstallerOption", |
578 throw new PackagerException("ERR_InvalidTypeOption", |
617 CLIOptions.PREDEFINED_RUNTIME_IMAGE.getIdWithPrefix()); |
579 CLIOptions.PREDEFINED_RUNTIME_IMAGE.getIdWithPrefix(), |
|
580 ptype); |
618 } |
581 } |
619 if (hasMainJar && hasMainModule) { |
582 if (hasMainJar && hasMainModule) { |
620 throw new PackagerException("ERR_BothMainJarAndModule"); |
583 throw new PackagerException("ERR_BothMainJarAndModule"); |
621 } |
584 } |
622 if (imageOnly && !hasMainJar && !hasMainModule) { |
585 if (imageOnly && !hasMainJar && !hasMainModule) { |
623 throw new PackagerException("ERR_NoEntryPoint"); |
586 throw new PackagerException("ERR_NoEntryPoint"); |
624 } |
587 } |
625 } |
588 } |
626 |
589 |
627 private List<jdk.jpackage.internal.Bundler> getPlatformBundlers() { |
590 private jdk.jpackage.internal.Bundler getPlatformBundler() { |
628 |
591 String bundleType = (packageType == null ? "IMAGE" : "INSTALLER"); |
629 if (platformBundlers != null) { |
592 |
630 return platformBundlers; |
|
631 } |
|
632 |
|
633 platformBundlers = new ArrayList<>(); |
|
634 for (jdk.jpackage.internal.Bundler bundler : |
593 for (jdk.jpackage.internal.Bundler bundler : |
635 Bundlers.createBundlersInstance().getBundlers( |
594 Bundlers.createBundlersInstance().getBundlers(bundleType)) { |
636 bundleType.toString())) { |
595 if ((packageType == null) || |
637 if (hasTargetFormat && deployParams.getTargetFormat() != null && |
596 packageType.equalsIgnoreCase(bundler.getID())) { |
638 !deployParams.getTargetFormat().equalsIgnoreCase( |
597 if (bundler.supported(runtimeInstaller)) { |
639 bundler.getID())) { |
598 return bundler; |
640 continue; |
599 } |
641 } |
600 } |
642 if (bundler.supported(runtimeInstaller)) { |
601 } |
643 platformBundlers.add(bundler); |
602 return null; |
644 } |
603 } |
645 } |
604 |
646 |
605 private void generateBundle(Map<String,? super Object> params) |
647 return platformBundlers; |
|
648 } |
|
649 |
|
650 private boolean generateBundle(Map<String,? super Object> params) |
|
651 throws PackagerException { |
606 throws PackagerException { |
652 |
607 |
653 boolean bundleCreated = false; |
608 boolean bundleCreated = false; |
654 |
609 |
655 // the temp-root needs to be fetched from the params early, |
610 // the temp-root needs to be fetched from the params early, |
657 // additional launchers) from generating a separate temp-root when |
612 // additional launchers) from generating a separate temp-root when |
658 // the default is used (the default is a new temp directory) |
613 // the default is used (the default is a new temp directory) |
659 // The bundler.cleanup() below would not otherwise be able to |
614 // The bundler.cleanup() below would not otherwise be able to |
660 // clean these extra (and unneeded) temp directories. |
615 // clean these extra (and unneeded) temp directories. |
661 StandardBundlerParam.TEMP_ROOT.fetchFrom(params); |
616 StandardBundlerParam.TEMP_ROOT.fetchFrom(params); |
662 List<jdk.jpackage.internal.Bundler> bundlers = getPlatformBundlers(); |
617 |
663 if (bundlers.isEmpty()) { |
618 // determine what bundler to run |
|
619 jdk.jpackage.internal.Bundler bundler = getPlatformBundler(); |
|
620 |
|
621 if (bundler == null) { |
664 throw new PackagerException("ERR_InvalidInstallerType", |
622 throw new PackagerException("ERR_InvalidInstallerType", |
665 deployParams.getTargetFormat()); |
623 deployParams.getTargetFormat()); |
666 } |
624 } |
667 PackagerException pe = null; |
625 |
668 for (jdk.jpackage.internal.Bundler bundler : bundlers) { |
626 Map<String, ? super Object> localParams = new HashMap<>(params); |
669 Map<String, ? super Object> localParams = new HashMap<>(params); |
627 try { |
670 try { |
628 bundler.validate(localParams); |
671 if (bundler.validate(localParams)) { |
629 File result = bundler.execute(localParams, deployParams.outdir); |
672 File result = |
630 if (!userProvidedBuildRoot) { |
673 bundler.execute(localParams, deployParams.outdir); |
631 bundler.cleanup(localParams); |
674 if (!userProvidedBuildRoot) { |
632 } |
675 bundler.cleanup(localParams); |
633 if (result == null) { |
676 } |
634 throw new PackagerException("MSG_BundlerFailed", |
677 if (result == null) { |
635 bundler.getID(), bundler.getName()); |
678 throw new PackagerException("MSG_BundlerFailed", |
636 } |
679 bundler.getID(), bundler.getName()); |
637 Log.verbose(MessageFormat.format( |
680 } |
638 I18N.getString("message.bundle-created"), |
681 bundleCreated = true; // at least one bundle was created |
639 bundler.getName())); |
682 } |
640 } catch (UnsupportedPlatformException upe) { |
|
641 Log.debug(upe); |
|
642 throw new PackagerException(upe, |
|
643 "MSG_BundlerPlatformException", bundler.getName()); |
|
644 } catch (ConfigException e) { |
|
645 Log.debug(e); |
|
646 if (e.getAdvice() != null) { |
|
647 throw new PackagerException(e, "MSG_BundlerConfigException", |
|
648 bundler.getName(), e.getMessage(), e.getAdvice()); |
|
649 } else { |
|
650 throw new PackagerException(e, |
|
651 "MSG_BundlerConfigExceptionNoAdvice", |
|
652 bundler.getName(), e.getMessage()); |
|
653 } |
|
654 } catch (RuntimeException re) { |
|
655 Log.debug(re); |
|
656 throw new PackagerException(re, "MSG_BundlerRuntimeException", |
|
657 bundler.getName(), re.toString()); |
|
658 } finally { |
|
659 if (userProvidedBuildRoot) { |
683 Log.verbose(MessageFormat.format( |
660 Log.verbose(MessageFormat.format( |
684 I18N.getString("message.bundle-created"), |
661 I18N.getString("message.debug-working-directory"), |
685 bundler.getName())); |
662 (new File(buildRoot)).getAbsolutePath())); |
686 } catch (UnsupportedPlatformException upe) { |
663 } |
687 Log.debug(upe); |
664 } |
688 if (pe == null) { |
|
689 pe = new PackagerException(upe, |
|
690 "MSG_BundlerPlatformException", bundler.getName()); |
|
691 } |
|
692 } catch (ConfigException e) { |
|
693 Log.debug(e); |
|
694 if (pe == null) { |
|
695 pe = (e.getAdvice() != null) ? |
|
696 new PackagerException(e, |
|
697 "MSG_BundlerConfigException", |
|
698 bundler.getName(), e.getMessage(), e.getAdvice()) : |
|
699 new PackagerException(e, |
|
700 "MSG_BundlerConfigExceptionNoAdvice", |
|
701 bundler.getName(), e.getMessage()); |
|
702 } |
|
703 } catch (RuntimeException re) { |
|
704 Log.debug(re); |
|
705 if (pe == null) { |
|
706 pe = new PackagerException(re, |
|
707 "MSG_BundlerRuntimeException", |
|
708 bundler.getName(), re.toString()); |
|
709 } |
|
710 } finally { |
|
711 if (userProvidedBuildRoot) { |
|
712 Log.verbose(MessageFormat.format( |
|
713 I18N.getString("message.debug-working-directory"), |
|
714 (new File(buildRoot)).getAbsolutePath())); |
|
715 } |
|
716 } |
|
717 } |
|
718 if (pe != null) { |
|
719 // throw packager exception only after trying all bundlers |
|
720 throw pe; |
|
721 } |
|
722 return bundleCreated; |
|
723 } |
665 } |
724 |
666 |
725 private void addResources(DeployParams deployParams, |
667 private void addResources(DeployParams deployParams, |
726 String inputdir) throws PackagerException { |
668 String inputdir) throws PackagerException { |
727 |
669 |