Skip to content

Commit

Permalink
Select suitable JDK to launch Gradle.
Browse files Browse the repository at this point in the history
- When the Gradle Java home preference is not set, and
  the default JDK is not compatible with the project
  Gradle, try to find compatible JDK if there is one available.

Signed-off-by: Sheng Chen <sheche@microsoft.com>
  • Loading branch information
jdneo committed Aug 24, 2023
1 parent a01129c commit 4fabed3
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ public void importToWorkspace(IProgressMonitor monitor) throws CoreException {
if (!applies(monitor)) {
return;
}
// run just once at the first project, assuming that all projects are using the same gradle version.
inferGradleJavaHome(directories.iterator().next(), monitor);
int projectSize = directories.size();
SubMonitor subMonitor = SubMonitor.convert(monitor, projectSize + 1);
subMonitor.setTaskName(IMPORTING_GRADLE_PROJECTS);
Expand Down Expand Up @@ -291,6 +293,33 @@ public void importToWorkspace(IProgressMonitor monitor) throws CoreException {
subMonitor.done();
}

private void inferGradleJavaHome(Path projectFolder, IProgressMonitor monitor) {
if (StringUtils.isNotBlank(getPreferences().getGradleJavaHome())) {
return;
}

File javaHome = getJavaHome(getPreferences());
String javaVersion;
if (javaHome == null) {
javaVersion = System.getProperty("java.version");
} else {
StandardVMType type = new StandardVMType();
javaVersion = type.readReleaseVersion(javaHome);
}
if (StringUtils.isBlank(javaVersion)) {
// return if failed to get java version.
return;
}
GradleVersion gradleVersion = GradleUtils.getGradleVersion(projectFolder, monitor);
if (GradleUtils.isIncompatible(gradleVersion, javaVersion)) {
String highestJavaVersion = GradleUtils.getHighestSupportedJava(gradleVersion);
File javaHomeFile = GradleUtils.getJdkToLaunchDaemon(highestJavaVersion);
if (javaHomeFile != null) {
getPreferences().setGradleJavaHome(javaHomeFile.getAbsolutePath());
}
}
}

private IStatus importDir(Path projectFolder, IProgressMonitor monitor) {
if (monitor.isCanceled()) {
return Status.CANCEL_STATUS;
Expand Down Expand Up @@ -438,11 +467,18 @@ protected IStatus startSynchronization(Path projectFolder, IProgressMonitor moni
}

public static BuildConfiguration getBuildConfiguration(Path rootFolder) {
return getBuildConfiguration(rootFolder, false);
}

public static BuildConfiguration getBuildConfiguration(Path rootFolder, boolean noDaemon) {
GradleDistribution distribution = getGradleDistribution(rootFolder);
Preferences preferences = getPreferences();
File javaHome = getJavaHome(preferences);
File gradleUserHome = getGradleUserHomeFile();
List<String> gradleArguments = new ArrayList<>();
if (noDaemon) {
gradleArguments.add("--no-daemon");
}
gradleArguments.addAll(getGradleInitScriptArgs());
gradleArguments.addAll(preferences.getGradleArguments());
List<String> gradleJvmArguments = preferences.getGradleJvmArguments();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.StreamCorruptedException;
import java.lang.Runtime.Version;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
Expand All @@ -28,8 +29,11 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.Set;
import java.util.Map.Entry;
import java.util.stream.Stream;

import org.apache.commons.lang3.StringUtils;
import org.eclipse.buildship.core.BuildConfiguration;
import org.eclipse.buildship.core.GradleBuild;
import org.eclipse.buildship.core.GradleCore;
Expand All @@ -39,14 +43,21 @@
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.launching.StandardVMType;
import org.eclipse.jdt.launching.AbstractVMInstall;
import org.eclipse.jdt.launching.IVMInstall;
import org.eclipse.jdt.launching.IVMInstallType;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
import org.eclipse.jdt.ls.core.internal.ProjectUtils;
import org.eclipse.jdt.ls.core.internal.RuntimeEnvironment;
import org.eclipse.jdt.ls.core.internal.preferences.Preferences;
import org.gradle.tooling.model.build.BuildEnvironment;
import org.gradle.tooling.model.build.GradleEnvironment;

public class GradleUtils {

public static String MAX_SUPPORTED_JAVA = JavaCore.VERSION_17;
// see https://github.com/gradle/gradle/pull/17397
public static String INVALID_TYPE_FIXED_VERSION = "7.2";
// see https://github.com/gradle/gradle/issues/890
Expand All @@ -55,11 +66,6 @@ public class GradleUtils {

private static final String MESSAGE_DIGEST_ALGORITHM = "SHA-256";

/**
* A pattern to parse annotation processing arguments.
*/
private static final Pattern OPTION_PATTERN = Pattern.compile("-A([^ \\t\"']+)");

public static boolean isIncompatible(GradleVersion gradleVersion, String javaVersion) {
if (gradleVersion == null || javaVersion == null || javaVersion.isEmpty()) {
return false;
Expand All @@ -72,7 +78,13 @@ public static String getHighestSupportedJava(GradleVersion gradleVersion) {
GradleVersion baseVersion = gradleVersion.getBaseVersion();
try {
// https://docs.gradle.org/current/userguide/compatibility.html
if (baseVersion.compareTo(GradleVersion.version("7.3")) >= 0) {
if (baseVersion.compareTo(GradleVersion.version("8.3")) >= 0) {
return JavaCore.VERSION_20;
} else if (baseVersion.compareTo(GradleVersion.version("7.6")) >= 0) {
return JavaCore.VERSION_19;
} else if (baseVersion.compareTo(GradleVersion.version("7.5")) >= 0) {
return JavaCore.VERSION_18;
} else if (baseVersion.compareTo(GradleVersion.version("7.3")) >= 0) {
return JavaCore.VERSION_17;
} else if (baseVersion.compareTo(GradleVersion.version("7.0")) >= 0) {
return JavaCore.VERSION_16;
Expand All @@ -91,10 +103,10 @@ public static String getHighestSupportedJava(GradleVersion gradleVersion) {
} else if (baseVersion.compareTo(GradleVersion.version("4.3")) >= 0) {
return JavaCore.VERSION_9;
}
return JavaCore.VERSION_1_8;
} catch (IllegalArgumentException e) {
return MAX_SUPPORTED_JAVA;
// ignore
}
return JavaCore.VERSION_1_8;
}

public static boolean hasGradleInvalidTypeCodeException(IStatus status, Path projectFolder, IProgressMonitor monitor) {
Expand Down Expand Up @@ -123,7 +135,7 @@ public static boolean isGradleInvalidTypeCodeException(Throwable throwable) {

public static GradleVersion getGradleVersion(Path projectFolder, IProgressMonitor monitor) {
try {
BuildConfiguration build = GradleProjectImporter.getBuildConfiguration(projectFolder);
BuildConfiguration build = GradleProjectImporter.getBuildConfiguration(projectFolder, true);
GradleBuild gradleBuild = GradleCore.getWorkspace().createBuild(build);
BuildEnvironment environment = gradleBuild.withConnection(connection -> connection.getModel(BuildEnvironment.class), monitor);
GradleEnvironment gradleEnvironment = environment.getGradle();
Expand Down Expand Up @@ -293,4 +305,75 @@ public static void synchronizeAnnotationProcessingConfiguration(IProgressMonitor
}
}
}

/**
* Find the latest JDK but equal or lower than the {@code highestJavaVersion}.
*/
public static File getJdkToLaunchDaemon(String highestJavaVersion) {
if (StringUtils.isBlank(highestJavaVersion)) {
return null;
}

Map<String, File> jdks = getAllVmInstalls();;
Entry<String, File> selected = null;
for (Entry<String, File> jdk : jdks.entrySet()) {
String javaVersion = jdk.getKey();
if (Version.parse(javaVersion).compareTo(Version.parse(highestJavaVersion)) <= 0
&& (selected == null || Version.parse(selected.getKey()).compareTo(Version.parse(javaVersion)) < 0)) {
selected = jdk;
}
}

return selected == null ? null : selected.getValue();
}

/**
* Get all the available JDK installations in the Eclipse VM registry. If multiple installations
* are found for the same major version, the first found one is return.
*
* The results are returned as map, where key is the major version and value is the file instance of
* the installation.
*/
private static Map<String, File> getAllVmInstalls() {
List<IVMInstall> vmList = Stream.of(JavaRuntime.getVMInstallTypes())
.map(IVMInstallType::getVMInstalls)
.flatMap(Arrays::stream)
.toList();
Map<String, File> vmInstalls = new HashMap<>();
for (IVMInstall vmInstall : vmList) {
if (vmInstall instanceof AbstractVMInstall vm) {
String javaVersion = getMajorJavaVersion(vm.getJavaVersion());
if (StringUtils.isBlank(javaVersion) || vm.getInstallLocation() == null) {
continue;
}

vmInstalls.putIfAbsent(javaVersion, vm.getInstallLocation());
}
}

Preferences preferences = JavaLanguageServerPlugin.getPreferencesManager().getPreferences();
Set<RuntimeEnvironment> runtimes = preferences.getRuntimes();
for (RuntimeEnvironment runtime : runtimes) {
if (StringUtils.isBlank(runtime.getPath())) {
continue;
}
File javaHome = new File(runtime.getPath());
if (vmInstalls.containsValue(javaHome)) {
continue;
}

String javaVersion = new StandardVMType().readReleaseVersion(javaHome);
if (StringUtils.isNotBlank(javaVersion)) {
// the user preference should have higher priority and replace
// the existing one if the major version is the same.
vmInstalls.put(getMajorJavaVersion(javaVersion), javaHome);
}
}

return vmInstalls;
}

public static String getMajorJavaVersion(String version) {
return CompilerOptions.versionFromJdkLevel(CompilerOptions.versionToJdkLevel(version));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
import org.eclipse.jdt.ls.core.internal.preferences.Preferences;
import org.eclipse.jdt.ls.core.internal.preferences.Preferences.FeatureStatus;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
Expand All @@ -79,6 +80,12 @@
public class GradleProjectImporterTest extends AbstractGradleBasedTest{

private static final String GRADLE1_PATTERN = "**/gradle1";
private String gradleJavaHome;

@Before
public void setUp() {
gradleJavaHome = JavaLanguageServerPlugin.getPreferencesManager().getPreferences().getGradleJavaHome();
}

@Test
public void importSimpleGradleProject() throws Exception {
Expand All @@ -94,6 +101,7 @@ public void importSimpleGradleProject() throws Exception {
public void cleanUp() throws Exception {
super.cleanUp();
Job.getJobManager().join(CorePlugin.GRADLE_JOB_FAMILY, new NullProgressMonitor());
JavaLanguageServerPlugin.getPreferencesManager().getPreferences().setGradleJavaHome(gradleJavaHome);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*******************************************************************************
* Copyright (c) 2023 Microsoft Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Microsoft Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.ls.core.internal.managers;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.io.File;

import org.junit.Test;

public class GradleUtilsTest {
@Test
public void testGetJdkToLaunchDaemon() {
assertEquals("17", GradleUtils.getMajorJavaVersion("17.0.8"));
assertEquals("1.8", GradleUtils.getMajorJavaVersion("1.8.0_202"));
}

@Test
public void testGetMajorJavaVersion() {
File javaHome = GradleUtils.getJdkToLaunchDaemon("10");
assertTrue(javaHome.getAbsolutePath().contains("fakejdk" + File.separator + "10"));
}
}

0 comments on commit 4fabed3

Please sign in to comment.