Skip to content

Commit b6c96c7

Browse files
committed
Introduce dedicated toolchain resolver for EA java versions
1 parent 969cf97 commit b6c96c7

File tree

8 files changed

+302
-14
lines changed

8 files changed

+302
-14
lines changed

build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/info/GlobalBuildInfoPlugin.java

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.gradle.jvm.toolchain.JavaToolchainService;
4141
import org.gradle.jvm.toolchain.JavaToolchainSpec;
4242
import org.gradle.jvm.toolchain.JvmVendorSpec;
43+
import org.gradle.jvm.toolchain.internal.DefaultJvmVendorSpec;
4344
import org.gradle.jvm.toolchain.internal.InstallationLocation;
4445
import org.gradle.util.GradleVersion;
4546
import org.jetbrains.annotations.NotNull;
@@ -63,6 +64,7 @@
6364
import javax.inject.Inject;
6465

6566
import static org.elasticsearch.gradle.internal.conventions.GUtils.elvis;
67+
import static org.elasticsearch.gradle.internal.toolchain.EarlyAccessCatalogJdkToolchainResolver.findLatestEABuildNumber;
6668

6769
public class GlobalBuildInfoPlugin implements Plugin<Project> {
6870
private static final Logger LOGGER = Logging.getLogger(GlobalBuildInfoPlugin.class);
@@ -338,6 +340,7 @@ private Provider<File> findRuntimeJavaHome() {
338340
String runtimeJavaProperty = System.getProperty("runtime.java");
339341

340342
if (runtimeJavaProperty != null) {
343+
System.out.println("GlobalBuildInfoPlugin.findRuntimeJavaHome");
341344
return resolveJavaHomeFromToolChainService(runtimeJavaProperty);
342345
}
343346
if (System.getenv("RUNTIME_JAVA_HOME") != null) {
@@ -355,9 +358,26 @@ private Provider<File> findRuntimeJavaHome() {
355358

356359
@NotNull
357360
private Provider<File> resolveJavaHomeFromToolChainService(String version) {
358-
Property<JavaLanguageVersion> value = objectFactory.property(JavaLanguageVersion.class).value(JavaLanguageVersion.of(version));
359-
return toolChainService.launcherFor(javaToolchainSpec -> javaToolchainSpec.getLanguageVersion().value(value))
360-
.map(launcher -> launcher.getMetadata().getInstallationPath().getAsFile());
361+
JavaLanguageVersion languageVersion = JavaLanguageVersion.of(version);
362+
Property<JavaLanguageVersion> value = objectFactory.property(JavaLanguageVersion.class).value(languageVersion);
363+
return toolChainService.launcherFor(javaToolchainSpec -> {
364+
javaToolchainSpec.getLanguageVersion().value(value);
365+
366+
if (Integer.parseInt(VersionProperties.getBundledJdkMajorVersion()) < Integer.parseInt(version)) {
367+
// If the requested version is higher than the bundled JDK, we need trick the toolchain into using our early access catalog
368+
// Otherwise, we use the default implementation
369+
Integer buildNumber = Integer.getInteger("runtime.java.build");
370+
371+
if (buildNumber == null) {
372+
buildNumber = Integer.getInteger("runtime.java." + version + ".build");
373+
}
374+
if (buildNumber == null) {
375+
buildNumber = findLatestEABuildNumber(languageVersion);
376+
}
377+
javaToolchainSpec.getVendor()
378+
.set(DefaultJvmVendorSpec.of("Oracle[" + languageVersion + "/" + buildNumber + "]"));
379+
}
380+
}).map(launcher -> launcher.getMetadata().getInstallationPath().getAsFile());
361381
}
362382

363383
public static String getResourceContents(String resourcePath) {
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.gradle.internal.toolchain;
11+
12+
import com.fasterxml.jackson.databind.JsonNode;
13+
import com.fasterxml.jackson.databind.ObjectMapper;
14+
import com.fasterxml.jackson.databind.node.ArrayNode;
15+
16+
import org.elasticsearch.gradle.VersionProperties;
17+
import org.gradle.jvm.toolchain.JavaLanguageVersion;
18+
import org.gradle.jvm.toolchain.JavaToolchainDownload;
19+
import org.gradle.jvm.toolchain.JavaToolchainRequest;
20+
import org.gradle.jvm.toolchain.JavaToolchainSpec;
21+
import org.gradle.jvm.toolchain.JvmVendorSpec;
22+
import org.gradle.jvm.toolchain.internal.DefaultJvmVendorSpec;
23+
import org.gradle.platform.Architecture;
24+
import org.gradle.platform.BuildPlatform;
25+
import org.gradle.platform.OperatingSystem;
26+
27+
import java.io.IOException;
28+
import java.io.InputStream;
29+
import java.net.MalformedURLException;
30+
import java.net.URI;
31+
import java.net.URL;
32+
import java.util.ArrayList;
33+
import java.util.List;
34+
import java.util.Optional;
35+
import java.util.regex.Matcher;
36+
import java.util.regex.Pattern;
37+
38+
public abstract class EarlyAccessCatalogJdkToolchainResolver extends AbstractCustomJavaToolchainResolver {
39+
40+
interface JdkBuild {
41+
JavaLanguageVersion languageVersion();
42+
43+
String url(String os, String arch, String extension);
44+
}
45+
46+
private static final Pattern PATTERN = Pattern.compile("Oracle\\[(\\d+)/(\\d+)\\]");
47+
48+
public static class EaCatalogVendorSpec extends JvmVendorSpec {
49+
50+
private final JavaLanguageVersion languageVersion;
51+
private final int buildNumber;
52+
53+
private EaCatalogVendorSpec(JavaLanguageVersion languageVersion, int buildNumber) {
54+
this.languageVersion = languageVersion;
55+
this.buildNumber = buildNumber;
56+
}
57+
58+
public static EaCatalogVendorSpec of(JavaLanguageVersion languageVersion, int buildNumber) {
59+
return new EaCatalogVendorSpec(languageVersion, buildNumber);
60+
}
61+
62+
@Override
63+
public boolean matches(String vendor) {
64+
return false;
65+
}
66+
67+
public int getBuildNumber() {
68+
return buildNumber;
69+
}
70+
}
71+
72+
@FunctionalInterface
73+
interface EarlyAccessJdkBuildResolver {
74+
Optional<? extends JdkBuild> findLatestEABuild(JavaLanguageVersion languageVersion);
75+
}
76+
77+
// allow overriding for testing
78+
EarlyAccessJdkBuildResolver earlyAccessJdkBuildResolver = (languageVersion) -> findLatestEABuild(languageVersion);
79+
80+
record EarlyAccessJdkBuild(JavaLanguageVersion languageVersion, int buildNumber) implements JdkBuild {
81+
@Override
82+
public String url(String os, String arch, String extension) {
83+
// example:
84+
// https://builds.es-jdk-archive.com/jdks/openjdk/26/openjdk-26-ea+6/openjdk-26-ea+6_linux-aarch64_bin.tar.gz
85+
return "https://builds.es-jdk-archive.com/jdks/openjdk/"
86+
+ languageVersion.asInt()
87+
+ "/"
88+
+ "openjdk-"
89+
+ languageVersion.asInt()
90+
+ "-ea+"
91+
+ buildNumber
92+
+ "/"
93+
+ "openjdk-"
94+
+ languageVersion.asInt()
95+
+ "-ea+"
96+
+ buildNumber
97+
+ "_"
98+
+ os
99+
+ "-"
100+
+ arch
101+
+ "_bin."
102+
+ extension;
103+
}
104+
}
105+
106+
private static final List<OperatingSystem> supportedOperatingSystems = List.of(
107+
OperatingSystem.MAC_OS,
108+
OperatingSystem.LINUX,
109+
OperatingSystem.WINDOWS
110+
);
111+
112+
// static EarlyAccessJdkBuild getEarlyAccessBuild(JavaLanguageVersion languageVersion, String buildNumber) {
113+
// // first try the unversioned override, then the versioned override which has higher precedence
114+
// buildNumber = System.getProperty("runtime.java.build", buildNumber);
115+
// buildNumber = System.getProperty("runtime.java." + languageVersion.asInt() + ".build", buildNumber);
116+
//
117+
// return new EarlyAccessJdkBuild(languageVersion, buildNumber);
118+
// }
119+
120+
/**
121+
* We need some place to map JavaLanguageVersion to buildNumber, minor version etc.
122+
* */
123+
@Override
124+
public Optional<JavaToolchainDownload> resolve(JavaToolchainRequest request) {
125+
if (Integer.parseInt(VersionProperties.getBundledJdkMajorVersion()) >= request.getJavaToolchainSpec()
126+
.getLanguageVersion()
127+
.get()
128+
.asInt()) {
129+
// This resolver only handles early access builds, that are beyond the last bundled jdk version
130+
}
131+
return findSupportedBuild(request).map(build -> {
132+
OperatingSystem operatingSystem = request.getBuildPlatform().getOperatingSystem();
133+
String extension = operatingSystem.equals(OperatingSystem.WINDOWS) ? "zip" : "tar.gz";
134+
String arch = toArchString(request.getBuildPlatform().getArchitecture());
135+
String os = toOsString(operatingSystem);
136+
return (JavaToolchainDownload) () -> URI.create(build.url(os, arch, extension));
137+
});
138+
}
139+
140+
/**
141+
* Check if request can be full-filled by this resolver:
142+
* 1. Aarch64 windows images are not supported
143+
*/
144+
private Optional<? extends JdkBuild> findSupportedBuild(JavaToolchainRequest request) {
145+
JavaToolchainSpec javaToolchainSpec = request.getJavaToolchainSpec();
146+
BuildPlatform buildPlatform = request.getBuildPlatform();
147+
Architecture architecture = buildPlatform.getArchitecture();
148+
OperatingSystem operatingSystem = buildPlatform.getOperatingSystem();
149+
150+
if (supportedOperatingSystems.contains(operatingSystem) == false
151+
|| Architecture.AARCH64 == architecture && OperatingSystem.WINDOWS == operatingSystem) {
152+
return Optional.empty();
153+
}
154+
155+
JavaLanguageVersion languageVersion = javaToolchainSpec.getLanguageVersion().get();
156+
// resolve from vendor spec if available
157+
if (javaToolchainSpec.getVendor().isPresent() && javaToolchainSpec.getVendor().get() instanceof DefaultJvmVendorSpec) {
158+
DefaultJvmVendorSpec spec = (DefaultJvmVendorSpec) javaToolchainSpec.getVendor().get();
159+
String criteria = spec.toCriteria();
160+
Matcher matcher = PATTERN.matcher(criteria);
161+
if (matcher.matches()) {
162+
int level = Integer.parseInt(matcher.group(1));
163+
int build = Integer.parseInt(matcher.group(2));
164+
assert level == languageVersion.asInt() : "Language version does not match: " + level + " != " + languageVersion.asInt();
165+
return Optional.of(new EarlyAccessJdkBuild(languageVersion, build));
166+
}
167+
}
168+
return findLatestEABuild(languageVersion);
169+
}
170+
171+
private static Optional<EarlyAccessJdkBuild> findLatestEABuild(JavaLanguageVersion languageVersion) {
172+
System.out.println("CatalogJdkToolchainResolver.findLatestEABuild");
173+
try {
174+
URL url = new URL("https://storage.googleapis.com/elasticsearch-jdk-archive/jdks/openjdk/latest.json");
175+
try (InputStream is = url.openStream()) {
176+
ObjectMapper mapper = new ObjectMapper();
177+
JsonNode node = mapper.readTree(is);
178+
ArrayNode buildsNode = (ArrayNode) node.get("builds");
179+
List<JsonNode> buildsList = new ArrayList<>();
180+
buildsNode.forEach(buildsList::add);
181+
List<EarlyAccessJdkBuild> eaBuilds = buildsList.stream()
182+
.map(
183+
n -> new EarlyAccessJdkBuild(
184+
JavaLanguageVersion.of(n.get("major").asText()),
185+
Integer.parseInt(n.get("build").asText())
186+
)
187+
)
188+
.toList();
189+
return eaBuilds.stream().filter(ea -> ea.languageVersion().equals(languageVersion)).findFirst();
190+
} catch (IOException e) {
191+
throw new RuntimeException(e);
192+
}
193+
} catch (MalformedURLException e) {
194+
return Optional.empty();
195+
}
196+
}
197+
198+
public static int findLatestEABuildNumber(JavaLanguageVersion languageVersion) {
199+
return findLatestEABuild(languageVersion).map(ea -> ea.buildNumber()).get();
200+
}
201+
}

build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/toolchain/JavaToolChainResolverPlugin.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public void apply(Settings settings) {
2323
settings.getPlugins().apply("jvm-toolchain-management");
2424
JavaToolchainResolverRegistry registry = getToolchainResolverRegistry();
2525
registry.register(OracleOpenJdkToolchainResolver.class);
26+
registry.register(EarlyAccessCatalogJdkToolchainResolver.class);
2627
registry.register(AdoptiumJdkToolchainResolver.class);
2728
registry.register(ArchivedOracleJdkToolchainResolver.class);
2829
}

build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/toolchain/OracleOpenJdkToolchainResolver.java

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,11 @@ public String url(String os, String arch, String extension) {
6161
record EarlyAccessJdkBuild(JavaLanguageVersion languageVersion, String buildNumber) implements JdkBuild {
6262
@Override
6363
public String url(String os, String arch, String extension) {
64-
// example:
65-
// https://builds.es-jdk-archive.com/jdks/openjdk/26/openjdk-26-ea+6/openjdk-26-ea+6_linux-aarch64_bin.tar.gz
66-
return "https://builds.es-jdk-archive.com/jdks/openjdk/"
64+
return "https://download.java.net/java/early_access/jdk"
6765
+ languageVersion.asInt()
6866
+ "/"
69-
+ "openjdk-"
70-
+ languageVersion.asInt()
71-
+ "-ea+"
7267
+ buildNumber
73-
+ "/"
74-
+ "openjdk-"
68+
+ "/GPL/openjdk-"
7569
+ languageVersion.asInt()
7670
+ "-ea+"
7771
+ buildNumber
@@ -96,8 +90,7 @@ public String url(String os, String arch, String extension) {
9690

9791
// package private so it can be replaced by tests
9892
List<JdkBuild> builds = List.of(
99-
getBundledJdkBuild(VersionProperties.getBundledJdkVersion(), VersionProperties.getBundledJdkMajorVersion()),
100-
getEarlyAccessBuild(JavaLanguageVersion.of(25), "3")
93+
getBundledJdkBuild(VersionProperties.getBundledJdkVersion(), VersionProperties.getBundledJdkMajorVersion())
10194
);
10295

10396
static EarlyAccessJdkBuild getEarlyAccessBuild(JavaLanguageVersion languageVersion, String buildNumber) {

build-tools-internal/src/test/groovy/org/elasticsearch/gradle/internal/toolchain/AbstractToolchainResolverSpec.groovy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ abstract class AbstractToolchainResolverSpec extends Specification {
7373
_ * languageVersionProperty.get() >> languageVersion
7474

7575
Property<JvmVendorSpec> vendorSpecProperty = Mock()
76+
_ * vendorSpecProperty.isPresent() >> true
7677
_ * vendorSpecProperty.get() >> vendorSpec
7778
_ * toolchainSpec.getVendor() >> vendorSpecProperty
7879

build-tools-internal/src/test/groovy/org/elasticsearch/gradle/internal/toolchain/AdoptiumJdkToolchainResolverSpec.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class AdoptiumJdkToolchainResolverSpec extends AbstractToolchainResolverSpec {
4747
@Override
4848
def supportedRequests() {
4949
return [
50-
[19, ADOPTIUM, MAC_OS, X86_64, "https://api.adoptium.net/v3/binary/version/jdk-19.1.1.1+37.1/mac/x64/jdk/hotspot/normal/eclipse?project=jdk"],
50+
5151
[19, ADOPTIUM, LINUX, X86_64, "https://api.adoptium.net/v3/binary/version/jdk-19.1.1.1+37.1/linux/x64/jdk/hotspot/normal/eclipse?project=jdk"],
5252
[19, ADOPTIUM, WINDOWS, X86_64, "https://api.adoptium.net/v3/binary/version/jdk-19.1.1.1+37.1/windows/x64/jdk/hotspot/normal/eclipse?project=jdk"],
5353
[19, ADOPTIUM, MAC_OS, AARCH64, "https://api.adoptium.net/v3/binary/version/jdk-19.1.1.1+37.1/mac/aarch64/jdk/hotspot/normal/eclipse?project=jdk"],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.gradle.internal.toolchain
11+
12+
import org.gradle.api.services.BuildServiceParameters
13+
import org.gradle.jvm.toolchain.JavaLanguageVersion
14+
import org.gradle.jvm.toolchain.JavaToolchainResolver
15+
import org.gradle.jvm.toolchain.JvmVendorSpec
16+
17+
import static org.gradle.platform.Architecture.AARCH64
18+
import static org.gradle.platform.Architecture.X86_64
19+
import static org.gradle.platform.OperatingSystem.*
20+
21+
class EarlyAccessCatalogJdkToolchainResolverSpec extends AbstractToolchainResolverSpec {
22+
@Override
23+
JavaToolchainResolver resolverImplementation() {
24+
def resolver = new EarlyAccessCatalogJdkToolchainResolver() {
25+
@Override
26+
BuildServiceParameters.None getParameters() {
27+
return null
28+
}
29+
}
30+
resolver.earlyAccessJdkBuildResolver = () -> {
31+
return Optional.of(
32+
new EarlyAccessCatalogJdkToolchainResolver.EarlyAccessJdkBuild(JavaLanguageVersion.of(25), 31),
33+
new EarlyAccessCatalogJdkToolchainResolver.EarlyAccessJdkBuild(JavaLanguageVersion.of(26), 6)
34+
)
35+
}
36+
return resolver
37+
}
38+
39+
def anyVendorMatch() {
40+
return JvmVendorSpec.ANY
41+
}
42+
@Override
43+
def supportedRequests() {
44+
return [
45+
[25, vSpec(
46+
25,
47+
30
48+
), LINUX, X86_64, "https://builds.es-jdk-archive.com/jdks/openjdk/25/openjdk-25-ea+30/openjdk-25-ea+30_linux-x64_bin.tar.gz"],
49+
[26, vSpec(
50+
26,
51+
6
52+
), WINDOWS, X86_64, "https://builds.es-jdk-archive.com/jdks/openjdk/26/openjdk-26-ea+6/openjdk-26-ea+6_windows-x64_bin.zip"],
53+
[26, vSpec(
54+
26,
55+
6
56+
), MAC_OS, AARCH64, "https://builds.es-jdk-archive.com/jdks/openjdk/26/openjdk-26-ea+6/openjdk-26-ea+6_macos-aarch64_bin.tar.gz"]
57+
]
58+
}
59+
60+
private JvmVendorSpec vSpec(int version, int build) {
61+
return org.gradle.jvm.toolchain.internal.DefaultJvmVendorSpec.of("EarlyAccessJvmCatalog[" + version + "/" + build + "]");
62+
}
63+
64+
@Override
65+
def unsupportedRequests() {
66+
return []
67+
}
68+
}

settings.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import org.elasticsearch.gradle.internal.toolchain.OracleOpenJdkToolchainResolver
22
import org.elasticsearch.gradle.internal.toolchain.ArchivedOracleJdkToolchainResolver
33
import org.elasticsearch.gradle.internal.toolchain.AdoptiumJdkToolchainResolver
4+
import org.elasticsearch.gradle.internal.toolchain.EarlyAccessCatalogJdkToolchainResolver
45

56
pluginManagement {
67
repositories {
@@ -42,6 +43,9 @@ toolchainManagement {
4243
repository('archivedOracleJdks') {
4344
resolverClass = ArchivedOracleJdkToolchainResolver
4445
}
46+
repository('EarlyAccessCatalogJdks') {
47+
resolverClass = EarlyAccessCatalogJdkToolchainResolver
48+
}
4549
}
4650
}
4751
}

0 commit comments

Comments
 (0)