8232919 : If user installs msi and exe, two installations are found in Add/Remove
Submitted-by: asemenyuk
Reviewed-by: aherrick, almatvee
--- a/make/CompileJavaModules.gmk Mon Nov 04 14:57:27 2019 -0500
+++ b/make/CompileJavaModules.gmk Mon Nov 04 15:06:01 2019 -0500
@@ -381,7 +381,7 @@
################################################################################
jdk.jpackage_COPY += .gif .png .txt .spec .script .prerm .preinst .postrm .postinst .list .sh \
- .desktop .copyright .control .plist .template .icns .scpt .entitlements .wxs .wxl .ico .bmp
+ .desktop .copyright .control .plist .template .icns .scpt .entitlements .wxs .wxl .wxi .ico .bmp
jdk.jpackage_CLEAN += .properties
--- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java Mon Nov 04 14:57:27 2019 -0500
+++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinAppBundler.java Mon Nov 04 15:06:01 2019 -0500
@@ -31,7 +31,6 @@
import java.util.*;
import static jdk.jpackage.internal.WindowsBundlerParam.*;
-import static jdk.jpackage.internal.WinMsiBundler.WIN_APP_IMAGE;
public class WinAppBundler extends AbstractImageBundler {
--- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java Mon Nov 04 14:57:27 2019 -0500
+++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java Mon Nov 04 15:06:01 2019 -0500
@@ -27,6 +27,7 @@
import java.io.*;
import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -34,6 +35,7 @@
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
@@ -135,12 +137,12 @@
(s, p) -> s
);
- public static final BundlerParamInfo<UUID> UPGRADE_UUID =
+ private static final BundlerParamInfo<String> UPGRADE_UUID =
new WindowsBundlerParam<>(
Arguments.CLIOptions.WIN_UPGRADE_UUID.getId(),
- UUID.class,
- params -> UUID.randomUUID(),
- (s, p) -> UUID.fromString(s));
+ String.class,
+ null,
+ (s, p) -> s);
@Override
public String getName() {
@@ -186,6 +188,27 @@
return false;
}
+ private static UUID getUpgradeCode(Map<String, ? super Object> params) {
+ String upgradeCode = UPGRADE_UUID.fetchFrom(params);
+ if (upgradeCode != null) {
+ return UUID.fromString(upgradeCode);
+ }
+ return createNameUUID("UpgradeCode", params, List.of(VENDOR, APP_NAME));
+ }
+
+ private static UUID getProductCode(Map<String, ? super Object> params) {
+ return createNameUUID("ProductCode", params, List.of(VENDOR, APP_NAME,
+ VERSION));
+ }
+
+ private static UUID createNameUUID(String prefix,
+ Map<String, ? super Object> params,
+ List<StandardBundlerParam<String>> components) {
+ String key = Stream.concat(Stream.of(prefix), components.stream().map(
+ c -> c.fetchFrom(params))).collect(Collectors.joining("/"));
+ return UUID.nameUUIDFromBytes(key.getBytes(StandardCharsets.UTF_8));
+ }
+
@Override
public boolean validate(Map<String, ? super Object> params)
throws ConfigException {
@@ -194,6 +217,12 @@
wixToolset = WixTool.toolset();
}
+ try {
+ getUpgradeCode(params);
+ } catch (IllegalArgumentException ex) {
+ throw new ConfigException(ex);
+ }
+
for (var toolInfo: wixToolset.values()) {
Log.verbose(MessageFormat.format(I18N.getString(
"message.tool-version"), toolInfo.path.getFileName(),
@@ -225,10 +254,8 @@
List<String> mimes = FA_CONTENT_TYPE.fetchFrom(assoc);
if (mimes.size() > 1) {
throw new ConfigException(MessageFormat.format(
- I18N.getString("error.too-many-content-"
- + "types-for-file-association"), i),
- I18N.getString("error.too-many-content-"
- + "types-for-file-association.advice"));
+ I18N.getString("error.too-many-content-types-for-file-association"), i),
+ I18N.getString("error.too-many-content-types-for-file-association.advice"));
}
}
}
@@ -362,32 +389,27 @@
Map<String, ? super Object> params) throws IOException {
Map<String, String> data = new HashMap<>();
- UUID productGUID = UUID.randomUUID();
+ final UUID productCode = getProductCode(params);
+ final UUID upgradeCode = getUpgradeCode(params);
- Log.verbose(MessageFormat.format(
- I18N.getString("message.generated-product-guid"),
- productGUID.toString()));
+ data.put("JpProductCode", productCode.toString());
+ data.put("JpProductUpgradeCode", upgradeCode.toString());
- // we use random GUID for product itself but
- // user provided for upgrade guid
- // Upgrade guid is important to decide whether it is an upgrade of
- // installed app. I.e. we need it to be the same for
- // 2 different versions of app if possible
- data.put("JpProductCode", productGUID.toString());
- data.put("JpProductUpgradeCode",
- UPGRADE_UUID.fetchFrom(params).toString());
+ Log.verbose(MessageFormat.format(I18N.getString("message.product-code"),
+ productCode));
+ Log.verbose(MessageFormat.format(I18N.getString("message.upgrade-code"),
+ upgradeCode));
- if (!UPGRADE_UUID.getIsDefaultValue()) {
- data.put("JpAllowDowngrades", "yes");
- }
+ data.put("JpAllowUpgrades", "yes");
data.put("JpAppName", APP_NAME.fetchFrom(params));
data.put("JpAppDescription", DESCRIPTION.fetchFrom(params));
data.put("JpAppVendor", VENDOR.fetchFrom(params));
data.put("JpAppVersion", PRODUCT_VERSION.fetchFrom(params));
- data.put("JpConfigDir",
- CONFIG_ROOT.fetchFrom(params).getAbsolutePath());
+ final Path configDir = CONFIG_ROOT.fetchFrom(params).toPath();
+
+ data.put("JpConfigDir", configDir.toAbsolutePath().toString());
if (MSI_SYSTEM_WIDE.fetchFrom(params)) {
data.put("JpIsSystemWide", "yes");
@@ -422,18 +444,16 @@
}
createResource("main.wxs", params)
- .setCategory(I18N.getString("resource.wxs-file"))
- .saveToFile(Paths.get(getConfig_ProjectFile(params)
- .getAbsolutePath()));
+ .setCategory(I18N.getString("resource.main-wix-file"))
+ .saveToFile(configDir.resolve("main.wxs"));
+ createResource("overrides.wxi", params)
+ .setCategory(I18N.getString("resource.overrides-wix-file"))
+ .saveToFile(configDir.resolve("overrides.wxi"));
return data;
}
- private File getConfig_ProjectFile(Map<String, ? super Object> params) {
- return new File(CONFIG_ROOT.fetchFrom(params), "main.wxs");
- }
-
private File buildMSI(Map<String, ? super Object> params,
Map<String, String> wixVars, File outdir)
throws IOException {
--- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/MsiInstallerStrings_en.wxl Mon Nov 04 14:57:27 2019 -0500
+++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/MsiInstallerStrings_en.wxl Mon Nov 04 15:06:01 2019 -0500
@@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization" Codepage="1252">
<String Id="message.install.dir.exist">The folder [INSTALLDIR] already exist. Would you like to install to that folder anyway?</String>
+ <String Id="MainFeatureTitle">Main Feature</String>
+ <String Id="DowngradeErrorMessage">A higher version of [ProductName] is already installed. Downgrades disabled. Setup will now exit.</String>
+ <String Id="DisallowUpgradeErrorMessage">A lower version of [ProductName] is already installed. Upgrades disabled. Setup will now exit.</String>
</WixLocalization>
--- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/MsiInstallerStrings_ja.wxl Mon Nov 04 14:57:27 2019 -0500
+++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/MsiInstallerStrings_ja.wxl Mon Nov 04 15:06:01 2019 -0500
@@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
-<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization" Codepage="1252">
+<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization" Codepage="932">
<String Id="message.install.dir.exist">The folder [INSTALLDIR] already exist. Would you like to install to that folder anyway?</String>
+ <String Id="MainFeatureTitle">Main Feature</String>
+ <String Id="DowngradeErrorMessage">A higher version of [ProductName] is already installed. Downgrades disabled. Setup will now exit.</String>
+ <String Id="DisallowUpgradeErrorMessage">A lower version of [ProductName] is already installed. Upgrades disabled. Setup will now exit.</String>
</WixLocalization>
--- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/MsiInstallerStrings_zh_CN.wxl Mon Nov 04 14:57:27 2019 -0500
+++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/MsiInstallerStrings_zh_CN.wxl Mon Nov 04 15:06:01 2019 -0500
@@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
-<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization" Codepage="1252">
+<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization" Codepage="936">
<String Id="message.install.dir.exist">The folder [INSTALLDIR] already exist. Would you like to install to that folder anyway?</String>
+ <String Id="MainFeatureTitle">Main Feature</String>
+ <String Id="DowngradeErrorMessage">A higher version of [ProductName] is already installed. Downgrades disabled. Setup will now exit.</String>
+ <String Id="DisallowUpgradeErrorMessage">A lower version of [ProductName] is already installed. Upgrades disabled. Setup will now exit.</String>
</WixLocalization>
--- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties Mon Nov 04 14:57:27 2019 -0500
+++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties Mon Nov 04 15:06:01 2019 -0500
@@ -35,7 +35,8 @@
resource.post-app-image-script=script to run after application image is populated
resource.post-msi-script=script to run after msi file for exe installer is created
resource.wxl-file-name=MsiInstallerStrings_en.wxl
-resource.wxs-file=Main wxs project file
+resource.main-wix-file=Main WiX project file
+resource.overrides-wix-file=Overrides WiX project file
error.no-wix-tools=Can not find WiX tools (light.exe, candle.exe)
error.no-wix-tools.advice=Download WiX 3.0 or later from https://wixtoolset.org and add it to the PATH.
@@ -58,7 +59,8 @@
message.wrong-tool-version=Detected [{0}] version {1} but version {2} is required.
message.version-string-too-many-components=Version sting may have up to 3 components - major.minor.build .
message.use-wix36-features=WiX {0} detected. Enabling advanced cleanup action.
-message.generated-product-guid=Generated product GUID: {0}.
+message.product-code=MSI ProductCode: {0}.
+message.upgrade-code=MSI UpgradeCode: {0}.
message.preparing-msi-config=Preparing MSI config: {0}.
message.generating-msi=Generating MSI: {0}.
message.invalid.install.dir=Warning: Invalid install directory {0}. Install directory should be a relative sub-path under the default installation location such as "Program Files". Defaulting to application name "{1}".
--- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources_ja.properties Mon Nov 04 14:57:27 2019 -0500
+++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources_ja.properties Mon Nov 04 15:06:01 2019 -0500
@@ -35,7 +35,8 @@
resource.post-app-image-script=script to run after application image is populated
resource.post-msi-script=script to run after msi file for exe installer is created
resource.wxl-file-name=MsiInstallerStrings_en.wxl
-resource.wxs-file=Main wxs project file
+resource.main-wix-file=Main WiX project file
+resource.overrides-wix-file=Overrides WiX project file
error.no-wix-tools=Can not find WiX tools (light.exe, candle.exe)
error.no-wix-tools.advice=Download WiX 3.0 or later from https://wixtoolset.org and add it to the PATH.
@@ -58,7 +59,8 @@
message.wrong-tool-version=Detected [{0}] version {1} but version {2} is required.
message.version-string-too-many-components=Version sting may have up to 3 components - major.minor.build .
message.use-wix36-features=WiX {0} detected. Enabling advanced cleanup action.
-message.generated-product-guid=Generated product GUID: {0}.
+message.product-code=MSI ProductCode: {0}.
+message.upgrade-code=MSI UpgradeCode: {0}.
message.preparing-msi-config=Preparing MSI config: {0}.
message.generating-msi=Generating MSI: {0}.
message.invalid.install.dir=Warning: Invalid install directory {0}. Install directory should be a relative sub-path under the default installation location such as "Program Files". Defaulting to application name "{1}".
--- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources_zh_CN.properties Mon Nov 04 14:57:27 2019 -0500
+++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources_zh_CN.properties Mon Nov 04 15:06:01 2019 -0500
@@ -35,7 +35,8 @@
resource.post-app-image-script=script to run after application image is populated
resource.post-msi-script=script to run after msi file for exe installer is created
resource.wxl-file-name=MsiInstallerStrings_en.wxl
-resource.wxs-file=Main wxs project file
+resource.main-wix-file=Main WiX project file
+resource.overrides-wix-file=Overrides WiX project file
error.no-wix-tools=Can not find WiX tools (light.exe, candle.exe)
error.no-wix-tools.advice=Download WiX 3.0 or later from https://wixtoolset.org and add it to the PATH.
@@ -58,7 +59,8 @@
message.wrong-tool-version=Detected [{0}] version {1} but version {2} is required.
message.version-string-too-many-components=Version sting may have up to 3 components - major.minor.build .
message.use-wix36-features=WiX {0} detected. Enabling advanced cleanup action.
-message.generated-product-guid=Generated product GUID: {0}.
+message.product-code=MSI ProductCode: {0}.
+message.upgrade-code=MSI UpgradeCode: {0}.
message.preparing-msi-config=Preparing MSI config: {0}.
message.generating-msi=Generating MSI: {0}.
message.invalid.install.dir=Warning: Invalid install directory {0}. Install directory should be a relative sub-path under the default installation location such as "Program Files". Defaulting to application name "{1}".
--- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/main.wxs Mon Nov 04 14:57:27 2019 -0500
+++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/main.wxs Mon Nov 04 15:06:01 2019 -0500
@@ -8,24 +8,74 @@
<?define JpInstallScope="perUser"?>
<?endif?>
- <Product Id="$(var.JpProductCode)" Name="$(var.JpAppName)"
- Language="1033" Version="$(var.JpAppVersion)"
- Manufacturer="$(var.JpAppVendor)"
- UpgradeCode="$(var.JpProductUpgradeCode)">
- <Package Description="$(var.JpAppDescription)"
- Manufacturer="$(var.JpAppVendor)"
- InstallerVersion="200" Compressed="yes"
- InstallScope="$(var.JpInstallScope)" Platform="x64"/>
- <Media Id="1" Cabinet="simple.cab" EmbedCab="yes" />
+ <?define JpProductLanguage=1033 ?>
+ <?define JpInstallerVersion=200 ?>
+ <?define JpCompressedMsi=yes ?>
+
+ <?include $(var.JpConfigDir)/overrides.wxi ?>
+
+ <Product
+ Id="$(var.JpProductCode)"
+ Name="$(var.JpAppName)"
+ Language="$(var.JpProductLanguage)"
+ Version="$(var.JpAppVersion)"
+ Manufacturer="$(var.JpAppVendor)"
+ UpgradeCode="$(var.JpProductUpgradeCode)">
+
+ <Package
+ Description="$(var.JpAppDescription)"
+ Manufacturer="$(var.JpAppVendor)"
+ InstallerVersion="$(var.JpInstallerVersion)"
+ Compressed="$(var.JpCompressedMsi)"
+ InstallScope="$(var.JpInstallScope)" Platform="x64"
+ />
+
+ <Media Id="1" Cabinet="Data.cab" EmbedCab="yes" />
<?ifdef JpAllowDowngrades ?>
- <MajorUpgrade AllowDowngrades="yes"/>
+ <?ifdef JpAllowUpgrades ?>
+ <MajorUpgrade
+ AllowDowngrades="yes"
+ Disallow="no"
+ />
+ <?endif?>
+ <?endif?>
+
+ <?ifdef JpAllowDowngrades ?>
+ <?ifndef JpAllowUpgrades ?>
+ <MajorUpgrade
+ AllowDowngrades="yes"
+ Disallow="yes"
+ DisallowUpgradeErrorMessage="!(loc.DisallowUpgradeErrorMessage)"
+ />
+ <?endif?>
+ <?endif?>
+
+ <?ifndef JpAllowDowngrades ?>
+ <?ifdef JpAllowUpgrades ?>
+ <MajorUpgrade
+ AllowDowngrades="no"
+ Disallow="no"
+ DowngradeErrorMessage="!(loc.DowngradeErrorMessage)"
+ />
+ <?endif?>
+ <?endif?>
+
+ <?ifndef JpAllowDowngrades ?>
+ <?ifndef JpAllowUpgrades ?>
+ <MajorUpgrade
+ AllowDowngrades="no"
+ Disallow="yes"
+ DowngradeErrorMessage="!(loc.DowngradeErrorMessage)"
+ DisallowUpgradeErrorMessage="!(loc.DisallowUpgradeErrorMessage)"
+ />
+ <?endif?>
<?endif?>
<!-- Standard required root -->
<Directory Id="TARGETDIR" Name="SourceDir"/>
- <Feature Id="DefaultFeature" Title="Main Feature" Level="1">
+ <Feature Id="DefaultFeature" Title="!(loc.MainFeatureTitle)" Level="1">
<ComponentGroupRef Id="Shortcuts"/>
<ComponentGroupRef Id="Files"/>
<ComponentGroupRef Id="FileAssociations"/>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/overrides.wxi Mon Nov 04 15:06:01 2019 -0500
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Stub by design -->
+<Include/>
\ No newline at end of file
--- a/test/jdk/tools/jpackage/windows/WinResourceTest.java Mon Nov 04 14:57:27 2019 -0500
+++ b/test/jdk/tools/jpackage/windows/WinResourceTest.java Mon Nov 04 15:06:01 2019 -0500
@@ -27,6 +27,7 @@
import jdk.jpackage.test.PackageTest;
import jdk.jpackage.test.PackageType;
import jdk.jpackage.test.Annotations.Test;
+import jdk.jpackage.test.Annotations.Parameters;
import java.util.List;
/**
@@ -48,8 +49,22 @@
*/
public class WinResourceTest {
+
+ public WinResourceTest(String wixSource, String expectedLogMessage) {
+ this.wixSource = wixSource;
+ this.expectedLogMessage = expectedLogMessage;
+ }
+
+ @Parameters
+ public static List<Object[]> data() {
+ return List.of(new Object[][]{
+ {"main.wxs", "Using custom package resource [Main WiX project file]"},
+ {"overrides.wxi", "Using custom package resource [Overrides WiX project file]"},
+ });
+ }
+
@Test
- public static void test() throws IOException {
+ public void test() throws IOException {
new PackageTest()
.forTypes(PackageType.WINDOWS)
.configureHelloApp()
@@ -61,14 +76,14 @@
cmd.setFakeRuntime().saveConsoleOutput(true);
cmd.addArguments("--resource-dir", resourceDir);
- // Create invalid main wxs file in a resource dir.
- TKit.createTextFile(resourceDir.resolve("main.wxs"), List.of(
- "any string that is an invalid wxs file"));
+ // Create invalid WiX source file in a resource dir.
+ TKit.createTextFile(resourceDir.resolve(wixSource), List.of(
+ "any string that is an invalid WiX source file"));
})
.addBundleVerifier((cmd, result) -> {
// Assert jpackage picked custom main.wxs and failed as expected by
// examining its output
- TKit.assertTextStream("Using custom package resource [Main wxs project file]")
+ TKit.assertTextStream(expectedLogMessage)
.predicate(String::startsWith)
.apply(result.getOutput().stream());
TKit.assertTextStream("error CNDL0104 : Not a valid source file")
@@ -77,4 +92,7 @@
.setExpectedExitCode(1)
.run();
}
+
+ final String wixSource;
+ final String expectedLogMessage;
}