25 |
25 |
26 package jdk.jpackage.internal; |
26 package jdk.jpackage.internal; |
27 |
27 |
28 import java.io.*; |
28 import java.io.*; |
29 import java.nio.charset.Charset; |
29 import java.nio.charset.Charset; |
|
30 import java.nio.charset.StandardCharsets; |
30 import java.nio.file.Files; |
31 import java.nio.file.Files; |
31 import java.nio.file.Path; |
32 import java.nio.file.Path; |
32 import java.nio.file.Paths; |
33 import java.nio.file.Paths; |
33 import java.text.MessageFormat; |
34 import java.text.MessageFormat; |
34 import java.util.*; |
35 import java.util.*; |
35 import java.util.regex.Pattern; |
36 import java.util.regex.Pattern; |
36 import java.util.stream.Collectors; |
37 import java.util.stream.Collectors; |
|
38 import java.util.stream.Stream; |
37 import javax.xml.stream.XMLOutputFactory; |
39 import javax.xml.stream.XMLOutputFactory; |
38 import javax.xml.stream.XMLStreamException; |
40 import javax.xml.stream.XMLStreamException; |
39 import javax.xml.stream.XMLStreamWriter; |
41 import javax.xml.stream.XMLStreamWriter; |
40 import static jdk.jpackage.internal.OverridableResource.createResource; |
42 import static jdk.jpackage.internal.OverridableResource.createResource; |
41 import static jdk.jpackage.internal.StandardBundlerParam.*; |
43 import static jdk.jpackage.internal.StandardBundlerParam.*; |
133 String.class, |
135 String.class, |
134 VERSION::fetchFrom, |
136 VERSION::fetchFrom, |
135 (s, p) -> s |
137 (s, p) -> s |
136 ); |
138 ); |
137 |
139 |
138 public static final BundlerParamInfo<UUID> UPGRADE_UUID = |
140 private static final BundlerParamInfo<String> UPGRADE_UUID = |
139 new WindowsBundlerParam<>( |
141 new WindowsBundlerParam<>( |
140 Arguments.CLIOptions.WIN_UPGRADE_UUID.getId(), |
142 Arguments.CLIOptions.WIN_UPGRADE_UUID.getId(), |
141 UUID.class, |
143 String.class, |
142 params -> UUID.randomUUID(), |
144 null, |
143 (s, p) -> UUID.fromString(s)); |
145 (s, p) -> s); |
144 |
146 |
145 @Override |
147 @Override |
146 public String getName() { |
148 public String getName() { |
147 return I18N.getString("msi.bundler.name"); |
149 return I18N.getString("msi.bundler.name"); |
148 } |
150 } |
184 @Override |
186 @Override |
185 public boolean isDefault() { |
187 public boolean isDefault() { |
186 return false; |
188 return false; |
187 } |
189 } |
188 |
190 |
|
191 private static UUID getUpgradeCode(Map<String, ? super Object> params) { |
|
192 String upgradeCode = UPGRADE_UUID.fetchFrom(params); |
|
193 if (upgradeCode != null) { |
|
194 return UUID.fromString(upgradeCode); |
|
195 } |
|
196 return createNameUUID("UpgradeCode", params, List.of(VENDOR, APP_NAME)); |
|
197 } |
|
198 |
|
199 private static UUID getProductCode(Map<String, ? super Object> params) { |
|
200 return createNameUUID("ProductCode", params, List.of(VENDOR, APP_NAME, |
|
201 VERSION)); |
|
202 } |
|
203 |
|
204 private static UUID createNameUUID(String prefix, |
|
205 Map<String, ? super Object> params, |
|
206 List<StandardBundlerParam<String>> components) { |
|
207 String key = Stream.concat(Stream.of(prefix), components.stream().map( |
|
208 c -> c.fetchFrom(params))).collect(Collectors.joining("/")); |
|
209 return UUID.nameUUIDFromBytes(key.getBytes(StandardCharsets.UTF_8)); |
|
210 } |
|
211 |
189 @Override |
212 @Override |
190 public boolean validate(Map<String, ? super Object> params) |
213 public boolean validate(Map<String, ? super Object> params) |
191 throws ConfigException { |
214 throws ConfigException { |
192 try { |
215 try { |
193 if (wixToolset == null) { |
216 if (wixToolset == null) { |
194 wixToolset = WixTool.toolset(); |
217 wixToolset = WixTool.toolset(); |
|
218 } |
|
219 |
|
220 try { |
|
221 getUpgradeCode(params); |
|
222 } catch (IllegalArgumentException ex) { |
|
223 throw new ConfigException(ex); |
195 } |
224 } |
196 |
225 |
197 for (var toolInfo: wixToolset.values()) { |
226 for (var toolInfo: wixToolset.values()) { |
198 Log.verbose(MessageFormat.format(I18N.getString( |
227 Log.verbose(MessageFormat.format(I18N.getString( |
199 "message.tool-version"), toolInfo.path.getFileName(), |
228 "message.tool-version"), toolInfo.path.getFileName(), |
223 for (int i = 0; i < associations.size(); i++) { |
252 for (int i = 0; i < associations.size(); i++) { |
224 Map<String, ? super Object> assoc = associations.get(i); |
253 Map<String, ? super Object> assoc = associations.get(i); |
225 List<String> mimes = FA_CONTENT_TYPE.fetchFrom(assoc); |
254 List<String> mimes = FA_CONTENT_TYPE.fetchFrom(assoc); |
226 if (mimes.size() > 1) { |
255 if (mimes.size() > 1) { |
227 throw new ConfigException(MessageFormat.format( |
256 throw new ConfigException(MessageFormat.format( |
228 I18N.getString("error.too-many-content-" |
257 I18N.getString("error.too-many-content-types-for-file-association"), i), |
229 + "types-for-file-association"), i), |
258 I18N.getString("error.too-many-content-types-for-file-association.advice")); |
230 I18N.getString("error.too-many-content-" |
|
231 + "types-for-file-association.advice")); |
|
232 } |
259 } |
233 } |
260 } |
234 } |
261 } |
235 |
262 |
236 return true; |
263 return true; |
360 |
387 |
361 Map<String, String> prepareMainProjectFile( |
388 Map<String, String> prepareMainProjectFile( |
362 Map<String, ? super Object> params) throws IOException { |
389 Map<String, ? super Object> params) throws IOException { |
363 Map<String, String> data = new HashMap<>(); |
390 Map<String, String> data = new HashMap<>(); |
364 |
391 |
365 UUID productGUID = UUID.randomUUID(); |
392 final UUID productCode = getProductCode(params); |
366 |
393 final UUID upgradeCode = getUpgradeCode(params); |
367 Log.verbose(MessageFormat.format( |
394 |
368 I18N.getString("message.generated-product-guid"), |
395 data.put("JpProductCode", productCode.toString()); |
369 productGUID.toString())); |
396 data.put("JpProductUpgradeCode", upgradeCode.toString()); |
370 |
397 |
371 // we use random GUID for product itself but |
398 Log.verbose(MessageFormat.format(I18N.getString("message.product-code"), |
372 // user provided for upgrade guid |
399 productCode)); |
373 // Upgrade guid is important to decide whether it is an upgrade of |
400 Log.verbose(MessageFormat.format(I18N.getString("message.upgrade-code"), |
374 // installed app. I.e. we need it to be the same for |
401 upgradeCode)); |
375 // 2 different versions of app if possible |
402 |
376 data.put("JpProductCode", productGUID.toString()); |
403 data.put("JpAllowUpgrades", "yes"); |
377 data.put("JpProductUpgradeCode", |
|
378 UPGRADE_UUID.fetchFrom(params).toString()); |
|
379 |
|
380 if (!UPGRADE_UUID.getIsDefaultValue()) { |
|
381 data.put("JpAllowDowngrades", "yes"); |
|
382 } |
|
383 |
404 |
384 data.put("JpAppName", APP_NAME.fetchFrom(params)); |
405 data.put("JpAppName", APP_NAME.fetchFrom(params)); |
385 data.put("JpAppDescription", DESCRIPTION.fetchFrom(params)); |
406 data.put("JpAppDescription", DESCRIPTION.fetchFrom(params)); |
386 data.put("JpAppVendor", VENDOR.fetchFrom(params)); |
407 data.put("JpAppVendor", VENDOR.fetchFrom(params)); |
387 data.put("JpAppVersion", PRODUCT_VERSION.fetchFrom(params)); |
408 data.put("JpAppVersion", PRODUCT_VERSION.fetchFrom(params)); |
388 |
409 |
389 data.put("JpConfigDir", |
410 final Path configDir = CONFIG_ROOT.fetchFrom(params).toPath(); |
390 CONFIG_ROOT.fetchFrom(params).getAbsolutePath()); |
411 |
|
412 data.put("JpConfigDir", configDir.toAbsolutePath().toString()); |
391 |
413 |
392 if (MSI_SYSTEM_WIDE.fetchFrom(params)) { |
414 if (MSI_SYSTEM_WIDE.fetchFrom(params)) { |
393 data.put("JpIsSystemWide", "yes"); |
415 data.put("JpIsSystemWide", "yes"); |
394 } |
416 } |
395 |
417 |
420 fname)); |
442 fname)); |
421 } |
443 } |
422 } |
444 } |
423 |
445 |
424 createResource("main.wxs", params) |
446 createResource("main.wxs", params) |
425 .setCategory(I18N.getString("resource.wxs-file")) |
447 .setCategory(I18N.getString("resource.main-wix-file")) |
426 .saveToFile(Paths.get(getConfig_ProjectFile(params) |
448 .saveToFile(configDir.resolve("main.wxs")); |
427 .getAbsolutePath())); |
449 |
428 |
450 createResource("overrides.wxi", params) |
|
451 .setCategory(I18N.getString("resource.overrides-wix-file")) |
|
452 .saveToFile(configDir.resolve("overrides.wxi")); |
429 |
453 |
430 return data; |
454 return data; |
431 } |
|
432 |
|
433 private File getConfig_ProjectFile(Map<String, ? super Object> params) { |
|
434 return new File(CONFIG_ROOT.fetchFrom(params), "main.wxs"); |
|
435 } |
455 } |
436 |
456 |
437 private File buildMSI(Map<String, ? super Object> params, |
457 private File buildMSI(Map<String, ? super Object> params, |
438 Map<String, String> wixVars, File outdir) |
458 Map<String, String> wixVars, File outdir) |
439 throws IOException { |
459 throws IOException { |