mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-15 16:44:36 +02:00
8150442: Enforce Supported Platforms in Packager for MSI bundles
Reviewed-by: almatvee, cstein
This commit is contained in:
parent
642816538f
commit
e7157d174c
14 changed files with 404 additions and 10 deletions
|
@ -29,7 +29,7 @@ DISABLED_WARNINGS_java += dangling-doc-comments
|
||||||
|
|
||||||
COPY += .gif .png .txt .spec .script .prerm .preinst \
|
COPY += .gif .png .txt .spec .script .prerm .preinst \
|
||||||
.postrm .postinst .list .sh .desktop .copyright .control .plist .template \
|
.postrm .postinst .list .sh .desktop .copyright .control .plist .template \
|
||||||
.icns .scpt .wxs .wxl .wxi .ico .bmp .tiff .service .xsl
|
.icns .scpt .wxs .wxl .wxi .wxf .ico .bmp .tiff .service .xsl
|
||||||
|
|
||||||
CLEAN += .properties
|
CLEAN += .properties
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
# Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
|
# Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
#
|
#
|
||||||
# This code is free software; you can redistribute it and/or modify it
|
# This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -661,6 +661,12 @@ jpackage will lookup files by specific names in the resource directory.
|
||||||
|
|
||||||
: WiX project file for installer UI
|
: WiX project file for installer UI
|
||||||
|
|
||||||
|
`os-condition.wxf`
|
||||||
|
|
||||||
|
: WiX project file with the condition to block installation on older versions of Windows
|
||||||
|
|
||||||
|
Default resource is *os-condition.wxf*
|
||||||
|
|
||||||
`wix-conv.xsl`
|
`wix-conv.xsl`
|
||||||
|
|
||||||
: WiX source code converter. Used for converting WiX sources from WiX v3 to v4 schema when WiX v4 or newer is used
|
: WiX source code converter. Used for converting WiX sources from WiX v3 to v4 schema when WiX v4 or newer is used
|
||||||
|
|
|
@ -0,0 +1,205 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
package jdk.jpackage.internal;
|
||||||
|
|
||||||
|
import static jdk.jpackage.internal.WinMsiBundler.WIN_APP_IMAGE;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HexFormat;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import jdk.jpackage.internal.util.XmlConsumer;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WiX Condition to block/allow installation based on OS version.
|
||||||
|
*/
|
||||||
|
record OSVersionCondition(WindowsVersion version) {
|
||||||
|
|
||||||
|
static OSVersionCondition createFromAppImage(ApplicationLayout appLayout, Map<String, ? super Object> params) {
|
||||||
|
Objects.requireNonNull(appLayout);
|
||||||
|
|
||||||
|
final List<Path> executables = new ArrayList<>();
|
||||||
|
|
||||||
|
if (!StandardBundlerParam.isRuntimeInstaller(params)) {
|
||||||
|
final var launcherName = StandardBundlerParam.APP_NAME.fetchFrom(params);
|
||||||
|
executables.add(appLayout.launchersDirectory().resolve(launcherName + ".exe"));
|
||||||
|
}
|
||||||
|
|
||||||
|
executables.add(appLayout.runtimeDirectory().resolve("bin\\java.dll"));
|
||||||
|
|
||||||
|
final var lowestOsVersion = executables.stream()
|
||||||
|
.filter(Files::isRegularFile)
|
||||||
|
.map(WindowsVersion::getExecutableOSVersion)
|
||||||
|
// Order by version, with the higher version first
|
||||||
|
.sorted(WindowsVersion.descendingOrder())
|
||||||
|
.findFirst().orElseGet(() -> {
|
||||||
|
// No java.dll, no launchers, it is either a highly customized or messed up app image.
|
||||||
|
// Let it install on Windows NT/95 or newer.
|
||||||
|
return new WindowsVersion(4, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
return new OSVersionCondition(lowestOsVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
record WindowsVersion(int majorOSVersion, int minorOSVersion) {
|
||||||
|
|
||||||
|
WindowsVersion {
|
||||||
|
if (majorOSVersion <= 0) {
|
||||||
|
throw new IllegalArgumentException("Invalid major version");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minorOSVersion < 0) {
|
||||||
|
throw new IllegalArgumentException("Invalid minor version");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static WindowsVersion getExecutableOSVersion(Path executable) {
|
||||||
|
try (final var fin = Files.newInputStream(executable);
|
||||||
|
final var in = new BufferedInputStream(fin)) {
|
||||||
|
// Skip all but "e_lfanew" fields of DOS stub (https://wiki.osdev.org/PE#DOS_Stub)
|
||||||
|
in.skipNBytes(64 - 4);
|
||||||
|
|
||||||
|
final int peHeaderOffset = read32BitLE(in);
|
||||||
|
if (peHeaderOffset <= 0) {
|
||||||
|
throw new IOException("Invalid PE header offset");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to PE header
|
||||||
|
in.skip(peHeaderOffset - 64);
|
||||||
|
|
||||||
|
// Read "mMagic" field (aka PE signature), (https://wiki.osdev.org/PE#PE_header)
|
||||||
|
final byte[] peSignature = in.readNBytes(4);
|
||||||
|
if (peSignature.length != 4) {
|
||||||
|
throw notEnoughBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peSignature[0] != 'P' || peSignature[1] != 'E' || peSignature[2] != 0 || peSignature[3] != 0) {
|
||||||
|
throw new IOException(String.format("Invalid PE signature: %s", HexFormat.of().formatHex(peSignature)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read size of optional PE header from "mSizeOfOptionalHeader" field (https://wiki.osdev.org/PE#PE_header)
|
||||||
|
in.skip(16);
|
||||||
|
final int sizeOfOptionalHeader = read16BitLE(in);
|
||||||
|
if (sizeOfOptionalHeader < (40 + 4)) {
|
||||||
|
throw new IOException("Invalid PE optional header size");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip PE header
|
||||||
|
in.skip(2);
|
||||||
|
|
||||||
|
// Skip all fields of Optional PE header until "mMajorOperatingSystemVersion" field (https://wiki.osdev.org/PE#Optional_header)
|
||||||
|
in.skip(40);
|
||||||
|
|
||||||
|
final int mMajorOperatingSystemVersion = read16BitLE(in);
|
||||||
|
final int mMinorOperatingSystemVersion = read16BitLE(in);
|
||||||
|
|
||||||
|
return new WindowsVersion(mMajorOperatingSystemVersion, mMinorOperatingSystemVersion);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new UncheckedIOException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Comparator<WindowsVersion> descendingOrder() {
|
||||||
|
return Comparator.comparing(WindowsVersion::majorOSVersion).thenComparing(WindowsVersion::minorOSVersion).reversed();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int read16BitLE(InputStream in) throws IOException {
|
||||||
|
byte buffer[] = new byte[2];
|
||||||
|
if (buffer.length != in.read(buffer)) {
|
||||||
|
throw notEnoughBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((buffer[0] & 0xFF) | ((buffer[1] & 0xFF) << 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int read32BitLE(InputStream in) throws IOException {
|
||||||
|
byte buffer[] = new byte[4];
|
||||||
|
if (buffer.length != in.read(buffer)) {
|
||||||
|
throw notEnoughBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((buffer[0] & 0xFF) | ((buffer[1] & 0xFF) << 8) |
|
||||||
|
((buffer[2] & 0xFF) << 16) | ((buffer[3] & 0xFF) << 24));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IOException notEnoughBytes() {
|
||||||
|
return new IOException("Invalid PE file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int msiVersionNumber() {
|
||||||
|
return version.majorOSVersion() * 100 + version.minorOSVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
String msiVersionString() {
|
||||||
|
return String.valueOf(msiVersionNumber());
|
||||||
|
}
|
||||||
|
|
||||||
|
static WixFragmentBuilder createWixFragmentBuilder() {
|
||||||
|
final var builder = new WixFragmentBuilder() {
|
||||||
|
@Override
|
||||||
|
protected Collection<XmlConsumer> getFragmentWriters() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void initFromParams(Map<String, ? super Object> params) {
|
||||||
|
super.initFromParams(params);
|
||||||
|
|
||||||
|
final Path appImageRoot = WIN_APP_IMAGE.fetchFrom(params);
|
||||||
|
|
||||||
|
ApplicationLayout appImageLayout;
|
||||||
|
if (StandardBundlerParam.isRuntimeInstaller(params)) {
|
||||||
|
appImageLayout = ApplicationLayout.javaRuntime();
|
||||||
|
} else {
|
||||||
|
appImageLayout = ApplicationLayout.platformAppImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
appImageLayout = appImageLayout.resolveAt(appImageRoot);
|
||||||
|
|
||||||
|
final var cond = OSVersionCondition.createFromAppImage(appImageLayout, params);
|
||||||
|
|
||||||
|
setWixVariable("JpExecutableMajorOSVersion", String.valueOf(cond.version().majorOSVersion));
|
||||||
|
setWixVariable("JpExecutableMinorOSVersion", String.valueOf(cond.version().minorOSVersion));
|
||||||
|
setWixVariable("JpExecutableOSVersion", String.valueOf(cond.msiVersionString()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
builder.setDefaultResourceName("os-condition.wxf");
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -227,7 +227,8 @@ public class WinMsiBundler extends AbstractBundler {
|
||||||
appImageBundler = new WinAppBundler().setDependentTask(true);
|
appImageBundler = new WinAppBundler().setDependentTask(true);
|
||||||
wixFragments = Stream.of(
|
wixFragments = Stream.of(
|
||||||
Map.entry("bundle.wxf", new WixAppImageFragmentBuilder()),
|
Map.entry("bundle.wxf", new WixAppImageFragmentBuilder()),
|
||||||
Map.entry("ui.wxf", new WixUiFragmentBuilder())
|
Map.entry("ui.wxf", new WixUiFragmentBuilder()),
|
||||||
|
Map.entry("os-condition.wxf", OSVersionCondition.createWixFragmentBuilder())
|
||||||
).<WixFragmentBuilder>map(e -> {
|
).<WixFragmentBuilder>map(e -> {
|
||||||
e.getValue().setOutputFileName(e.getKey());
|
e.getValue().setOutputFileName(e.getKey());
|
||||||
return e.getValue();
|
return e.getValue();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -38,7 +38,6 @@ import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import javax.xml.stream.XMLStreamWriter;
|
import javax.xml.stream.XMLStreamWriter;
|
||||||
import jdk.jpackage.internal.util.XmlConsumer;
|
import jdk.jpackage.internal.util.XmlConsumer;
|
||||||
import jdk.jpackage.internal.OverridableResource.Source;
|
|
||||||
import static jdk.jpackage.internal.StandardBundlerParam.CONFIG_ROOT;
|
import static jdk.jpackage.internal.StandardBundlerParam.CONFIG_ROOT;
|
||||||
import jdk.internal.util.Architecture;
|
import jdk.internal.util.Architecture;
|
||||||
import static jdk.jpackage.internal.OverridableResource.createResource;
|
import static jdk.jpackage.internal.OverridableResource.createResource;
|
||||||
|
@ -62,12 +61,15 @@ abstract class WixFragmentBuilder {
|
||||||
outputFileName = v;
|
outputFileName = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final void setDefaultResourceName(String v) {
|
||||||
|
defaultResourceName = v;
|
||||||
|
}
|
||||||
|
|
||||||
void initFromParams(Map<String, ? super Object> params) {
|
void initFromParams(Map<String, ? super Object> params) {
|
||||||
wixVariables = null;
|
wixVariables = null;
|
||||||
additionalResources = null;
|
additionalResources = null;
|
||||||
configRoot = CONFIG_ROOT.fetchFrom(params);
|
configRoot = CONFIG_ROOT.fetchFrom(params);
|
||||||
fragmentResource = createResource(outputFileName, params).setSourceOrder(
|
fragmentResource = createResource(defaultResourceName, params).setPublicName(outputFileName);
|
||||||
Source.ResourceDir);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> getLoggableWixFeatures() {
|
List<String> getLoggableWixFeatures() {
|
||||||
|
@ -82,7 +84,10 @@ abstract class WixFragmentBuilder {
|
||||||
|
|
||||||
void addFilesToConfigRoot() throws IOException {
|
void addFilesToConfigRoot() throws IOException {
|
||||||
Path fragmentPath = configRoot.resolve(outputFileName);
|
Path fragmentPath = configRoot.resolve(outputFileName);
|
||||||
if (fragmentResource.saveToFile(fragmentPath) == null) {
|
final var src = fragmentResource.saveToStream(null);
|
||||||
|
if (src == null) {
|
||||||
|
// There is no predefined resource for the fragment.
|
||||||
|
// The fragment should be built in the format matching the version of the WiX Toolkit.
|
||||||
createWixSource(fragmentPath, xml -> {
|
createWixSource(fragmentPath, xml -> {
|
||||||
for (var fragmentWriter : getFragmentWriters()) {
|
for (var fragmentWriter : getFragmentWriters()) {
|
||||||
xml.writeStartElement("Fragment");
|
xml.writeStartElement("Fragment");
|
||||||
|
@ -90,6 +95,11 @@ abstract class WixFragmentBuilder {
|
||||||
xml.writeEndElement(); // <Fragment>
|
xml.writeEndElement(); // <Fragment>
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
// Fragment is picked from the resource. May require conversion.
|
||||||
|
final var resourceGroup = new ResourceGroup(getWixType());
|
||||||
|
resourceGroup.addResource(fragmentResource, fragmentPath);
|
||||||
|
resourceGroup.saveResources();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (additionalResources != null) {
|
if (additionalResources != null) {
|
||||||
|
@ -237,6 +247,7 @@ abstract class WixFragmentBuilder {
|
||||||
private WixVariables wixVariables;
|
private WixVariables wixVariables;
|
||||||
private ResourceGroup additionalResources;
|
private ResourceGroup additionalResources;
|
||||||
private OverridableResource fragmentResource;
|
private OverridableResource fragmentResource;
|
||||||
|
private String defaultResourceName;
|
||||||
private String outputFileName;
|
private String outputFileName;
|
||||||
private Path configRoot;
|
private Path configRoot;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,4 +15,6 @@
|
||||||
<String Id="InstallDirNotEmptyDlgInstallDirExistMessage">Der Ordner [INSTALLDIR] ist bereits vorhanden. Möchten Sie diesen Ordner trotzdem installieren?</String>
|
<String Id="InstallDirNotEmptyDlgInstallDirExistMessage">Der Ordner [INSTALLDIR] ist bereits vorhanden. Möchten Sie diesen Ordner trotzdem installieren?</String>
|
||||||
|
|
||||||
<String Id="ContextMenuCommandLabel">Mit [ProductName] öffnen</String>
|
<String Id="ContextMenuCommandLabel">Mit [ProductName] öffnen</String>
|
||||||
|
|
||||||
|
<String Id="OsConditionMessage">[ProductName][ProductVersion] is not supported on this version of Windows</String>
|
||||||
</WixLocalization>
|
</WixLocalization>
|
||||||
|
|
|
@ -15,4 +15,6 @@
|
||||||
<String Id="InstallDirNotEmptyDlgInstallDirExistMessage">The folder [INSTALLDIR] already exist. Would you like to install to that folder anyway?</String>
|
<String Id="InstallDirNotEmptyDlgInstallDirExistMessage">The folder [INSTALLDIR] already exist. Would you like to install to that folder anyway?</String>
|
||||||
|
|
||||||
<String Id="ContextMenuCommandLabel">Open with [ProductName]</String>
|
<String Id="ContextMenuCommandLabel">Open with [ProductName]</String>
|
||||||
|
|
||||||
|
<String Id="OsConditionMessage">[ProductName][ProductVersion] is not supported on this version of Windows</String>
|
||||||
</WixLocalization>
|
</WixLocalization>
|
||||||
|
|
|
@ -15,4 +15,6 @@
|
||||||
<String Id="InstallDirNotEmptyDlgInstallDirExistMessage">フォルダ[INSTALLDIR]はすでに存在します。そのフォルダにインストールしますか?</String>
|
<String Id="InstallDirNotEmptyDlgInstallDirExistMessage">フォルダ[INSTALLDIR]はすでに存在します。そのフォルダにインストールしますか?</String>
|
||||||
|
|
||||||
<String Id="ContextMenuCommandLabel">[ProductName]で開く</String>
|
<String Id="ContextMenuCommandLabel">[ProductName]で開く</String>
|
||||||
|
|
||||||
|
<String Id="OsConditionMessage">[ProductName][ProductVersion] is not supported on this version of Windows</String>
|
||||||
</WixLocalization>
|
</WixLocalization>
|
||||||
|
|
|
@ -15,4 +15,6 @@
|
||||||
<String Id="InstallDirNotEmptyDlgInstallDirExistMessage">文件夹 [INSTALLDIR] 已存在。是否仍要安装到该文件夹?</String>
|
<String Id="InstallDirNotEmptyDlgInstallDirExistMessage">文件夹 [INSTALLDIR] 已存在。是否仍要安装到该文件夹?</String>
|
||||||
|
|
||||||
<String Id="ContextMenuCommandLabel">使用 [ProductName] 打开</String>
|
<String Id="ContextMenuCommandLabel">使用 [ProductName] 打开</String>
|
||||||
|
|
||||||
|
<String Id="OsConditionMessage">[ProductName][ProductVersion] is not supported on this version of Windows</String>
|
||||||
</WixLocalization>
|
</WixLocalization>
|
||||||
|
|
|
@ -76,6 +76,7 @@
|
||||||
<ComponentGroupRef Id="Shortcuts"/>
|
<ComponentGroupRef Id="Shortcuts"/>
|
||||||
<ComponentGroupRef Id="Files"/>
|
<ComponentGroupRef Id="Files"/>
|
||||||
<ComponentGroupRef Id="FileAssociations"/>
|
<ComponentGroupRef Id="FileAssociations"/>
|
||||||
|
<ComponentGroupRef Id="FragmentOsCondition"/>
|
||||||
</Feature>
|
</Feature>
|
||||||
|
|
||||||
<CustomAction Id="JpSetARPINSTALLLOCATION" Property="ARPINSTALLLOCATION" Value="[INSTALLDIR]" />
|
<CustomAction Id="JpSetARPINSTALLLOCATION" Property="ARPINSTALLLOCATION" Value="[INSTALLDIR]" />
|
||||||
|
@ -123,6 +124,7 @@
|
||||||
<?ifndef JpAllowDowngrades ?>
|
<?ifndef JpAllowDowngrades ?>
|
||||||
<Custom Action="JpDisallowDowngrade" After="JpFindRelatedProducts">JP_DOWNGRADABLE_FOUND</Custom>
|
<Custom Action="JpDisallowDowngrade" After="JpFindRelatedProducts">JP_DOWNGRADABLE_FOUND</Custom>
|
||||||
<?endif?>
|
<?endif?>
|
||||||
|
<LaunchConditions Before="AppSearch"/>
|
||||||
<RemoveExistingProducts Before="CostInitialize"/>
|
<RemoveExistingProducts Before="CostInitialize"/>
|
||||||
<Custom Action="JpFindRelatedProducts" After="FindRelatedProducts"/>
|
<Custom Action="JpFindRelatedProducts" After="FindRelatedProducts"/>
|
||||||
</InstallExecuteSequence>
|
</InstallExecuteSequence>
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
-->
|
||||||
|
|
||||||
|
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||||
|
<Fragment>
|
||||||
|
<Condition Message="!(loc.OsConditionMessage)">
|
||||||
|
<![CDATA[Installed OR (VersionNT >= $(var.JpExecutableOSVersion))]]>
|
||||||
|
</Condition>
|
||||||
|
<!--
|
||||||
|
Fragment contents must be referenced. Otherwise, the fragment will be ignored.
|
||||||
|
Use empty component group as an anchor for the reference.
|
||||||
|
-->
|
||||||
|
<ComponentGroup Id="FragmentOsCondition"/>
|
||||||
|
</Fragment>
|
||||||
|
</Wix>
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!--
|
<!--
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -73,6 +73,19 @@
|
||||||
</xsl:template>
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
From <Condition Message="foo">Bar</Condition> to <Launch Message="foo" Condition="Bar"/>
|
||||||
|
-->
|
||||||
|
<xsl:template match="wix3:Condition">
|
||||||
|
<xsl:element name="Launch" namespace="http://wixtoolset.org/schemas/v4/wxs">
|
||||||
|
<xsl:attribute name="Condition">
|
||||||
|
<xsl:value-of select="text()"/>
|
||||||
|
</xsl:attribute>
|
||||||
|
<xsl:apply-templates select="@*"/>
|
||||||
|
</xsl:element>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Wix3 Product (https://wixtoolset.org/docs/v3/xsd/wix/product/):
|
Wix3 Product (https://wixtoolset.org/docs/v3/xsd/wix/product/):
|
||||||
Id
|
Id
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jdk.jpackage.internal;
|
||||||
|
|
||||||
|
import static jdk.jpackage.internal.OSVersionCondition.WindowsVersion.getExecutableOSVersion;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.junit.jupiter.api.condition.OS.WINDOWS;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import jdk.jpackage.internal.OSVersionCondition.WindowsVersion;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.condition.EnabledOnOs;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
|
||||||
|
|
||||||
|
public class ExecutableOSVersionTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@EnabledOnOs(WINDOWS)
|
||||||
|
public void testWindowsVersionGetExecutableOSVersion() {
|
||||||
|
final var javaHome = Path.of(System.getProperty("java.home"));
|
||||||
|
|
||||||
|
final var javaExeVer = getExecutableOSVersion(javaHome.resolve("bin/java.exe"));
|
||||||
|
|
||||||
|
assertTrue(javaExeVer.majorOSVersion() > 0);
|
||||||
|
assertTrue(javaExeVer.minorOSVersion() >= 0);
|
||||||
|
|
||||||
|
final var javaDllVer = getExecutableOSVersion(javaHome.resolve("bin/java.dll"));
|
||||||
|
|
||||||
|
assertEquals(javaExeVer, javaDllVer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@EnabledOnOs(WINDOWS)
|
||||||
|
@MethodSource
|
||||||
|
public void testWindowsVersionDescendingOrder(List<WindowsVersion> unsorted, WindowsVersion expectedFirst) {
|
||||||
|
final var actualFirst = unsorted.stream().sorted(WindowsVersion.descendingOrder()).findFirst().orElseThrow();
|
||||||
|
assertEquals(expectedFirst, actualFirst);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stream<Object[]> testWindowsVersionDescendingOrder() {
|
||||||
|
return Stream.<Object[]>of(
|
||||||
|
new Object[] { List.of(wver(5, 0), wver(5, 1), wver(4, 9)), wver(5, 1) },
|
||||||
|
new Object[] { List.of(wver(5, 0)), wver(5, 0) },
|
||||||
|
new Object[] { List.of(wver(5, 1), wver(5, 1), wver(5, 0)), wver(5, 1) },
|
||||||
|
new Object[] { List.of(wver(3, 11), wver(4, 8), wver(5, 6)), wver(5, 6) },
|
||||||
|
new Object[] { List.of(wver(3, 11), wver(3, 9), wver(3, 13)), wver(3, 13) }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static WindowsVersion wver(int major, int minor) {
|
||||||
|
return new WindowsVersion(major, minor);
|
||||||
|
}
|
||||||
|
}
|
29
test/jdk/tools/jpackage/junit/windows/junit.java
Normal file
29
test/jdk/tools/jpackage/junit/windows/junit.java
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* @test
|
||||||
|
* @summary Test function reading OS version from PE file
|
||||||
|
* @requires (os.family == "windows")
|
||||||
|
* @compile/module=jdk.jpackage jdk/jpackage/internal/ExecutableOSVersionTest.java
|
||||||
|
* @run junit jdk.jpackage/jdk.jpackage.internal.ExecutableOSVersionTest
|
||||||
|
*/
|
Loading…
Add table
Add a link
Reference in a new issue