Skip to content

Commit

Permalink
Select suitable JDK to launch Gradle. (#2812)
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 28, 2023
1 parent d8e5236 commit 792c343
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 @@ -204,6 +204,8 @@ public void importToWorkspace(IProgressMonitor monitor) throws CoreException {
subMonitor.setTaskName(IMPORTING_GRADLE_PROJECTS);
JavaLanguageServerPlugin.logInfo(IMPORTING_GRADLE_PROJECTS);
subMonitor.worked(1);
// run just once at the first project, assuming that all projects are using the same gradle version.
inferGradleJavaHome(directories.iterator().next(), monitor);
MultiStatus compatibilityStatus = new MultiStatus(IConstants.PLUGIN_ID, -1, "Compatibility issue occurs when importing Gradle projects", null);
MultiStatus gradleUpgradeWrapperStatus = new MultiStatus(IConstants.PLUGIN_ID, -1, "Gradle upgrade wrapper", null);
for (Path directory : directories) {
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 792c343

Please sign in to comment.