25
26 package jdk.jpackage.internal;
27
28 import java.io.*;
29 import java.nio.charset.Charset;
30 import java.nio.file.Files;
31 import java.text.MessageFormat;
32 import java.util.*;
33 import java.util.regex.Matcher;
34 import java.util.regex.Pattern;
35
36 import static jdk.jpackage.internal.WindowsBundlerParam.*;
37
38 public class WinMsiBundler extends AbstractBundler {
39
40 private static final ResourceBundle I18N = ResourceBundle.getBundle(
41 "jdk.jpackage.internal.resources.WinResources");
42
43 public static final BundlerParamInfo<WinAppBundler> APP_BUNDLER =
44 new WindowsBundlerParam<>(
45 I18N.getString("param.msi-bundler.name"),
46 I18N.getString("param.msi-bundler.description"),
47 "win.app.bundler",
48 WinAppBundler.class,
49 params -> new WinAppBundler(),
50 null);
51
52 public static final BundlerParamInfo<Boolean> CAN_USE_WIX36 =
53 new WindowsBundlerParam<>(
54 I18N.getString("param.can-use-wix36.name"),
55 I18N.getString("param.can-use-wix36.description"),
56 "win.msi.canUseWix36",
57 Boolean.class,
58 params -> false,
59 (s, p) -> Boolean.valueOf(s));
60
61 public static final BundlerParamInfo<File> MSI_IMAGE_DIR =
62 new WindowsBundlerParam<>(
63 I18N.getString("param.image-dir.name"),
64 I18N.getString("param.image-dir.description"),
65 "win.msi.imageDir",
66 File.class,
67 params -> {
68 File imagesRoot = IMAGES_ROOT.fetchFrom(params);
69 if (!imagesRoot.exists()) imagesRoot.mkdirs();
70 return new File(imagesRoot, "win-msi.image");
71 },
72 (s, p) -> null);
73
74 public static final BundlerParamInfo<File> WIN_APP_IMAGE =
75 new WindowsBundlerParam<>(
76 I18N.getString("param.app-dir.name"),
77 I18N.getString("param.app-dir.description"),
78 "win.app.image",
79 File.class,
80 null,
81 (s, p) -> null);
82
83 public static final StandardBundlerParam<Boolean> MSI_SYSTEM_WIDE =
84 new StandardBundlerParam<>(
85 I18N.getString("param.system-wide.name"),
86 I18N.getString("param.system-wide.description"),
87 Arguments.CLIOptions.WIN_PER_USER_INSTALLATION.getId(),
88 Boolean.class,
89 params -> true, // MSIs default to system wide
90 // valueOf(null) is false,
91 // and we actually do want null
92 (s, p) -> (s == null || "null".equalsIgnoreCase(s))? null
93 : Boolean.valueOf(s)
94 );
95
96
97 public static final StandardBundlerParam<String> PRODUCT_VERSION =
98 new StandardBundlerParam<>(
99 I18N.getString("param.product-version.name"),
100 I18N.getString("param.product-version.description"),
101 "win.msi.productVersion",
102 String.class,
103 VERSION::fetchFrom,
104 (s, p) -> s
105 );
106
107 public static final BundlerParamInfo<UUID> UPGRADE_UUID =
108 new WindowsBundlerParam<>(
109 I18N.getString("param.upgrade-uuid.name"),
110 I18N.getString("param.upgrade-uuid.description"),
111 Arguments.CLIOptions.WIN_UPGRADE_UUID.getId(),
112 UUID.class,
113 params -> UUID.randomUUID(),
114 (s, p) -> UUID.fromString(s));
115
116 private static final String TOOL_CANDLE = "candle.exe";
117 private static final String TOOL_LIGHT = "light.exe";
118 // autodetect just v3.7, v3.8, 3.9, 3.10 and 3.11
119 private static final String AUTODETECT_DIRS =
120 ";C:\\Program Files (x86)\\WiX Toolset v3.11\\bin;"
121 + "C:\\Program Files\\WiX Toolset v3.11\\bin;"
122 + "C:\\Program Files (x86)\\WiX Toolset v3.10\\bin;"
123 + "C:\\Program Files\\WiX Toolset v3.10\\bin;"
124 + "C:\\Program Files (x86)\\WiX Toolset v3.9\\bin;"
125 + "C:\\Program Files\\WiX Toolset v3.9\\bin;"
126 + "C:\\Program Files (x86)\\WiX Toolset v3.8\\bin;"
127 + "C:\\Program Files\\WiX Toolset v3.8\\bin;"
128 + "C:\\Program Files (x86)\\WiX Toolset v3.7\\bin;"
129 + "C:\\Program Files\\WiX Toolset v3.7\\bin";
130
131 public static final BundlerParamInfo<String> TOOL_CANDLE_EXECUTABLE =
132 new WindowsBundlerParam<>(
133 I18N.getString("param.candle-path.name"),
134 I18N.getString("param.candle-path.description"),
135 "win.msi.candle.exe",
136 String.class,
137 params -> {
138 for (String dirString : (System.getenv("PATH") +
139 AUTODETECT_DIRS).split(";")) {
140 File f = new File(dirString.replace("\"", ""), TOOL_CANDLE);
141 if (f.isFile()) {
142 return f.toString();
143 }
144 }
145 return null;
146 },
147 null);
148
149 public static final BundlerParamInfo<String> TOOL_LIGHT_EXECUTABLE =
150 new WindowsBundlerParam<>(
151 I18N.getString("param.light-path.name"),
152 I18N.getString("param.light-path.description"),
153 "win.msi.light.exe",
154 String.class,
155 params -> {
156 for (String dirString : (System.getenv("PATH") +
157 AUTODETECT_DIRS).split(";")) {
158 File f = new File(dirString.replace("\"", ""), TOOL_LIGHT);
159 if (f.isFile()) {
160 return f.toString();
161 }
162 }
163 return null;
164 },
165 null);
166
167 public static final StandardBundlerParam<Boolean> MENU_HINT =
168 new WindowsBundlerParam<>(
169 I18N.getString("param.menu-shortcut-hint.name"),
170 I18N.getString("param.menu-shortcut-hint.description"),
171 Arguments.CLIOptions.WIN_MENU_HINT.getId(),
172 Boolean.class,
173 params -> false,
174 // valueOf(null) is false,
175 // and we actually do want null in some cases
176 (s, p) -> (s == null ||
177 "null".equalsIgnoreCase(s))? true : Boolean.valueOf(s)
178 );
179
180 public static final StandardBundlerParam<Boolean> SHORTCUT_HINT =
181 new WindowsBundlerParam<>(
182 I18N.getString("param.desktop-shortcut-hint.name"),
183 I18N.getString("param.desktop-shortcut-hint.description"),
184 Arguments.CLIOptions.WIN_SHORTCUT_HINT.getId(),
185 Boolean.class,
186 params -> false,
187 // valueOf(null) is false,
188 // and we actually do want null in some cases
189 (s, p) -> (s == null ||
190 "null".equalsIgnoreCase(s))? false : Boolean.valueOf(s)
191 );
192
193 @Override
194 public String getName() {
195 return I18N.getString("msi.bundler.name");
196 }
197
198 @Override
199 public String getDescription() {
200 return I18N.getString("msi.bundler.description");
201 }
202
203 @Override
575
576 data.put("REGISTRY_ROOT", getRegistryRoot(params));
577
578 boolean canUseWix36Features = CAN_USE_WIX36.fetchFrom(params);
579 data.put("WIX36_ONLY_START",
580 canUseWix36Features ? "" : "<!--");
581 data.put("WIX36_ONLY_END",
582 canUseWix36Features ? "" : "-->");
583
584 if (MSI_SYSTEM_WIDE.fetchFrom(params)) {
585 data.put("INSTALL_SCOPE", "perMachine");
586 } else {
587 data.put("INSTALL_SCOPE", "perUser");
588 }
589
590 data.put("PLATFORM", "x64");
591 data.put("WIN64", "yes");
592
593 data.put("UI_BLOCK", getUIBlock(params));
594
595 List<Map<String, ? super Object>> secondaryLaunchers =
596 SECONDARY_LAUNCHERS.fetchFrom(params);
597
598 StringBuilder secondaryLauncherIcons = new StringBuilder();
599 for (int i = 0; i < secondaryLaunchers.size(); i++) {
600 Map<String, ? super Object> sl = secondaryLaunchers.get(i);
601 // <Icon Id="DesktopIcon.exe" SourceFile="APPLICATION_ICON" />
602 if (SHORTCUT_HINT.fetchFrom(sl) || MENU_HINT.fetchFrom(sl)) {
603 File secondaryLauncher = new File(imageRootDir,
604 WinAppBundler.getLauncherName(sl));
605 String secondaryLauncherPath =
606 relativePath(imageRootDir, secondaryLauncher);
607 String secondaryLauncherIconPath =
608 secondaryLauncherPath.replace(".exe", ".ico");
609
610 secondaryLauncherIcons.append(" <Icon Id=\"Launcher");
611 secondaryLauncherIcons.append(i);
612 secondaryLauncherIcons.append(".exe\" SourceFile=\"");
613 secondaryLauncherIcons.append(secondaryLauncherIconPath);
614 secondaryLauncherIcons.append("\" />\r\n");
615 }
616 }
617 data.put("SECONDARY_LAUNCHER_ICONS", secondaryLauncherIcons.toString());
618
619 String wxs = RUNTIME_INSTALLER.fetchFrom(params) ?
620 MSI_PROJECT_TEMPLATE_SERVER_JRE : MSI_PROJECT_TEMPLATE;
621
622 Writer w = new BufferedWriter(
623 new FileWriter(getConfig_ProjectFile(params)));
624
625 String content = preprocessTextResource(
626 getConfig_ProjectFile(params).getName(),
627 I18N.getString("resource.wix-config-file"),
628 wxs, data, VERBOSE.fetchFrom(params),
629 RESOURCE_DIR.fetchFrom(params));
630 w.write(content);
631 w.close();
632 return true;
633 }
634 private int id;
635 private int compId;
636 private final static String LAUNCHER_ID = "LauncherId";
637
638 /**
639 * Overrides the dialog sequence in built-in dialog set "WixUI_InstallDir"
780 + " Source=\"" + relativePath(imageRootDir, f) + "\""
781 + " ProcessorArchitecture=\"x64\"" + ">");
782 if (doShortcuts && desktopShortcut) {
783 out.println(prefix
784 + " <Shortcut Id=\"desktopShortcut\" Directory="
785 + "\"DesktopFolder\""
786 + " Name=\"" + APP_NAME.fetchFrom(params)
787 + "\" WorkingDirectory=\"INSTALLDIR\""
788 + " Advertise=\"no\" Icon=\"DesktopIcon.exe\""
789 + " IconIndex=\"0\" />");
790 }
791 if (doShortcuts && menuShortcut) {
792 out.println(prefix
793 + " <Shortcut Id=\"ExeShortcut\" Directory="
794 + "\"ProgramMenuDir\""
795 + " Name=\"" + APP_NAME.fetchFrom(params)
796 + "\" Advertise=\"no\" Icon=\"StartMenuIcon.exe\""
797 + " IconIndex=\"0\" />");
798 }
799
800 List<Map<String, ? super Object>> secondaryLaunchers =
801 SECONDARY_LAUNCHERS.fetchFrom(params);
802 for (int i = 0; i < secondaryLaunchers.size(); i++) {
803 Map<String, ? super Object> sl = secondaryLaunchers.get(i);
804 File secondaryLauncherFile = new File(imageRootDir,
805 WinAppBundler.getLauncherName(sl));
806 if (f.equals(secondaryLauncherFile)) {
807 if (SHORTCUT_HINT.fetchFrom(sl)) {
808 out.println(prefix
809 + " <Shortcut Id=\"desktopShortcut"
810 + i + "\" Directory=\"DesktopFolder\""
811 + " Name=\"" + APP_NAME.fetchFrom(sl)
812 + "\" WorkingDirectory=\"INSTALLDIR\""
813 + " Advertise=\"no\" Icon=\"Launcher"
814 + i + ".exe\" IconIndex=\"0\" />");
815 }
816 if (MENU_HINT.fetchFrom(sl)) {
817 out.println(prefix
818 + " <Shortcut Id=\"ExeShortcut"
819 + i + "\" Directory=\"ProgramMenuDir\""
820 + " Name=\"" + APP_NAME.fetchFrom(sl)
821 + "\" Advertise=\"no\" Icon=\"Launcher"
822 + i + ".exe\" IconIndex=\"0\" />");
823 // Should we allow different menu groups? Not for now.
824 }
825 }
826 }
1015 } else {
1016 return filePath;
1017 }
1018 }
1019
1020 return null;
1021 }
1022
1023 private boolean prepareWiXConfig(
1024 Map<String, ? super Object> params) throws IOException {
1025 return prepareMainProjectFile(params) && prepareContentList(params);
1026
1027 }
1028 private final static String MSI_PROJECT_TEMPLATE = "template.wxs";
1029 private final static String MSI_PROJECT_TEMPLATE_SERVER_JRE =
1030 "template.jre.wxs";
1031 private final static String MSI_PROJECT_CONTENT_FILE = "bundle.wxi";
1032
1033 private File buildMSI(Map<String, ? super Object> params, File outdir)
1034 throws IOException {
1035 File tmpDir = new File(BUILD_ROOT.fetchFrom(params), "tmp");
1036 File candleOut = new File(
1037 tmpDir, APP_NAME.fetchFrom(params) +".wixobj");
1038 File msiOut = new File(
1039 outdir, INSTALLER_FILE_NAME.fetchFrom(params) + ".msi");
1040
1041 Log.verbose(MessageFormat.format(I18N.getString(
1042 "message.preparing-msi-config"), msiOut.getAbsolutePath()));
1043
1044 msiOut.getParentFile().mkdirs();
1045
1046 // run candle
1047 ProcessBuilder pb = new ProcessBuilder(
1048 TOOL_CANDLE_EXECUTABLE.fetchFrom(params),
1049 "-nologo",
1050 getConfig_ProjectFile(params).getAbsolutePath(),
1051 "-ext", "WixUtilExtension",
1052 "-out", candleOut.getAbsolutePath());
1053 pb = pb.directory(WIN_APP_IMAGE.fetchFrom(params));
1054 IOUtils.exec(pb, false);
1055
|
25
26 package jdk.jpackage.internal;
27
28 import java.io.*;
29 import java.nio.charset.Charset;
30 import java.nio.file.Files;
31 import java.text.MessageFormat;
32 import java.util.*;
33 import java.util.regex.Matcher;
34 import java.util.regex.Pattern;
35
36 import static jdk.jpackage.internal.WindowsBundlerParam.*;
37
38 public class WinMsiBundler extends AbstractBundler {
39
40 private static final ResourceBundle I18N = ResourceBundle.getBundle(
41 "jdk.jpackage.internal.resources.WinResources");
42
43 public static final BundlerParamInfo<WinAppBundler> APP_BUNDLER =
44 new WindowsBundlerParam<>(
45 "win.app.bundler",
46 WinAppBundler.class,
47 params -> new WinAppBundler(),
48 null);
49
50 public static final BundlerParamInfo<Boolean> CAN_USE_WIX36 =
51 new WindowsBundlerParam<>(
52 "win.msi.canUseWix36",
53 Boolean.class,
54 params -> false,
55 (s, p) -> Boolean.valueOf(s));
56
57 public static final BundlerParamInfo<File> MSI_IMAGE_DIR =
58 new WindowsBundlerParam<>(
59 "win.msi.imageDir",
60 File.class,
61 params -> {
62 File imagesRoot = IMAGES_ROOT.fetchFrom(params);
63 if (!imagesRoot.exists()) imagesRoot.mkdirs();
64 return new File(imagesRoot, "win-msi.image");
65 },
66 (s, p) -> null);
67
68 public static final BundlerParamInfo<File> WIN_APP_IMAGE =
69 new WindowsBundlerParam<>(
70 "win.app.image",
71 File.class,
72 null,
73 (s, p) -> null);
74
75 public static final StandardBundlerParam<Boolean> MSI_SYSTEM_WIDE =
76 new StandardBundlerParam<>(
77 Arguments.CLIOptions.WIN_PER_USER_INSTALLATION.getId(),
78 Boolean.class,
79 params -> true, // MSIs default to system wide
80 // valueOf(null) is false,
81 // and we actually do want null
82 (s, p) -> (s == null || "null".equalsIgnoreCase(s))? null
83 : Boolean.valueOf(s)
84 );
85
86
87 public static final StandardBundlerParam<String> PRODUCT_VERSION =
88 new StandardBundlerParam<>(
89 "win.msi.productVersion",
90 String.class,
91 VERSION::fetchFrom,
92 (s, p) -> s
93 );
94
95 public static final BundlerParamInfo<UUID> UPGRADE_UUID =
96 new WindowsBundlerParam<>(
97 Arguments.CLIOptions.WIN_UPGRADE_UUID.getId(),
98 UUID.class,
99 params -> UUID.randomUUID(),
100 (s, p) -> UUID.fromString(s));
101
102 private static final String TOOL_CANDLE = "candle.exe";
103 private static final String TOOL_LIGHT = "light.exe";
104 // autodetect just v3.7, v3.8, 3.9, 3.10 and 3.11
105 private static final String AUTODETECT_DIRS =
106 ";C:\\Program Files (x86)\\WiX Toolset v3.11\\bin;"
107 + "C:\\Program Files\\WiX Toolset v3.11\\bin;"
108 + "C:\\Program Files (x86)\\WiX Toolset v3.10\\bin;"
109 + "C:\\Program Files\\WiX Toolset v3.10\\bin;"
110 + "C:\\Program Files (x86)\\WiX Toolset v3.9\\bin;"
111 + "C:\\Program Files\\WiX Toolset v3.9\\bin;"
112 + "C:\\Program Files (x86)\\WiX Toolset v3.8\\bin;"
113 + "C:\\Program Files\\WiX Toolset v3.8\\bin;"
114 + "C:\\Program Files (x86)\\WiX Toolset v3.7\\bin;"
115 + "C:\\Program Files\\WiX Toolset v3.7\\bin";
116
117 public static final BundlerParamInfo<String> TOOL_CANDLE_EXECUTABLE =
118 new WindowsBundlerParam<>(
119 "win.msi.candle.exe",
120 String.class,
121 params -> {
122 for (String dirString : (System.getenv("PATH") +
123 AUTODETECT_DIRS).split(";")) {
124 File f = new File(dirString.replace("\"", ""), TOOL_CANDLE);
125 if (f.isFile()) {
126 return f.toString();
127 }
128 }
129 return null;
130 },
131 null);
132
133 public static final BundlerParamInfo<String> TOOL_LIGHT_EXECUTABLE =
134 new WindowsBundlerParam<>(
135 "win.msi.light.exe",
136 String.class,
137 params -> {
138 for (String dirString : (System.getenv("PATH") +
139 AUTODETECT_DIRS).split(";")) {
140 File f = new File(dirString.replace("\"", ""), TOOL_LIGHT);
141 if (f.isFile()) {
142 return f.toString();
143 }
144 }
145 return null;
146 },
147 null);
148
149 public static final StandardBundlerParam<Boolean> MENU_HINT =
150 new WindowsBundlerParam<>(
151 Arguments.CLIOptions.WIN_MENU_HINT.getId(),
152 Boolean.class,
153 params -> false,
154 // valueOf(null) is false,
155 // and we actually do want null in some cases
156 (s, p) -> (s == null ||
157 "null".equalsIgnoreCase(s))? true : Boolean.valueOf(s)
158 );
159
160 public static final StandardBundlerParam<Boolean> SHORTCUT_HINT =
161 new WindowsBundlerParam<>(
162 Arguments.CLIOptions.WIN_SHORTCUT_HINT.getId(),
163 Boolean.class,
164 params -> false,
165 // valueOf(null) is false,
166 // and we actually do want null in some cases
167 (s, p) -> (s == null ||
168 "null".equalsIgnoreCase(s))? false : Boolean.valueOf(s)
169 );
170
171 @Override
172 public String getName() {
173 return I18N.getString("msi.bundler.name");
174 }
175
176 @Override
177 public String getDescription() {
178 return I18N.getString("msi.bundler.description");
179 }
180
181 @Override
553
554 data.put("REGISTRY_ROOT", getRegistryRoot(params));
555
556 boolean canUseWix36Features = CAN_USE_WIX36.fetchFrom(params);
557 data.put("WIX36_ONLY_START",
558 canUseWix36Features ? "" : "<!--");
559 data.put("WIX36_ONLY_END",
560 canUseWix36Features ? "" : "-->");
561
562 if (MSI_SYSTEM_WIDE.fetchFrom(params)) {
563 data.put("INSTALL_SCOPE", "perMachine");
564 } else {
565 data.put("INSTALL_SCOPE", "perUser");
566 }
567
568 data.put("PLATFORM", "x64");
569 data.put("WIN64", "yes");
570
571 data.put("UI_BLOCK", getUIBlock(params));
572
573 List<Map<String, ? super Object>> addLaunchers =
574 ADD_LAUNCHERS.fetchFrom(params);
575
576 StringBuilder addLauncherIcons = new StringBuilder();
577 for (int i = 0; i < addLaunchers.size(); i++) {
578 Map<String, ? super Object> sl = addLaunchers.get(i);
579 // <Icon Id="DesktopIcon.exe" SourceFile="APPLICATION_ICON" />
580 if (SHORTCUT_HINT.fetchFrom(sl) || MENU_HINT.fetchFrom(sl)) {
581 File addLauncher = new File(imageRootDir,
582 WinAppBundler.getLauncherName(sl));
583 String addLauncherPath =
584 relativePath(imageRootDir, addLauncher);
585 String addLauncherIconPath =
586 addLauncherPath.replace(".exe", ".ico");
587
588 addLauncherIcons.append(" <Icon Id=\"Launcher");
589 addLauncherIcons.append(i);
590 addLauncherIcons.append(".exe\" SourceFile=\"");
591 addLauncherIcons.append(addLauncherIconPath);
592 addLauncherIcons.append("\" />\r\n");
593 }
594 }
595 data.put("ADD_LAUNCHER_ICONS", addLauncherIcons.toString());
596
597 String wxs = StandardBundlerParam.isRuntimeInstaller(params) ?
598 MSI_PROJECT_TEMPLATE_SERVER_JRE : MSI_PROJECT_TEMPLATE;
599
600 Writer w = new BufferedWriter(
601 new FileWriter(getConfig_ProjectFile(params)));
602
603 String content = preprocessTextResource(
604 getConfig_ProjectFile(params).getName(),
605 I18N.getString("resource.wix-config-file"),
606 wxs, data, VERBOSE.fetchFrom(params),
607 RESOURCE_DIR.fetchFrom(params));
608 w.write(content);
609 w.close();
610 return true;
611 }
612 private int id;
613 private int compId;
614 private final static String LAUNCHER_ID = "LauncherId";
615
616 /**
617 * Overrides the dialog sequence in built-in dialog set "WixUI_InstallDir"
758 + " Source=\"" + relativePath(imageRootDir, f) + "\""
759 + " ProcessorArchitecture=\"x64\"" + ">");
760 if (doShortcuts && desktopShortcut) {
761 out.println(prefix
762 + " <Shortcut Id=\"desktopShortcut\" Directory="
763 + "\"DesktopFolder\""
764 + " Name=\"" + APP_NAME.fetchFrom(params)
765 + "\" WorkingDirectory=\"INSTALLDIR\""
766 + " Advertise=\"no\" Icon=\"DesktopIcon.exe\""
767 + " IconIndex=\"0\" />");
768 }
769 if (doShortcuts && menuShortcut) {
770 out.println(prefix
771 + " <Shortcut Id=\"ExeShortcut\" Directory="
772 + "\"ProgramMenuDir\""
773 + " Name=\"" + APP_NAME.fetchFrom(params)
774 + "\" Advertise=\"no\" Icon=\"StartMenuIcon.exe\""
775 + " IconIndex=\"0\" />");
776 }
777
778 List<Map<String, ? super Object>> addLaunchers =
779 ADD_LAUNCHERS.fetchFrom(params);
780 for (int i = 0; i < addLaunchers.size(); i++) {
781 Map<String, ? super Object> sl = addLaunchers.get(i);
782 File addLauncherFile = new File(imageRootDir,
783 WinAppBundler.getLauncherName(sl));
784 if (f.equals(addLauncherFile)) {
785 if (SHORTCUT_HINT.fetchFrom(sl)) {
786 out.println(prefix
787 + " <Shortcut Id=\"desktopShortcut"
788 + i + "\" Directory=\"DesktopFolder\""
789 + " Name=\"" + APP_NAME.fetchFrom(sl)
790 + "\" WorkingDirectory=\"INSTALLDIR\""
791 + " Advertise=\"no\" Icon=\"Launcher"
792 + i + ".exe\" IconIndex=\"0\" />");
793 }
794 if (MENU_HINT.fetchFrom(sl)) {
795 out.println(prefix
796 + " <Shortcut Id=\"ExeShortcut"
797 + i + "\" Directory=\"ProgramMenuDir\""
798 + " Name=\"" + APP_NAME.fetchFrom(sl)
799 + "\" Advertise=\"no\" Icon=\"Launcher"
800 + i + ".exe\" IconIndex=\"0\" />");
801 // Should we allow different menu groups? Not for now.
802 }
803 }
804 }
993 } else {
994 return filePath;
995 }
996 }
997
998 return null;
999 }
1000
1001 private boolean prepareWiXConfig(
1002 Map<String, ? super Object> params) throws IOException {
1003 return prepareMainProjectFile(params) && prepareContentList(params);
1004
1005 }
1006 private final static String MSI_PROJECT_TEMPLATE = "template.wxs";
1007 private final static String MSI_PROJECT_TEMPLATE_SERVER_JRE =
1008 "template.jre.wxs";
1009 private final static String MSI_PROJECT_CONTENT_FILE = "bundle.wxi";
1010
1011 private File buildMSI(Map<String, ? super Object> params, File outdir)
1012 throws IOException {
1013 File tmpDir = new File(TEMP_ROOT.fetchFrom(params), "tmp");
1014 File candleOut = new File(
1015 tmpDir, APP_NAME.fetchFrom(params) +".wixobj");
1016 File msiOut = new File(
1017 outdir, INSTALLER_FILE_NAME.fetchFrom(params) + ".msi");
1018
1019 Log.verbose(MessageFormat.format(I18N.getString(
1020 "message.preparing-msi-config"), msiOut.getAbsolutePath()));
1021
1022 msiOut.getParentFile().mkdirs();
1023
1024 // run candle
1025 ProcessBuilder pb = new ProcessBuilder(
1026 TOOL_CANDLE_EXECUTABLE.fetchFrom(params),
1027 "-nologo",
1028 getConfig_ProjectFile(params).getAbsolutePath(),
1029 "-ext", "WixUtilExtension",
1030 "-out", candleOut.getAbsolutePath());
1031 pb = pb.directory(WIN_APP_IMAGE.fetchFrom(params));
1032 IOUtils.exec(pb, false);
1033
|