mirror of
https://github.com/openjdk/jdk.git
synced 2026-07-28 03:43:21 +00:00
8357404: jpackage should attempt to get a package version from the JDK's release file if the --version option is not specified
Reviewed-by: almatvee
This commit is contained in:
parent
775f07e671
commit
c315d1cd2b
@ -27,6 +27,7 @@ package jdk.jpackage.internal;
|
||||
import static jdk.jpackage.internal.FromOptions.buildApplicationBuilder;
|
||||
import static jdk.jpackage.internal.FromOptions.createPackageBuilder;
|
||||
import static jdk.jpackage.internal.LinuxPackagingPipeline.APPLICATION_LAYOUT;
|
||||
import static jdk.jpackage.internal.cli.StandardBundlingOperation.CREATE_LINUX_RPM;
|
||||
import static jdk.jpackage.internal.cli.StandardOption.LINUX_APP_CATEGORY;
|
||||
import static jdk.jpackage.internal.cli.StandardOption.LINUX_DEB_MAINTAINER_EMAIL;
|
||||
import static jdk.jpackage.internal.cli.StandardOption.LINUX_MENU_GROUP;
|
||||
@ -39,6 +40,7 @@ import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB;
|
||||
import static jdk.jpackage.internal.model.StandardPackageType.LINUX_RPM;
|
||||
|
||||
import jdk.jpackage.internal.cli.Options;
|
||||
import jdk.jpackage.internal.model.DottedVersion;
|
||||
import jdk.jpackage.internal.model.Launcher;
|
||||
import jdk.jpackage.internal.model.LinuxApplication;
|
||||
import jdk.jpackage.internal.model.LinuxDebPackage;
|
||||
@ -67,6 +69,10 @@ final class LinuxFromOptions {
|
||||
|
||||
appBuilder.launchers().map(LinuxPackagingPipeline::normalizeShortcuts).ifPresent(appBuilder::launchers);
|
||||
|
||||
if (OptionUtils.bundlingOperation(options) == CREATE_LINUX_RPM) {
|
||||
appBuilder.derivedVersionNormalizer(LinuxFromOptions::normalizeRpmVersion);
|
||||
}
|
||||
|
||||
return LinuxApplication.create(appBuilder.create());
|
||||
}
|
||||
|
||||
@ -118,4 +124,15 @@ final class LinuxFromOptions {
|
||||
return pkgBuilder;
|
||||
}
|
||||
|
||||
private static String normalizeRpmVersion(String version) {
|
||||
// RPM does not support "-" symbol in version. In some case
|
||||
// we might have "-" from "release" file version.
|
||||
// Normalize version if it has "-" symbols. All other supported version
|
||||
// formats by "release" file should be supported by RPM.
|
||||
if (version.contains("-")) {
|
||||
return DottedVersion.lazy(version).toComponentsString();
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,7 +31,6 @@ import static jdk.jpackage.internal.MacRuntimeValidator.validateRuntimeHasJliLib
|
||||
import static jdk.jpackage.internal.MacRuntimeValidator.validateRuntimeHasNoBinDir;
|
||||
import static jdk.jpackage.internal.OptionUtils.isBundlingOperation;
|
||||
import static jdk.jpackage.internal.cli.StandardBundlingOperation.CREATE_MAC_PKG;
|
||||
import static jdk.jpackage.internal.cli.StandardBundlingOperation.SIGN_MAC_APP_IMAGE;
|
||||
import static jdk.jpackage.internal.cli.StandardOption.APPCLASS;
|
||||
import static jdk.jpackage.internal.cli.StandardOption.ICON;
|
||||
import static jdk.jpackage.internal.cli.StandardOption.MAC_APP_CATEGORY;
|
||||
@ -65,6 +64,7 @@ import jdk.jpackage.internal.cli.OptionValue;
|
||||
import jdk.jpackage.internal.cli.Options;
|
||||
import jdk.jpackage.internal.cli.StandardFaOption;
|
||||
import jdk.jpackage.internal.model.ApplicationLaunchers;
|
||||
import jdk.jpackage.internal.model.DottedVersion;
|
||||
import jdk.jpackage.internal.model.ExternalApplication;
|
||||
import jdk.jpackage.internal.model.FileAssociation;
|
||||
import jdk.jpackage.internal.model.Launcher;
|
||||
@ -234,7 +234,7 @@ final class MacFromOptions {
|
||||
superAppBuilder.launchers(new ApplicationLaunchers(MacLauncher.create(mainLauncher), launchers.additionalLaunchers()));
|
||||
}
|
||||
|
||||
final var app = superAppBuilder.create();
|
||||
superAppBuilder.derivedVersionNormalizer(MacFromOptions::normalizeVersion);
|
||||
|
||||
return superAppBuilder;
|
||||
}
|
||||
@ -389,4 +389,11 @@ final class MacFromOptions {
|
||||
private static boolean hasPkgInstallerSignIdentity(Options options) {
|
||||
return options.contains(MAC_SIGNING_KEY_NAME) || options.contains(MAC_INSTALLER_SIGN_IDENTITY);
|
||||
}
|
||||
|
||||
private static String normalizeVersion(String version) {
|
||||
// macOS requires 1, 2 or 3 components version string.
|
||||
// When reading from release file it can be 1 or 3 or maybe more.
|
||||
// We will always normalize to 3 components if needed.
|
||||
return DottedVersion.lazy(version).trim(3).toComponentsString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,17 +36,20 @@ 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;
|
||||
import jdk.jpackage.internal.model.ExternalApplication;
|
||||
import jdk.jpackage.internal.model.Launcher;
|
||||
import jdk.jpackage.internal.model.LauncherIcon;
|
||||
import jdk.jpackage.internal.model.LauncherModularStartupInfo;
|
||||
import jdk.jpackage.internal.model.LauncherStartupInfo;
|
||||
import jdk.jpackage.internal.model.ResourceDirLauncherIcon;
|
||||
import jdk.jpackage.internal.model.RuntimeBuilder;
|
||||
import jdk.jpackage.internal.model.RuntimeLayout;
|
||||
import jdk.jpackage.internal.util.RootedPath;
|
||||
import jdk.jpackage.internal.util.RuntimeReleaseFile;
|
||||
|
||||
final class ApplicationBuilder {
|
||||
|
||||
@ -65,6 +68,8 @@ final class ApplicationBuilder {
|
||||
appImageLayout = other.appImageLayout;
|
||||
runtimeBuilder = other.runtimeBuilder;
|
||||
launchers = other.launchers;
|
||||
runtimeReleaseFile = other.runtimeReleaseFile;
|
||||
derivedVersionNormalizer = other.derivedVersionNormalizer;
|
||||
}
|
||||
|
||||
ApplicationBuilder copy() {
|
||||
@ -86,7 +91,7 @@ final class ApplicationBuilder {
|
||||
return new Application.Stub(
|
||||
effectiveName,
|
||||
Optional.ofNullable(description).orElse(effectiveName),
|
||||
Optional.ofNullable(version).orElseGet(DEFAULTS::version),
|
||||
validatedVersion(),
|
||||
Optional.ofNullable(vendor).orElseGet(DEFAULTS::vendor),
|
||||
Optional.ofNullable(copyright).orElseGet(DEFAULTS::copyright),
|
||||
Optional.ofNullable(appDirSources).orElseGet(List::of),
|
||||
@ -147,6 +152,11 @@ final class ApplicationBuilder {
|
||||
|
||||
Optional<String> version() {
|
||||
return Optional.ofNullable(version);
|
||||
}
|
||||
|
||||
ApplicationBuilder runtimeReleaseFile(Path v) {
|
||||
runtimeReleaseFile = v;
|
||||
return this;
|
||||
}
|
||||
|
||||
ApplicationBuilder vendor(String v) {
|
||||
@ -169,6 +179,54 @@ final class ApplicationBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
ApplicationBuilder derivedVersionNormalizer(UnaryOperator<String> v) {
|
||||
derivedVersionNormalizer = v;
|
||||
return this;
|
||||
}
|
||||
|
||||
private String validatedVersion() {
|
||||
return Optional.ofNullable(version).or(() -> {
|
||||
// Application version has not been specified explicitly. Derive it.
|
||||
var derivedVersion = derivedVersion();
|
||||
if (derivedVersionNormalizer != null) {
|
||||
derivedVersion = derivedVersion.map(v -> {
|
||||
var mappedVersion = derivedVersionNormalizer.apply(v);
|
||||
if (!mappedVersion.equals(v)) {
|
||||
Log.verbose(I18N.format("message.version-normalized", mappedVersion, v));
|
||||
}
|
||||
return mappedVersion;
|
||||
});
|
||||
}
|
||||
return derivedVersion;
|
||||
}).orElseGet(DEFAULTS::version);
|
||||
}
|
||||
|
||||
private Optional<String> derivedVersion() {
|
||||
if (appImageLayout instanceof RuntimeLayout && runtimeReleaseFile != null) {
|
||||
try {
|
||||
var releaseVersion = new RuntimeReleaseFile(runtimeReleaseFile).getJavaVersion().toString();
|
||||
Log.verbose(I18N.format("message.release-version", releaseVersion));
|
||||
return Optional.of(releaseVersion);
|
||||
} catch (Exception ex) {
|
||||
Log.verbose(ex);
|
||||
return Optional.empty();
|
||||
}
|
||||
} else if (launchers != null) {
|
||||
return launchers.mainLauncher().startupInfo()
|
||||
.filter(LauncherModularStartupInfo.class::isInstance)
|
||||
.map(LauncherModularStartupInfo.class::cast)
|
||||
.flatMap(modularStartupInfo -> {
|
||||
var moduleVersion = modularStartupInfo.moduleVersion();
|
||||
moduleVersion.ifPresent(v -> {
|
||||
Log.verbose(I18N.format("message.module-version", v, modularStartupInfo.moduleName()));
|
||||
});
|
||||
return moduleVersion;
|
||||
});
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
static <T extends Launcher> ApplicationLaunchers normalizeIcons(
|
||||
ApplicationLaunchers appLaunchers, Optional<Path> resourceDir, BiFunction<T, Launcher, T> launcherOverrideCtor) {
|
||||
|
||||
@ -333,6 +391,8 @@ final class ApplicationBuilder {
|
||||
private AppImageLayout appImageLayout;
|
||||
private RuntimeBuilder runtimeBuilder;
|
||||
private ApplicationLaunchers launchers;
|
||||
private Path runtimeReleaseFile;
|
||||
private UnaryOperator<String> derivedVersionNormalizer;
|
||||
|
||||
private static final Defaults DEFAULTS = new Defaults(
|
||||
"1.0",
|
||||
|
||||
@ -59,10 +59,10 @@ import jdk.jpackage.internal.model.Application;
|
||||
import jdk.jpackage.internal.model.ApplicationLaunchers;
|
||||
import jdk.jpackage.internal.model.ApplicationLayout;
|
||||
import jdk.jpackage.internal.model.Launcher;
|
||||
import jdk.jpackage.internal.model.LauncherModularStartupInfo;
|
||||
import jdk.jpackage.internal.model.PackageType;
|
||||
import jdk.jpackage.internal.model.RuntimeLayout;
|
||||
import jdk.jpackage.internal.util.RootedPath;
|
||||
import jdk.jpackage.internal.util.RuntimeReleaseFile;
|
||||
|
||||
final class FromOptions {
|
||||
|
||||
@ -212,19 +212,6 @@ final class FromOptions {
|
||||
|
||||
runtimeBuilderBuilder.modulePath(ensureBaseModuleInModulePath(MODULE_PATH.findIn(options).orElseGet(List::of)));
|
||||
|
||||
if (!APP_VERSION.containsIn(options)) {
|
||||
// Version is not specified explicitly. Try to get it from the app's module.
|
||||
launchers.mainLauncher().startupInfo().ifPresent(startupInfo -> {
|
||||
if (startupInfo instanceof LauncherModularStartupInfo modularStartupInfo) {
|
||||
modularStartupInfo.moduleVersion().ifPresent(moduleVersion -> {
|
||||
appBuilder.version(moduleVersion);
|
||||
Log.verbose(I18N.format("message.module-version",
|
||||
moduleVersion, modularStartupInfo.moduleName()));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
predefinedRuntimeDirectory.ifPresentOrElse(runtimeBuilderBuilder::forRuntime, () -> {
|
||||
final var startupInfos = launchers.asList().stream()
|
||||
.map(Launcher::startupInfo)
|
||||
@ -239,6 +226,8 @@ final class FromOptions {
|
||||
}
|
||||
}
|
||||
|
||||
predefinedRuntimeDirectory.map(RuntimeReleaseFile::releaseFilePathInRuntime).ifPresent(appBuilder::runtimeReleaseFile);
|
||||
|
||||
return appBuilder;
|
||||
}
|
||||
|
||||
|
||||
@ -24,17 +24,13 @@
|
||||
*/
|
||||
package jdk.jpackage.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
import jdk.jpackage.internal.util.RuntimeReleaseFile;
|
||||
|
||||
record ModuleInfo(String name, Optional<String> version, Optional<String> mainClass, Optional<URI> location) {
|
||||
|
||||
@ -56,30 +52,16 @@ record ModuleInfo(String name, Optional<String> version, Optional<String> mainCl
|
||||
// We can't extract info about version and main class of a module
|
||||
// linked in external runtime without running ModuleFinder in that
|
||||
// runtime. But this is too much work as the runtime might have been
|
||||
// coocked without native launchers. So just make sure the module
|
||||
// is linked in the runtime by simply analysing the data
|
||||
// cooked without native launchers. So just make sure the module
|
||||
// is linked in the runtime by simply analyzing the data
|
||||
// of `release` file.
|
||||
|
||||
final Path releaseFile = cookedRuntime.resolve("release");
|
||||
|
||||
try (Reader reader = Files.newBufferedReader(releaseFile)) {
|
||||
Properties props = new Properties();
|
||||
props.load(reader);
|
||||
String moduleList = props.getProperty("MODULES");
|
||||
if (moduleList == null) {
|
||||
try {
|
||||
var cookedRuntimeModules = RuntimeReleaseFile.loadFromRuntime(cookedRuntime).getModules();
|
||||
if (!cookedRuntimeModules.contains(moduleName)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
if ((moduleList.startsWith("\"") && moduleList.endsWith("\""))
|
||||
|| (moduleList.startsWith("\'") && moduleList.endsWith(
|
||||
"\'"))) {
|
||||
moduleList = moduleList.substring(1, moduleList.length() - 1);
|
||||
}
|
||||
|
||||
if (!List.of(moduleList.split("\\s+")).contains(moduleName)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
} catch (IOException|IllegalArgumentException ex) {
|
||||
} catch (Exception ex) {
|
||||
Log.verbose(ex);
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@ -52,6 +52,8 @@ message.app-image-created=Succeeded in building output application image directo
|
||||
message.debug-working-directory=Kept working directory for debug: {0}
|
||||
|
||||
message.module-version=Using version "{0}" from module "{1}" as application version
|
||||
message.release-version=Using version "{0}" from "release" file of the predefined runtime as a package version
|
||||
message.version-normalized=Using version "{0}" normalized to platform supported format from "{1}"
|
||||
|
||||
message.error-header=Error: {0}
|
||||
message.advice-header=Advice to fix: {0}
|
||||
|
||||
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
|
||||
public final class RuntimeReleaseFile {
|
||||
|
||||
public RuntimeReleaseFile(Path releaseFilePath) throws IOException {
|
||||
// The implementation is based on the behavior of
|
||||
// jdk.tools.jlink.internal.plugins.ReleaseInfoPlugin, which
|
||||
// uses java.util.Properties to read/write the "release" file.
|
||||
try (Reader reader = Files.newBufferedReader(releaseFilePath)) {
|
||||
props = new Properties();
|
||||
props.load(reader);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns path to the "runtime" file in the specified runtime directory.
|
||||
*
|
||||
* @param runtimeDir the path to a directory with the standard Java runtime
|
||||
* structure
|
||||
*/
|
||||
public static Path releaseFilePathInRuntime(Path runtimeDir) {
|
||||
return runtimeDir.resolve("release");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the instance form the "runtime" file in the specified runtime
|
||||
* directory.
|
||||
* <p>
|
||||
* Uses {@link #releaseFilePathInRuntime(Path)} to get the path to the "runtime"
|
||||
* file in the specified runtime directory.
|
||||
*
|
||||
* @param runtimeDir the path to a directory with the standard Java runtime
|
||||
* structure
|
||||
*/
|
||||
public static RuntimeReleaseFile loadFromRuntime(Path runtimeDir) throws IOException {
|
||||
return new RuntimeReleaseFile(releaseFilePathInRuntime(runtimeDir));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns verbatim value of the property with the specified name or an empty
|
||||
* {@code Optional} if there is no property with the specified name.
|
||||
* <p>
|
||||
* Property values in the "release" file are enclosed in double quotes.
|
||||
* This method returns the value with the double quotes.
|
||||
*
|
||||
* @param propertyName the property name
|
||||
*/
|
||||
public Optional<String> findRawProperty(String propertyName) {
|
||||
return Optional.ofNullable(props.getProperty(propertyName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns unquoted value of the property with the specified name or an empty
|
||||
* {@code Optional} if there is no property with the specified name.
|
||||
* <p>
|
||||
* Property values in the "release" file are enclosed in double quotes. This
|
||||
* method returns the value without the double quotes.
|
||||
*
|
||||
* @param propertyName the property name
|
||||
*/
|
||||
public Optional<String> findProperty(String propertyName) {
|
||||
return findRawProperty(propertyName).map(v -> {
|
||||
if (v.charAt(0) == '"' && v.charAt(v.length() - 1) == '"') {
|
||||
return v.substring(1, v.length() - 1);
|
||||
} else {
|
||||
return v;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the "JAVA_VERSION" property.
|
||||
* <p>
|
||||
* Will throw {@code NoSuchElementException} if there is no such property. Will
|
||||
* use {@link Runtime.Version#parse(String)} method to parse version string. Any
|
||||
* exception that it may yield will be passed to the caller verbatim.
|
||||
*
|
||||
* @throws NoSuchElementException if there is no such property
|
||||
*/
|
||||
public Runtime.Version getJavaVersion() {
|
||||
return findProperty("JAVA_VERSION").map(Runtime.Version::parse).orElseThrow(NoSuchElementException::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the "MODULES" property.
|
||||
*
|
||||
* @throws NoSuchElementException if there is no such property
|
||||
*/
|
||||
public List<String> getModules() {
|
||||
return findProperty("MODULES").map(v -> {
|
||||
return List.of(v.split("\\s+"));
|
||||
}).orElseThrow(NoSuchElementException::new);
|
||||
}
|
||||
|
||||
private final Properties props;
|
||||
}
|
||||
@ -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
|
||||
@ -42,6 +42,7 @@ import static jdk.jpackage.internal.cli.StandardOption.WIN_UPGRADE_UUID;
|
||||
import static jdk.jpackage.internal.model.StandardPackageType.WIN_MSI;
|
||||
|
||||
import jdk.jpackage.internal.cli.Options;
|
||||
import jdk.jpackage.internal.model.DottedVersion;
|
||||
import jdk.jpackage.internal.model.Launcher;
|
||||
import jdk.jpackage.internal.model.WinApplication;
|
||||
import jdk.jpackage.internal.model.WinExePackage;
|
||||
@ -73,6 +74,8 @@ final class WinFromOptions {
|
||||
|
||||
appBuilder.launchers().map(WinPackagingPipeline::normalizeShortcuts).ifPresent(appBuilder::launchers);
|
||||
|
||||
appBuilder.derivedVersionNormalizer(WinFromOptions::normalizeVersion);
|
||||
|
||||
return WinApplication.create(appBuilder.create());
|
||||
}
|
||||
|
||||
@ -112,4 +115,11 @@ final class WinFromOptions {
|
||||
|
||||
return pkgBuilder.create();
|
||||
}
|
||||
|
||||
private static String normalizeVersion(String version) {
|
||||
// Windows requires between 2 and 4 components version string.
|
||||
// When reading from release file it can be 1 or 3 or maybe more.
|
||||
// One component will be normalized to 2 and more then 4 will be trim to 4.
|
||||
return DottedVersion.lazy(version).trim(4).pad(2).toComponentsString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ requires.properties = \
|
||||
jpackage.test.SQETest \
|
||||
jpackage.test.MacSignTests
|
||||
|
||||
maxOutputSize = 2000000
|
||||
maxOutputSize = 10000000
|
||||
|
||||
# Run jpackage tests on windows platform sequentially.
|
||||
# Having "share" directory in the list affects tests on other platforms.
|
||||
|
||||
@ -26,6 +26,7 @@ import static java.util.stream.Collectors.toMap;
|
||||
import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer;
|
||||
import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction;
|
||||
import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier;
|
||||
import static jdk.jpackage.test.JPackageCommand.DEFAULT_VERSION;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
@ -65,7 +66,7 @@ public record AppImageFile(String mainLauncherName, Optional<String> mainLaunche
|
||||
}
|
||||
|
||||
public AppImageFile(String mainLauncherName, Optional<String> mainLauncherClassName) {
|
||||
this(mainLauncherName, mainLauncherClassName, "1.0", false, Map.of(mainLauncherName, Map.of()));
|
||||
this(mainLauncherName, mainLauncherClassName, DEFAULT_VERSION, false, Map.of(mainLauncherName, Map.of()));
|
||||
}
|
||||
|
||||
public AppImageFile(String mainLauncherName, String mainLauncherClassName) {
|
||||
|
||||
@ -43,6 +43,7 @@ import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
@ -60,7 +61,10 @@ import java.util.spi.ToolProvider;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
import jdk.jpackage.internal.model.DottedVersion;
|
||||
import jdk.jpackage.internal.util.MacBundle;
|
||||
import jdk.jpackage.internal.util.Result;
|
||||
import jdk.jpackage.internal.util.RuntimeReleaseFile;
|
||||
import jdk.jpackage.internal.util.function.ExceptionBox;
|
||||
import jdk.jpackage.internal.util.function.ThrowingConsumer;
|
||||
import jdk.jpackage.internal.util.function.ThrowingFunction;
|
||||
@ -102,6 +106,7 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
|
||||
executeInDirectory = cmd.executeInDirectory;
|
||||
winMsiLogFile = cmd.winMsiLogFile;
|
||||
unpackedPackageDirectory = cmd.unpackedPackageDirectory;
|
||||
explicitVersion = cmd.explicitVersion;
|
||||
}
|
||||
|
||||
JPackageCommand createImmutableCopy() {
|
||||
@ -246,22 +251,100 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
|
||||
|
||||
public String version() {
|
||||
return PropertyFinder.findAppProperty(this,
|
||||
PropertyFinder.cmdlineOptionWithValue("--app-version").or(cmd -> {
|
||||
if (cmd.isRuntime() && PackageType.MAC.contains(cmd.packageType())) {
|
||||
// This is a macOS runtime bundle.
|
||||
var predefinedRuntimeBundle = MacBundle.fromPath(Path.of(cmd.getArgumentValue("--runtime-image")));
|
||||
if (predefinedRuntimeBundle.isPresent()) {
|
||||
// This is a macOS runtime bundle created from the predefined runtime bundle (not a predefined runtime directory).
|
||||
// The version of this bundle should be copied from the Info.plist file of the predefined runtime bundle.
|
||||
return MacHelper.readPList(predefinedRuntimeBundle.get().infoPlistFile()).findValue("CFBundleVersion");
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}),
|
||||
PropertyFinder.<JPackageCommand>of(Optional.ofNullable(explicitVersion))
|
||||
.or(PropertyFinder.cmdlineOptionWithValue("--app-version"))
|
||||
.or(JPackageCommand::derivedVersion),
|
||||
PropertyFinder.appImageFile(appImageFile -> {
|
||||
return appImageFile.version();
|
||||
})
|
||||
).orElse("1.0");
|
||||
).orElse(DEFAULT_VERSION);
|
||||
}
|
||||
|
||||
private Optional<String> derivedVersion() {
|
||||
if (isRuntime()) {
|
||||
var predefinedRuntimePath = Path.of(getArgumentValue("--runtime-image"));
|
||||
if (TKit.isOSX()) {
|
||||
// This is a macOS runtime bundle.
|
||||
return MacBundle.fromPath(predefinedRuntimePath).map(predefinedRuntimeBundle -> {
|
||||
return Result.<Optional<String>>of(() -> {
|
||||
// This is a macOS runtime bundle created from the predefined runtime bundle (not a predefined runtime directory).
|
||||
// The version of this bundle should be copied from the Info.plist file of the predefined runtime bundle.
|
||||
return MacHelper.readPList(predefinedRuntimeBundle.infoPlistFile()).findValue("CFBundleVersion");
|
||||
}).value().flatMap(x -> x).or(() -> {
|
||||
// Failed to read version from the Info.plist file of the predefined runtime bundle.
|
||||
// Try to read it from the "release" file of the predefined runtime directory.
|
||||
return normalizedVersionFromRuntimeReleaseFile(predefinedRuntimeBundle.homeDir());
|
||||
});
|
||||
}).orElseGet(() -> {
|
||||
return normalizedVersionFromRuntimeReleaseFile(predefinedRuntimePath);
|
||||
});
|
||||
} else {
|
||||
return normalizedVersionFromRuntimeReleaseFile(predefinedRuntimePath);
|
||||
}
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<String> normalizedVersionFromRuntimeReleaseFile(Path runtimeDir) {
|
||||
return Result.of(() -> {
|
||||
return RuntimeReleaseFile.loadFromRuntime(runtimeDir).getJavaVersion().toString();
|
||||
}, Exception.class).value().map(JPackageCommand::normalizeDerivedVersion).map(map -> {
|
||||
return Objects.requireNonNull(map.get(packageType()));
|
||||
});
|
||||
}
|
||||
|
||||
public static Map<PackageType, String> normalizeDerivedVersion(String version) {
|
||||
var dotted = DottedVersion.lazy(version);
|
||||
|
||||
var map = new HashMap<PackageType, String>();
|
||||
|
||||
// Linux
|
||||
map.put(PackageType.LINUX_IMAGE, version);
|
||||
map.put(PackageType.LINUX_DEB, version);
|
||||
if (dotted.getUnprocessedSuffix().contains("-")) {
|
||||
map.put(PackageType.LINUX_RPM, dotted.toComponentsString());
|
||||
} else {
|
||||
map.put(PackageType.LINUX_RPM, version);
|
||||
}
|
||||
|
||||
// macOS
|
||||
PackageType.ALL_MAC.forEach(type -> {
|
||||
map.put(type, dotted.trim(3).pad(1).toComponentsString());
|
||||
});
|
||||
|
||||
// Windows
|
||||
PackageType.ALL_WINDOWS.forEach(type -> {
|
||||
DottedVersion ver;
|
||||
if (dotted.getComponentsCount() < 2) {
|
||||
ver = dotted.pad(2);
|
||||
} else {
|
||||
ver = dotted.trim(4);
|
||||
}
|
||||
map.put(type, ver.toComponentsString());
|
||||
});
|
||||
|
||||
map.put(PackageType.IMAGE, Objects.requireNonNull(map.get(PackageType.appImageForOS(PackageType.IMAGE.os()))));
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets application version.
|
||||
* <p>
|
||||
* Use this method to explicitly set the application version. Normally, the
|
||||
* application version can be derived from the command line, but sometimes, when
|
||||
* jpackage derives it from other sources, the {@code JPackageCommand} class
|
||||
* can't get it correctly. Use this method in these uncommon cases.
|
||||
*
|
||||
* @param v the application version or {@code null} to reset previously set
|
||||
* value
|
||||
* @return this
|
||||
*/
|
||||
public JPackageCommand version(String v) {
|
||||
verifyMutable();
|
||||
explicitVersion = v;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
@ -1930,6 +2013,7 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
|
||||
private Path executeInDirectory;
|
||||
private Path winMsiLogFile;
|
||||
private Path unpackedPackageDirectory;
|
||||
private String explicitVersion;
|
||||
private Set<ReadOnlyPathAssert> readOnlyPathAsserts = Set.of(ReadOnlyPathAssert.values());
|
||||
private Set<StandardAssert> standardAsserts = Set.of(StandardAssert.values());
|
||||
private List<Consumer<Executor.Result>> validators = new ArrayList<>();
|
||||
@ -1938,7 +2022,9 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
|
||||
VALUE
|
||||
}
|
||||
|
||||
private static final Map<String, PackageType> PACKAGE_TYPES = Stream.of(PackageType.values()).collect(toMap(PackageType::getType, x -> x));
|
||||
private static final Map<String, PackageType> PACKAGE_TYPES = Stream.of(PackageType.values()).filter(type -> {
|
||||
return type.isNative() || type == PackageType.IMAGE;
|
||||
}).collect(toMap(PackageType::getType, x -> x));
|
||||
|
||||
// Set the property to the path of run-time image to speed up
|
||||
// building app images and platform bundles by avoiding running jlink.
|
||||
@ -1947,6 +2033,8 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
|
||||
// `--runtime-image` parameter set.
|
||||
public static final Path DEFAULT_RUNTIME_IMAGE = Optional.ofNullable(TKit.getConfigProperty("runtime-image")).map(Path::of).orElse(null);
|
||||
|
||||
public final static String DEFAULT_VERSION = "1.0";
|
||||
|
||||
// [HH:mm:ss.SSS]
|
||||
private static final Pattern TIMESTAMP_REGEXP = Pattern.compile(
|
||||
"^\\[\\d\\d:\\d\\d:\\d\\d.\\d\\d\\d\\] ");
|
||||
|
||||
@ -48,16 +48,22 @@ public enum PackageType {
|
||||
LINUX_RPM(".rpm", OperatingSystem.LINUX),
|
||||
MAC_DMG(".dmg", OperatingSystem.MACOS),
|
||||
MAC_PKG(".pkg", OperatingSystem.MACOS),
|
||||
IMAGE;
|
||||
IMAGE(OperatingSystem.current()),
|
||||
WIN_IMAGE(OperatingSystem.WINDOWS),
|
||||
LINUX_IMAGE(OperatingSystem.LINUX),
|
||||
MAC_IMAGE(OperatingSystem.MACOS),
|
||||
;
|
||||
|
||||
PackageType() {
|
||||
PackageType(OperatingSystem os) {
|
||||
this.os = Objects.requireNonNull(os);
|
||||
type = "app-image";
|
||||
suffix = null;
|
||||
supported = true;
|
||||
enabled = true;
|
||||
supported = (os == OperatingSystem.current());
|
||||
enabled = supported;
|
||||
}
|
||||
|
||||
PackageType(String packageName, String bundleSuffix, OperatingSystem os) {
|
||||
this.os = Objects.requireNonNull(os);
|
||||
type = Objects.requireNonNull(packageName);
|
||||
suffix = Objects.requireNonNull(bundleSuffix);
|
||||
supported = isSupported(new BundlingOperationDescriptor(os, type));
|
||||
@ -88,10 +94,29 @@ public enum PackageType {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public boolean isAppImage() {
|
||||
return type.equals(IMAGE.type);
|
||||
}
|
||||
|
||||
public boolean isNative() {
|
||||
return !isAppImage();
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public OperatingSystem os() {
|
||||
return os;
|
||||
}
|
||||
|
||||
public static PackageType appImageForOS(OperatingSystem os) {
|
||||
Objects.requireNonNull(os);
|
||||
return Stream.of(LINUX_IMAGE, MAC_IMAGE, WIN_IMAGE).filter(type -> {
|
||||
return type.os() == os;
|
||||
}).findFirst().orElseThrow();
|
||||
}
|
||||
|
||||
public static RuntimeException throwSkippedExceptionIfNativePackagingUnavailable() {
|
||||
if (NATIVE.stream().noneMatch(PackageType::isSupported)) {
|
||||
TKit.throwSkippedException("None of the native packagers supported in this environment");
|
||||
@ -115,6 +140,7 @@ public enum PackageType {
|
||||
return new LinkedHashSet<>(List.of(types));
|
||||
}
|
||||
|
||||
private final OperatingSystem os;
|
||||
private final String type;
|
||||
private final String suffix;
|
||||
private final boolean enabled;
|
||||
@ -126,6 +152,10 @@ public enum PackageType {
|
||||
public static final Set<PackageType> NATIVE = Stream.of(LINUX, WINDOWS, MAC)
|
||||
.flatMap(Collection::stream).collect(Collectors.toUnmodifiableSet());
|
||||
|
||||
public static final Set<PackageType> ALL_LINUX = orderedSet(LINUX_IMAGE, LINUX_DEB, LINUX_RPM);
|
||||
public static final Set<PackageType> ALL_WINDOWS = orderedSet(WIN_IMAGE, WIN_MSI, WIN_EXE);
|
||||
public static final Set<PackageType> ALL_MAC = orderedSet(MAC_IMAGE, MAC_DMG, MAC_PKG);
|
||||
|
||||
private static final class Inner {
|
||||
private static final Set<String> DISABLED_PACKAGERS = Optional.ofNullable(
|
||||
TKit.tokenizeConfigProperty("disabledPackagers")).orElse(
|
||||
|
||||
@ -22,18 +22,19 @@
|
||||
*/
|
||||
package jdk.jpackage.internal.model;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
@ -54,14 +55,6 @@ public class DottedVersionTest {
|
||||
this(input, type.createVersion, "", expectedComponentCount, input);
|
||||
}
|
||||
|
||||
static TestConfig greedy(String input, int expectedComponentCount, String expectedToComponent) {
|
||||
return new TestConfig(input, Type.GREEDY.createVersion, "", expectedComponentCount, expectedToComponent);
|
||||
}
|
||||
|
||||
static TestConfig greedy(String input, int expectedComponentCount) {
|
||||
return new TestConfig(input, Type.GREEDY.createVersion, "", expectedComponentCount, input);
|
||||
}
|
||||
|
||||
static TestConfig lazy(String input, String expectedSuffix, int expectedComponentCount, String expectedToComponent) {
|
||||
return new TestConfig(input, Type.LAZY.createVersion, expectedSuffix, expectedComponentCount, expectedToComponent);
|
||||
}
|
||||
@ -74,6 +67,7 @@ public class DottedVersionTest {
|
||||
assertEquals(cfg.expectedSuffix(), dv.getUnprocessedSuffix());
|
||||
assertEquals(cfg.expectedComponentCount(), dv.getComponents().length);
|
||||
assertEquals(cfg.expectedToComponent(), dv.toComponentsString());
|
||||
assertEquals(dv.toString(), cfg.input());
|
||||
}
|
||||
|
||||
private static List<TestConfig> testValid() {
|
||||
@ -123,7 +117,7 @@ public class DottedVersionTest {
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource
|
||||
public void testTrim(DottedVersion ver, String expectedStr, int limit) {
|
||||
public void test_trim(DottedVersion ver, String expectedStr, int limit) {
|
||||
var expected = DottedVersion.lazy(expectedStr);
|
||||
var actual = ver.trim(limit);
|
||||
assertEquals(expected, actual);
|
||||
@ -136,14 +130,14 @@ public class DottedVersionTest {
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource
|
||||
public void testTrimNegative(DottedVersion ver, int limit) {
|
||||
@MethodSource("test_trim_pad_negative")
|
||||
public void test_trim_negative(DottedVersion ver, int limit) {
|
||||
assertThrowsExactly(IllegalArgumentException.class, () -> {
|
||||
ver.trim(limit);
|
||||
});
|
||||
}
|
||||
|
||||
private static Stream<Arguments> testTrim() {
|
||||
private static Stream<Arguments> test_trim() {
|
||||
|
||||
var testCases = new ArrayList<Arguments>();
|
||||
|
||||
@ -160,15 +154,9 @@ public class DottedVersionTest {
|
||||
return testCases.stream().map(DottedVersionTest::mapFirstStringToDottedVersion);
|
||||
}
|
||||
|
||||
private static Stream<Arguments> testTrimNegative() {
|
||||
return Stream.of(
|
||||
Arguments.of("10.5.foo", -1)
|
||||
).map(DottedVersionTest::mapFirstStringToDottedVersion);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource
|
||||
public void testPad(DottedVersion ver, String expectedStr, int limit) {
|
||||
public void test_pad(DottedVersion ver, String expectedStr, int limit) {
|
||||
var expected = DottedVersion.lazy(expectedStr);
|
||||
var actual = ver.pad(limit);
|
||||
assertEquals(expected, actual);
|
||||
@ -181,14 +169,14 @@ public class DottedVersionTest {
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource
|
||||
public void testPadNegative(DottedVersion ver, int limit) {
|
||||
@MethodSource("test_trim_pad_negative")
|
||||
public void test_pad_negative(DottedVersion ver, int limit) {
|
||||
assertThrowsExactly(IllegalArgumentException.class, () -> {
|
||||
ver.pad(limit);
|
||||
});
|
||||
}
|
||||
|
||||
private static Stream<Arguments> testPad() {
|
||||
private static Stream<Arguments> test_pad() {
|
||||
|
||||
var testCases = new ArrayList<Arguments>();
|
||||
|
||||
@ -206,7 +194,7 @@ public class DottedVersionTest {
|
||||
return testCases.stream().map(DottedVersionTest::mapFirstStringToDottedVersion);
|
||||
}
|
||||
|
||||
private static Stream<Arguments> testPadNegative() {
|
||||
private static Stream<Arguments> test_trim_pad_negative() {
|
||||
return Stream.of(
|
||||
Arguments.of("10.5.foo", -1)
|
||||
).map(DottedVersionTest::mapFirstStringToDottedVersion);
|
||||
|
||||
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* 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.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.io.Writer;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
|
||||
class RuntimeReleaseFileTest {
|
||||
|
||||
@Test
|
||||
void test_invalid_input(@TempDir Path workdir) {
|
||||
assertThrows(IOException.class, () -> {
|
||||
new RuntimeReleaseFile(workdir);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_findRawProperty(@TempDir Path workdir) throws IOException {
|
||||
var releaseFile = new RuntimeReleaseFile(createPropFile(workdir, Map.of("Name", "John", "Company", "\"Acme LTD\"")));
|
||||
|
||||
assertEquals(Optional.empty(), releaseFile.findRawProperty("foo"));
|
||||
assertEquals(Optional.of("John"), releaseFile.findRawProperty("Name"));
|
||||
assertEquals(Optional.of("\"Acme LTD\""), releaseFile.findRawProperty("Company"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_findProperty(@TempDir Path workdir) throws IOException {
|
||||
var releaseFile = new RuntimeReleaseFile(createPropFile(workdir, Map.of("Name", "John", "Company", "\"Acme LTD\"")));
|
||||
|
||||
assertEquals(Optional.empty(), releaseFile.findProperty("foo"));
|
||||
assertEquals(Optional.of("John"), releaseFile.findProperty("Name"));
|
||||
assertEquals(Optional.of("Acme LTD"), releaseFile.findProperty("Company"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
"foo, foo",
|
||||
"\"foo\", foo",
|
||||
"'foo', 'foo'",
|
||||
"\"f\"o\"o\", f\"o\"o",
|
||||
"\"foo, \"foo",
|
||||
"foo\", foo\"",
|
||||
})
|
||||
void test_findProperty(String rawValue, String expectedValue, @TempDir Path workdir) throws IOException {
|
||||
var releaseFile = new RuntimeReleaseFile(createPropFile(workdir, Map.of("FOO", rawValue)));
|
||||
|
||||
assertEquals(expectedValue, releaseFile.findProperty("FOO").orElseThrow());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
"\"27.1.2\", 27.1.2",
|
||||
"27.1.2, 27.1.2",
|
||||
"\"27.1.2-ea\", 27.1.2-ea",
|
||||
"27.1.2-ea, 27.1.2-ea",
|
||||
"\"27.1.2+15\", 27.1.2+15",
|
||||
"27.1.2+15, 27.1.2+15",
|
||||
})
|
||||
void test_getJavaVersion(String version, String expectedVersion, @TempDir Path workdir) throws IOException {
|
||||
var releaseFile = new RuntimeReleaseFile(createPropFileWithValue(workdir, "JAVA_VERSION", version));
|
||||
|
||||
final var value = releaseFile.getJavaVersion();
|
||||
|
||||
assertEquals(expectedVersion, value.toString());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
"\"7.1.2+foo\"",
|
||||
"\"foo\"",
|
||||
"\"\"",
|
||||
"7.1.2+foo",
|
||||
"foo",
|
||||
"''"
|
||||
})
|
||||
void test_getJavaVersion_invalid(String version, @TempDir Path workdir) throws IOException {
|
||||
var releaseFile = new RuntimeReleaseFile(createPropFileWithValue(workdir, "JAVA_VERSION", version));
|
||||
|
||||
var ex = assertThrows(RuntimeException.class, releaseFile::getJavaVersion);
|
||||
|
||||
assertFalse(NoSuchElementException.class.isInstance(ex));
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_without_version(@TempDir Path workdir) throws IOException {
|
||||
var releaseFile = new RuntimeReleaseFile(createPropFileWithValue(workdir, "JDK_VERSION", "\"27.1.2\""));
|
||||
|
||||
assertThrowsExactly(NoSuchElementException.class, releaseFile::getJavaVersion);
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_getModules(@TempDir Path workdir) throws IOException {
|
||||
var releaseFile = new RuntimeReleaseFile(createPropFileWithValue(workdir, "MODULES", "foo bar\t buz "));
|
||||
|
||||
assertEquals(List.of("foo", "bar", "buz"), releaseFile.getModules());
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_current() throws IOException {
|
||||
var releaseFile = new RuntimeReleaseFile(Path.of(System.getProperty("java.home")).resolve("release"));
|
||||
|
||||
final var expectedVersion = Runtime.version();
|
||||
final var actualVersion = releaseFile.getJavaVersion();
|
||||
|
||||
assertEquals(expectedVersion.version(), actualVersion.version());
|
||||
|
||||
final var expectedModules = ModuleFinder.ofSystem().findAll().stream()
|
||||
.map(ModuleReference::descriptor).map(ModuleDescriptor::name).sorted().toList();
|
||||
final var actualModules = releaseFile.getModules().stream().sorted().toList();
|
||||
|
||||
assertEquals(expectedModules, actualModules);
|
||||
}
|
||||
|
||||
private Path createPropFileWithValue(Path workdir, String name, String value) {
|
||||
return createPropFile(workdir, Map.of(name, value));
|
||||
}
|
||||
|
||||
private Path createPropFile(Path workdir, Map<String, String> input) {
|
||||
Path releaseFile = workdir.resolve("foo");
|
||||
Properties props = new Properties();
|
||||
props.putAll(input);
|
||||
|
||||
try (Writer writer = Files.newBufferedWriter(releaseFile)) {
|
||||
props.store(writer, null);
|
||||
} catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
|
||||
return releaseFile;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -23,6 +23,7 @@
|
||||
|
||||
import static jdk.internal.util.OperatingSystem.LINUX;
|
||||
import static jdk.internal.util.OperatingSystem.MACOS;
|
||||
import static jdk.jpackage.test.JPackageCommand.DEFAULT_VERSION;
|
||||
import static jdk.jpackage.test.TKit.assertFalse;
|
||||
import static jdk.jpackage.test.TKit.assertTrue;
|
||||
|
||||
@ -81,7 +82,16 @@ public class RuntimePackageTest {
|
||||
|
||||
@Test
|
||||
public static void test() {
|
||||
init().run();
|
||||
init()
|
||||
.addInitializer(cmd -> {
|
||||
// JDK-8357404 enables jpackage to pick a version from the "release" file
|
||||
// of the predefined runtime when bundling the runtime package.
|
||||
// This makes the output of this test dependent on the version of the running JDK
|
||||
// and will be an inconvenience for SQE testing.
|
||||
// Explicitly specify the package version to fulfill expectations of SQE.
|
||||
cmd.setArgumentValue("--app-version", DEFAULT_VERSION);
|
||||
})
|
||||
.run();
|
||||
}
|
||||
|
||||
@Test(ifOS = MACOS)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user