8357404: jpackage should attempt to get a package version from the JDK's release file if the --version option is not specified [v5]

This commit is contained in:
alexander_matveev 2026-01-16 19:22:02 -08:00
parent 6cd845508f
commit 6da599179e
14 changed files with 368 additions and 196 deletions

View File

@ -53,11 +53,13 @@ import static jdk.jpackage.internal.model.StandardPackageType.MAC_DMG;
import static jdk.jpackage.internal.model.StandardPackageType.MAC_PKG;
import static jdk.jpackage.internal.util.function.ExceptionBox.toUnchecked;
import java.math.BigInteger;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.UnaryOperator;
import jdk.jpackage.internal.ApplicationBuilder.MainLauncherStartupInfo;
import jdk.jpackage.internal.SigningIdentityBuilder.ExpiredCertificateException;
import jdk.jpackage.internal.SigningIdentityBuilder.StandardCertificateSelector;
@ -65,6 +67,7 @@ import jdk.jpackage.internal.cli.OptionValue;
import jdk.jpackage.internal.cli.Options;
import jdk.jpackage.internal.cli.StandardFaOption;
import jdk.jpackage.internal.model.Application;
import jdk.jpackage.internal.model.DottedVersion;
import jdk.jpackage.internal.model.ApplicationLaunchers;
import jdk.jpackage.internal.model.ExternalApplication;
import jdk.jpackage.internal.model.FileAssociation;
@ -219,24 +222,10 @@ final class MacFromOptions {
if (isRuntimeInstaller(options) && !APP_VERSION.containsIn(options)) {
// User didn't explicitly specify the version on the command line. jpackage derived it from the input.
// In this case it should ensure the derived value is valid MacOS version.
var ver = normalizeVersion(app.version());
if (!ver.equals(app.version())) {
Log.verbose(I18N.format("message.version-normalized",
ver, app.version()));
}
app = new Application.Stub(
app.name(),
app.description(),
ver,
app.vendor(),
app.copyright(),
app.srcDir(),
app.contentDirs(),
app.imageLayout(),
app.runtimeBuilder(),
app.launchers(),
app.extraAppImageFileData());
UnaryOperator<String> versionNormalizer = version -> {
return normalizeVersion(version);
};
app = ApplicationBuilder.normalizeVersion(app, app.version(), versionNormalizer);
}
final var appBuilder = new MacApplicationBuilder(app);
@ -359,10 +348,10 @@ final class MacFromOptions {
// macOS requires 1, 2 or 3 components version string.
// When reading from release file it can be 1 or 3 or maybe more.
// We always normalize to 3 components.
String[] components = version.split("\\.");
DottedVersion ver = DottedVersion.greedy(version);
BigInteger[] components = ver.getComponents();
if (components.length >= 4) {
components = version.split("\\.", 4);
return String.join(".", Arrays.copyOf(components, components.length - 1));
return ver.toComponentsStringWithPadding(3);
}
return version;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2025, 2026, 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
@ -35,6 +35,7 @@ import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import jdk.jpackage.internal.model.AppImageLayout;
import jdk.jpackage.internal.model.Application;
import jdk.jpackage.internal.model.ApplicationLaunchers;
@ -227,6 +228,28 @@ final class ApplicationBuilder {
}
}
static Application normalizeVersion(Application app, String version,
UnaryOperator<String> versionNormalizer) {
final var ver = versionNormalizer.apply(version);
if (!ver.equals(app.version())) {
Log.verbose(I18N.format("message.version-normalized",
ver, app.version()));
}
return new Application.Stub(
app.name(),
app.description(),
ver,
app.vendor(),
app.copyright(),
app.srcDir(),
app.contentDirs(),
app.imageLayout(),
app.runtimeBuilder(),
app.launchers(),
app.extraAppImageFileData());
}
static Launcher overrideLauncherStartupInfo(Launcher launcher, LauncherStartupInfo startupInfo) {
return new Launcher.Stub(
launcher.name(),

View File

@ -45,6 +45,8 @@ import static jdk.jpackage.internal.cli.StandardOption.PREDEFINED_RUNTIME_IMAGE;
import static jdk.jpackage.internal.cli.StandardOption.RESOURCE_DIR;
import static jdk.jpackage.internal.cli.StandardOption.VENDOR;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
@ -54,6 +56,7 @@ import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Function;
import jdk.jpackage.internal.cli.Options;
import jdk.jpackage.internal.util.RuntimeImageUtils;
import jdk.jpackage.internal.util.RuntimeVersionReader;
import jdk.jpackage.internal.model.Application;
import jdk.jpackage.internal.model.ApplicationLaunchers;
@ -176,12 +179,18 @@ final class FromOptions {
appBuilder.appImageLayout(runtimeLayout);
if (!APP_VERSION.containsIn(options)) {
// Version is not specified explicitly. Try to get it from the release file.
RuntimeVersionReader.readVersion(PREDEFINED_RUNTIME_IMAGE.getFrom(options))
.ifPresent(version -> {
appBuilder.version(version);
Log.verbose(I18N.format("message.release-version",
version, PREDEFINED_RUNTIME_IMAGE.getFrom(options)));
});
final Path releaseFile = RuntimeImageUtils.getReleaseFilePath(
PREDEFINED_RUNTIME_IMAGE.getFrom(options));
try {
RuntimeVersionReader.readVersion(releaseFile)
.ifPresent(version -> {
appBuilder.version(version);
Log.verbose(I18N.format("message.release-version",
version, PREDEFINED_RUNTIME_IMAGE.getFrom(options)));
});
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
} else {
appBuilder.appImageLayout(appLayout);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2025, 2026, 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
@ -35,7 +35,7 @@ import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Properties;
import jdk.internal.util.OperatingSystem;
import jdk.jpackage.internal.util.RuntimeImageUtils;
record ModuleInfo(String name, Optional<String> version, Optional<String> mainClass, Optional<URI> location) {
@ -61,18 +61,7 @@ record ModuleInfo(String name, Optional<String> version, Optional<String> mainCl
// is linked in the runtime by simply analysing the data
// of `release` file.
final Path releaseFile;
if (!OperatingSystem.isMacOS()) {
releaseFile = cookedRuntime.resolve("release");
} else {
// On Mac `cookedRuntime` can be runtime root or runtime home.
Path runtimeHome = cookedRuntime.resolve("Contents/Home");
if (!Files.isDirectory(runtimeHome)) {
runtimeHome = cookedRuntime;
}
releaseFile = runtimeHome.resolve("release");
}
final Path releaseFile = RuntimeImageUtils.getReleaseFilePath(cookedRuntime);
try (Reader reader = Files.newBufferedReader(releaseFile)) {
Properties props = new Properties();
props.load(reader);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2026, 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
@ -224,6 +224,16 @@ public final class DottedVersion {
return Stream.of(components).map(BigInteger::toString).collect(Collectors.joining("."));
}
public String toComponentsStringWithPadding(int numberOfComponents) {
if (components.length >= numberOfComponents) {
return Stream.of(components).map(BigInteger::toString)
.limit(numberOfComponents).collect(Collectors.joining("."));
} else {
return toComponentsString()
.concat(".0".repeat(numberOfComponents - components.length));
}
}
public BigInteger[] getComponents() {
return components;
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2026, 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.util;
import java.nio.file.Files;
import java.nio.file.Path;
import jdk.internal.util.OperatingSystem;
public final class RuntimeImageUtils {
public static Path getReleaseFilePath(Path runtimePath) {
final Path releaseFile;
if (!OperatingSystem.isMacOS()) {
releaseFile = runtimePath.resolve("release");
} else {
// On Mac `runtimePath` can be runtime root or runtime home.
Path runtimeHome = runtimePath.resolve("Contents/Home");
if (!Files.isDirectory(runtimeHome)) {
runtimeHome = runtimePath;
}
releaseFile = runtimeHome.resolve("release");
}
return releaseFile;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2026, 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
@ -32,53 +32,21 @@ import java.nio.file.Path;
import java.util.Optional;
import java.util.Properties;
import jdk.jpackage.internal.Log;
import jdk.internal.util.OperatingSystem;
public final class RuntimeVersionReader {
public static Optional<String> readVersion(Path runtimeImage) {
Optional<Path> releasePath = getRuntimeReleaseFile(runtimeImage);
Optional<String> releaseVersion = Optional.empty();
if (releasePath.isPresent()) {
try (Reader reader = Files.newBufferedReader(releasePath.get())) {
Properties props = new Properties();
props.load(reader);
String version = props.getProperty("JAVA_VERSION");
if (version != null) {
version = version.replaceAll("^\"|\"$", "");
}
releaseVersion = Optional.ofNullable(version);
} catch (IOException ex) {
Log.verbose(ex);
}
};
return releaseVersion;
}
private static Optional<Path> checkReleaseFilePath(Path releaseFilePath) {
if (Files.isRegularFile(releaseFilePath)) {
return Optional.of(releaseFilePath);
} else {
public static Optional<String> readVersion(Path releaseFilePath) throws IOException {
if (!Files.isRegularFile(releaseFilePath)) {
return Optional.empty();
}
}
private static Optional<Path> getRuntimeReleaseFile(Path runtimeImage) {
Optional<Path> releasePath = Optional.empty();
// Try special case for macOS first ("Contents/Home/release").
if (OperatingSystem.isMacOS()) {
releasePath = checkReleaseFilePath(runtimeImage.resolve("Contents/Home/release"));
try (Reader reader = Files.newBufferedReader(releaseFilePath)) {
Properties props = new Properties();
props.load(reader);
String version = props.getProperty("JAVA_VERSION");
if (version != null) {
version = version.replaceAll("^\"|\"$", "");
}
return Optional.ofNullable(version);
}
// Try root for all platforms including macOS if releasePath is not set
if (releasePath.isEmpty()) {
releasePath = checkReleaseFilePath(runtimeImage.resolve("release"));
}
return releasePath;
}
}

View File

@ -43,10 +43,13 @@ import static jdk.jpackage.internal.cli.StandardOption.WIN_UPDATE_URL;
import static jdk.jpackage.internal.cli.StandardOption.WIN_UPGRADE_UUID;
import static jdk.jpackage.internal.model.StandardPackageType.WIN_MSI;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.function.UnaryOperator;
import jdk.jpackage.internal.cli.Options;
import jdk.jpackage.internal.model.Application;
import jdk.jpackage.internal.model.DottedVersion;
import jdk.jpackage.internal.model.Launcher;
import jdk.jpackage.internal.model.WinApplication;
import jdk.jpackage.internal.model.WinExePackage;
@ -83,24 +86,10 @@ final class WinFromOptions {
if (isRuntimeInstaller(options) && !APP_VERSION.containsIn(options)) {
// User didn't explicitly specify the version on the command line. jpackage derived it from the input.
// In this case it should ensure the derived value is valid Windows version.
var ver = normalizeVersion(app.version());
if (!ver.equals(app.version())) {
Log.verbose(I18N.format("message.version-normalized",
ver, app.version()));
}
app = new Application.Stub(
app.name(),
app.description(),
ver,
app.vendor(),
app.copyright(),
app.srcDir(),
app.contentDirs(),
app.imageLayout(),
app.runtimeBuilder(),
app.launchers(),
app.extraAppImageFileData());
UnaryOperator<String> versionNormalizer = version -> {
return normalizeVersion(version);
};
app = ApplicationBuilder.normalizeVersion(app, app.version(), versionNormalizer);
}
return WinApplication.create(app);
@ -147,14 +136,11 @@ final class WinFromOptions {
// Windows requires 2 or 4 components version string.
// When reading from release file it can be 1 or 3 or maybe more.
// We always normalize to 4 components.
String[] components = version.split("\\.");
if (components.length == 1) {
return version.concat(".0.0.0");
} else if (components.length == 3) {
return version.concat(".0");
} else if (components.length >= 5) {
components = version.split("\\.", 5);
return String.join(".", Arrays.copyOf(components, components.length - 1));
DottedVersion ver = DottedVersion.greedy(version);
BigInteger[] components = ver.getComponents();
if (components.length == 1 || components.length == 3 ||
components.length >= 5) {
return ver.toComponentsStringWithPadding(4);
}
return version;

View File

@ -63,6 +63,7 @@ import java.util.spi.ToolProvider;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import jdk.jpackage.internal.util.RuntimeImageUtils;
import jdk.jpackage.internal.util.RuntimeVersionReader;
import jdk.jpackage.internal.util.function.ExceptionBox;
import jdk.jpackage.internal.util.function.ThrowingConsumer;
@ -248,26 +249,27 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
}
public String version() {
if (isRuntime()) {
String appVersion = getArgumentValue("--app-version");
if (appVersion != null) {
return appVersion;
} else {
Optional<String> releaseVersion = RuntimeVersionReader
.readVersion(Path.of(getArgumentValue("--runtime-image")));
if (releaseVersion.isPresent()) {
if (TKit.isWindows()) {
return WindowsHelper.getNormalizedVersion(this, releaseVersion.get());
} else if (TKit.isOSX()) {
return MacHelper.getNormalizedVersion(this, releaseVersion.get());
}
return releaseVersion.get();
return Optional.ofNullable(getArgumentValue("--app-version")).or(() -> {
if (isRuntime()) {
final Path releaseFile = RuntimeImageUtils.getReleaseFilePath(
Path.of(getArgumentValue("--runtime-image")));
try {
return RuntimeVersionReader.readVersion(releaseFile).map(releaseVersion -> {
if (TKit.isWindows()) {
return WindowsHelper.getNormalizedVersion(releaseVersion);
} else if (TKit.isOSX()) {
return MacHelper.getNormalizedVersion(releaseVersion);
} else {
return releaseVersion;
}
});
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
} else {
return Optional.empty();
}
}
return getArgumentValue("--app-version", () -> "1.0");
}).orElse("1.0");
}
public String name() {
@ -315,10 +317,6 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
}
public JPackageCommand setFakeRuntime() {
return setFakeRuntime(Optional.empty());
}
public JPackageCommand setFakeRuntime(Optional<String> version) {
verifyMutable();
ThrowingConsumer<Path, IOException> createBulkFile = path -> {
@ -347,19 +345,6 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
// an error by PackageTest.
createBulkFile.accept(fakeRuntimeDir.resolve(Path.of("lib", "bulk")));
// Create release file with version if provided
version.ifPresent(ver -> {
Properties props = new Properties();
props.setProperty("JAVA_VERSION", ver);
try (Writer writer = Files.newBufferedWriter(fakeRuntimeDir.resolve("release"))) {
props.store(writer, null);
} catch (IOException ex) {
TKit.trace(String.format(
"Failed to create [%s] file: %s",
fakeRuntimeDir.resolve("release"), ex));
}
});
cmd.setArgumentValue("--runtime-image", fakeRuntimeDir);
});

View File

@ -42,6 +42,7 @@ import java.io.UncheckedIOException;
import java.lang.constant.ClassDesc;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.LinkOption;
@ -72,6 +73,7 @@ import jdk.jpackage.internal.util.PListReader;
import jdk.jpackage.internal.util.PathUtils;
import jdk.jpackage.internal.util.RetryExecutor;
import jdk.jpackage.internal.util.XmlUtils;
import jdk.jpackage.internal.model.DottedVersion;
import jdk.jpackage.internal.util.function.ThrowingConsumer;
import jdk.jpackage.internal.util.function.ThrowingSupplier;
import jdk.jpackage.test.MacSign.CertificateRequest;
@ -761,14 +763,13 @@ public final class MacHelper {
cmd.packageType().getSuffix());
}
static String getNormalizedVersion(JPackageCommand cmd, String version) {
cmd.verifyIsOfType(PackageType.MAC);
static String getNormalizedVersion(String version) {
// macOS requires 1, 2 or 3 components version string.
// We always normalize to 3 components.
String[] components = version.split("\\.");
DottedVersion ver = DottedVersion.greedy(version);
BigInteger[] components = ver.getComponents();
if (components.length >= 4) {
components = version.split("\\.", 4);
return String.join(".", Arrays.copyOf(components, components.length - 1));
return ver.toComponentsStringWithPadding(3);
}
return version;

View File

@ -29,6 +29,7 @@ import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.ref.SoftReference;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Instant;
@ -44,6 +45,7 @@ import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
import jdk.jpackage.internal.model.DottedVersion;
import jdk.jpackage.internal.util.function.ThrowingRunnable;
import jdk.jpackage.test.PackageTest.PackageHandlers;
@ -55,18 +57,14 @@ public class WindowsHelper {
cmd.packageType().getSuffix());
}
static String getNormalizedVersion(JPackageCommand cmd, String version) {
cmd.verifyIsOfType(PackageType.WINDOWS);
static String getNormalizedVersion(String version) {
// Windows requires 2 or 4 components version string.
// We always normalize to 4 components.
String[] components = version.split("\\.");
if (components.length == 1) {
return version.concat(".0.0.0");
} else if (components.length == 3) {
return version.concat(".0");
} else if (components.length >= 5) {
components = version.split("\\.", 5);
return String.join(".", Arrays.copyOf(components, components.length - 1));
DottedVersion ver = DottedVersion.greedy(version);
BigInteger[] components = ver.getComponents();
if (components.length == 1 || components.length == 3 ||
components.length >= 5) {
return ver.toComponentsStringWithPadding(4);
}
return version;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2026, 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
@ -41,26 +41,30 @@ public class DottedVersionTest {
public record TestConfig(String input,
Function<String, DottedVersion> createVersion, String expectedSuffix,
int expectedComponentCount, String expectedToComponent) {
int expectedComponentCount, String expectedToComponent, int numberOfComponents) {
TestConfig(String input, Type type, int expectedComponentCount, String expectedToComponent) {
this(input, type.createVersion, "", expectedComponentCount, expectedToComponent);
this(input, type.createVersion, "", expectedComponentCount, expectedToComponent, -1);
}
TestConfig(String input, Type type, int expectedComponentCount) {
this(input, type.createVersion, "", expectedComponentCount, input);
this(input, type.createVersion, "", expectedComponentCount, input, -1);
}
TestConfig(String input, Type type, String expectedToComponent, int numberOfComponents) {
this(input, type.createVersion, "", -1, expectedToComponent, numberOfComponents);
}
static TestConfig greedy(String input, int expectedComponentCount, String expectedToComponent) {
return new TestConfig(input, Type.GREEDY.createVersion, "", expectedComponentCount, expectedToComponent);
return new TestConfig(input, Type.GREEDY.createVersion, "", expectedComponentCount, expectedToComponent, -1);
}
static TestConfig greedy(String input, int expectedComponentCount) {
return new TestConfig(input, Type.GREEDY.createVersion, "", expectedComponentCount, input);
return new TestConfig(input, Type.GREEDY.createVersion, "", expectedComponentCount, input, -1);
}
static TestConfig lazy(String input, String expectedSuffix, int expectedComponentCount, String expectedToComponent) {
return new TestConfig(input, Type.LAZY.createVersion, expectedSuffix, expectedComponentCount, expectedToComponent);
return new TestConfig(input, Type.LAZY.createVersion, expectedSuffix, expectedComponentCount, expectedToComponent, -1);
}
}
@ -114,6 +118,29 @@ public class DottedVersionTest {
return data;
}
@ParameterizedTest
@MethodSource
public void testComponentsStringWithPadding(TestConfig cfg) {
var dv = cfg.createVersion.apply(cfg.input());
assertEquals(cfg.expectedToComponent(),
dv.toComponentsStringWithPadding(cfg.numberOfComponents()));
}
private static List<TestConfig> testComponentsStringWithPadding() {
List<TestConfig> data = new ArrayList<>();
for (var type : Type.values()) {
data.addAll(List.of(
new TestConfig("1", type, "1.0.0.0", 4),
new TestConfig("1.2", type, "1.2.0.0", 4),
new TestConfig("1.2.3", type, "1.2.3.0", 4),
new TestConfig("1.2.3.4", type, "1.2.3.4", 4),
new TestConfig("1.2.3.4.5", type, "1.2.3.4", 4)
));
}
return data;
}
record InvalidVersionTestSpec(String version, String invalidComponent) {
public InvalidVersionTestSpec {
Objects.requireNonNull(version);

View File

@ -0,0 +1,94 @@
/*
* Copyright (c) 2026, 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.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;
import java.util.Properties;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
public class RuntimeVersionReaderTest {
@Test
public void test_release_file_with_version(@TempDir Path workdir) {
final Optional<String> version;
try {
version = RuntimeVersionReader.readVersion(
createPropFileWithValue(workdir, "JAVA_VERSION", "27.1.2"));
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
assertTrue(version.isPresent());
version.ifPresent(ver -> {
assertEquals("27.1.2", version.get());
});
}
@Test
public void test_release_file_without_version(@TempDir Path workdir) {
final Optional<String> version;
try {
version = RuntimeVersionReader.readVersion(
createPropFileWithValue(workdir, "JDK_VERSION", "27.1.2"));
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
assertFalse(version.isPresent());
}
@Test
public void test_release_file_invalid_input(@TempDir Path workdir) {
final Optional<String> version;
try {
version = RuntimeVersionReader.readVersion(workdir);
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
assertFalse(version.isPresent());
}
private Path createPropFileWithValue(Path workdir, String name, String value)
throws IOException {
Path releaseFile = workdir.resolve("release");
Properties props = new Properties();
props.setProperty(name, "\"" + value + "\"");
try (Writer writer = Files.newBufferedWriter(releaseFile)) {
props.store(writer, null);
}
return releaseFile;
}
}

View File

@ -23,17 +23,22 @@
import static jdk.internal.util.OperatingSystem.LINUX;
import static jdk.internal.util.OperatingSystem.MACOS;
import static jdk.internal.util.OperatingSystem.WINDOWS;
import static jdk.jpackage.test.TKit.assertFalse;
import static jdk.jpackage.test.TKit.assertTrue;
import java.io.IOException;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
import java.util.Optional;
import java.util.Properties;
import java.util.function.Predicate;
import java.util.function.Supplier;
import jdk.jpackage.test.Annotations.Parameter;
import jdk.jpackage.test.Annotations.Test;
import jdk.jpackage.test.JPackageCommand;
import jdk.jpackage.test.JPackageStringBundle;
import jdk.jpackage.test.LinuxHelper;
import jdk.jpackage.test.MacHelper;
import jdk.jpackage.test.PackageTest;
@ -79,15 +84,15 @@ import jdk.jpackage.test.TKit;
*/
public class RuntimePackageTest {
@Test
public static void test() {
init().run();
}
// @Test
// public static void test() {
// init().run();
// }
@Test(ifOS = MACOS)
public static void testFromBundle() {
init(MacHelper::createRuntimeBundle).run();
}
// @Test(ifOS = MACOS)
// public static void testFromBundle() {
// init(MacHelper::createRuntimeBundle).run();
// }
@Test(ifOS = LINUX)
@Parameter("/usr")
@ -98,27 +103,66 @@ public class RuntimePackageTest {
.run();
}
@Test
public static void testName() {
// Test that jpackage can derive package name from the path to runtime image.
init()
.addInitializer(cmd -> cmd.removeArgumentWithValue("--name"))
// Don't attempt to install this package as it may have an odd name derived from
// the runtime image path. Say, on Linux for `--runtime-image foo/bar/sed`
// command line jpackage will create a package named 'sed' that will conflict
// with the default 'sed' package.
.run(Action.CREATE_AND_UNPACK);
}
// @Test
// public static void testName() {
// // Test that jpackage can derive package name from the path to runtime image.
// init()
// .addInitializer(cmd -> cmd.removeArgumentWithValue("--name"))
// // Don't attempt to install this package as it may have an odd name derived from
// // the runtime image path. Say, on Linux for `--runtime-image foo/bar/sed`
// // command line jpackage will create a package named 'sed' that will conflict
// // with the default 'sed' package.
// .run(Action.CREATE_AND_UNPACK);
// }
@Test
@Parameter("27")
@Parameter("27.1")
@Parameter("27.1.2")
@Parameter("27.1.2.3")
@Parameter("27.1.2.3.4")
public static void testReleaseFileVersion(String version) {
init()
.addInitializer(cmd -> cmd.setFakeRuntime(Optional.of(version)))
// 27
@Parameter(value = {"27", ""}, ifOS = {LINUX, MACOS})
@Parameter(value = {"27", "27.0.0.0"}, ifOS = WINDOWS)
// 27.1
@Parameter(value = {"27.1", ""})
// 27.1.2
@Parameter(value = {"27.1.2", ""}, ifOS = {LINUX, MACOS})
@Parameter(value = {"27.1.2", "27.1.2.0"}, ifOS = WINDOWS)
// 27.1.2.3
@Parameter(value = {"27.1.2.3", ""}, ifOS = {LINUX, WINDOWS})
@Parameter(value = {"27.1.2.3", "27.1.2"}, ifOS = MACOS)
// 27.1.2.3.4
@Parameter(value = {"27.1.2.3.4", ""}, ifOS = LINUX)
@Parameter(value = {"27.1.2.3.4", "27.1.2"}, ifOS = MACOS)
@Parameter(value = {"27.1.2.3.4", "27.1.2.3"}, ifOS = WINDOWS)
public static void testReleaseFileVersion(String version, String normalizedVersion) {
new PackageTest()
.addInitializer(cmd -> {
// Remove --input parameter from jpackage command line as we don't
// create input directory in the test and jpackage fails
// if --input references non existant directory.
cmd.removeArgumentWithValue("--input");
cmd.setFakeRuntime();
// Execute prerequisite actions, so fake runtime gets created
cmd.executePrerequisiteActions();
// Create release file with version in fake runtime
Path runtimeImage = Path.of(cmd.getArgumentValue("--runtime-image"));
Path releaseFile = runtimeImage.resolve("release");
Properties props = new Properties();
props.setProperty("JAVA_VERSION", "\"" + version + "\"");
try (Writer writer = Files.newBufferedWriter(releaseFile)) {
props.store(writer, null);
}
// Validate output
cmd.validateOutput(JPackageStringBundle.MAIN
.cannedFormattedString("message.release-version",
version, runtimeImage.toString()));
if (!normalizedVersion.isEmpty()) {
cmd.validateOutput(JPackageStringBundle.MAIN
.cannedFormattedString("message.version-normalized",
normalizedVersion, version));
}
})
// Just create package. It is enough to verify version in bundle name.
.run(Action.CREATE);
}