Skip to content

Commit

Permalink
enhancement - Find compatible GradleJavaHome and notify client in cas…
Browse files Browse the repository at this point in the history
…e of incompatibility (#165)

Changes:
- Added new method to check compatibility of Java Home with a probe build in GradleApiConnector
- Refactored LifecycleService#setGradleJavaHome to prioritize the default gradle configuration and send a notification to the client if the default behavior is changed.
- Added new test for java home detection with gradle default behavior.
  • Loading branch information
Tanish-Ranjan authored Aug 15, 2024
1 parent cd93aa3 commit 395b977
Show file tree
Hide file tree
Showing 12 changed files with 1,260 additions and 554 deletions.
10 changes: 6 additions & 4 deletions server/src/main/java/com/microsoft/java/bs/core/Launcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public static void main(String[] args) {
launcher.startListening();
}

private static org.eclipse.lsp4j.jsonrpc.Launcher<BuildClient>
private static org.eclipse.lsp4j.jsonrpc.Launcher<BuildClient>
createLauncherUsingPipe(String pipePath) {
NamedPipeStream pipeStream = new NamedPipeStream(pipePath);
try {
Expand All @@ -70,7 +70,7 @@ private static org.eclipse.lsp4j.jsonrpc.Launcher<BuildClient> createLauncherUsi
return createLauncher(System.out, System.in);
}

private static org.eclipse.lsp4j.jsonrpc.Launcher<BuildClient>
private static org.eclipse.lsp4j.jsonrpc.Launcher<BuildClient>
createLauncher(OutputStream outputStream, InputStream inputStream) {
BuildTargetManager buildTargetManager = new BuildTargetManager();
PreferenceManager preferenceManager = new PreferenceManager();
Expand All @@ -80,15 +80,17 @@ private static org.eclipse.lsp4j.jsonrpc.Launcher<BuildClient> createLauncherUsi
connector, preferenceManager);
GradleBuildServer gradleBuildServer = new GradleBuildServer(lifecycleService,
buildTargetService);
org.eclipse.lsp4j.jsonrpc.Launcher<BuildClient> launcher = new
org.eclipse.lsp4j.jsonrpc.Launcher<BuildClient> launcher = new
org.eclipse.lsp4j.jsonrpc.Launcher.Builder<BuildClient>()
.setOutput(outputStream)
.setInput(inputStream)
.setLocalService(gradleBuildServer)
.setRemoteInterface(BuildClient.class)
.setExecutorService(Executors.newCachedThreadPool())
.create();
buildTargetService.setClient(launcher.getRemoteProxy());
BuildClient client = launcher.getRemoteProxy();
lifecycleService.setClient(client);
buildTargetService.setClient(client);
return launcher;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.io.IOException;
import java.net.URI;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
Expand All @@ -22,10 +23,12 @@
import org.gradle.tooling.BuildLauncher;
import org.gradle.tooling.GradleConnectionException;
import org.gradle.tooling.GradleConnector;
import org.gradle.tooling.ModelBuilder;
import org.gradle.tooling.ProjectConnection;
import org.gradle.tooling.TestLauncher;
import org.gradle.tooling.events.OperationType;
import org.gradle.tooling.model.build.BuildEnvironment;
import org.gradle.tooling.model.gradle.GradleBuild;
import org.gradle.util.GradleVersion;

import com.microsoft.java.bs.core.internal.managers.PreferenceManager;
Expand All @@ -47,28 +50,103 @@ public class GradleApiConnector {
private final Map<File, GradleConnector> connectors;
private final PreferenceManager preferenceManager;

private static final String UNSUPPORTED_BUILD_ENVIRONMENT_MESSAGE =
"Could not create an instance of Tooling API implementation "
+ "using the specified Gradle distribution";

public GradleApiConnector(PreferenceManager preferenceManager) {
this.preferenceManager = preferenceManager;
connectors = new HashMap<>();
}

/**
* Get the Gradle version of the project.
* Extracts the GradleVersion for the given project.
*
* @param projectUri URI of the project used to fetch the gradle version.
* @return Gradle version of the project or empty string upon failure.
*/
public String getGradleVersion(URI projectUri) {
try (ProjectConnection connection = getGradleConnector(projectUri).connect()) {
return getGradleVersion(connection);
return getBuildEnvironment(connection).getGradle().getGradleVersion();
} catch (BuildException e) {
LOGGER.severe("Failed to get Gradle version: " + e.getMessage());
return "";
}
}

/**
* Extracts the GradleVersion for the given project connection.
*
* @param connection ProjectConnection used to fetch the gradle version.
* @return Gradle version of the project or empty string upon failure.
*/
public String getGradleVersion(ProjectConnection connection) {
try {
return getBuildEnvironment(connection).getGradle().getGradleVersion();
} catch (BuildException e) {
LOGGER.severe("Failed to get Gradle version: " + e.getMessage());
return "";
}
}

private String getGradleVersion(ProjectConnection connection) {
BuildEnvironment model = connection
/**
* Extracts the BuildEnvironment model for the given project.
*
* @param projectUri URI of the project used to fetch the gradle java home.
* @return BuildEnvironment of the project or {@code null} upon failure.
*/
public BuildEnvironment getBuildEnvironment(URI projectUri) {
try (ProjectConnection connection = getGradleConnector(projectUri).connect()) {
return getBuildEnvironment(connection);
} catch (BuildException e) {
LOGGER.severe("Failed to get Build Environment: " + e.getMessage());
return null;
}
}

/**
* Extracts the BuildEnvironment model for the given project.
*
* @param connection ProjectConnection used to fetch the gradle version.
* @return BuildEnvironment of the project.
*/
private BuildEnvironment getBuildEnvironment(ProjectConnection connection) {
return connection
.model(BuildEnvironment.class)
.get();
return model.getGradle().getGradleVersion();
}

/**
* Runs a probe build to check if the build fails due to java home incompatibility.
*
* @param projectUri URI of the project for which the check needs to be performed.
* @return true if the given project has compatible java home, false otherwise.
*/
public boolean checkCompatibilityWithProbeBuild(URI projectUri) {
try (ProjectConnection connection = getGradleConnector(projectUri).connect()) {
ModelBuilder<GradleBuild> modelBuilder = Utils.setLauncherProperties(
connection.model(GradleBuild.class), preferenceManager.getPreferences()
);
modelBuilder.get();
return true;
} catch (BuildException e) {
return hasUnsupportedBuildEnvironmentMessage(e);
}
}

private boolean hasUnsupportedBuildEnvironmentMessage(BuildException e) {
Set<Throwable> seen = new HashSet<>();
Throwable current = e;
while (current != null) {
if (current.getMessage().contains(UNSUPPORTED_BUILD_ENVIRONMENT_MESSAGE)) {
return true;
}
if (!seen.add(current)) {
break;
}
current = current.getCause();
}
return false;
}

/**
Expand Down Expand Up @@ -152,13 +230,15 @@ public StatusCode runTasks(URI projectUri, ProgressReporter reporter, String...
/**
* request Gradle to run tests.
*/
public StatusCode runTests(URI projectUri,
public StatusCode runTests(
URI projectUri,
Map<BuildTargetIdentifier, Map<String, Set<String>>> testClassesMethodsMap,
List<String> jvmOptions,
List<String> args,
Map<String, String> envVars,
BuildClient client, String originId,
CompileProgressReporter compileProgressReporter) {
CompileProgressReporter compileProgressReporter
) {

StatusCode statusCode = StatusCode.OK;
ProgressReporter reporter = new DefaultProgressReporter(client);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,12 +146,13 @@ public static <T extends ConfigurableLauncher<T>> T setLauncherProperties(T laun
}

/**
* Get the highest compatible Java version for the current Gradle version, according
* to https://docs.gradle.org/current/userguide/compatibility.html
* Get the latest compatible Java version for the current Gradle version, according
* to <a href="https://docs.gradle.org/current/userguide/compatibility.html">
* compatibility matrix</a>
*
* <p>If none of the compatible Java versions is found, an empty string will be returned.
* <p>If a compatible Java versions is not found, an empty string will be returned.
*/
public static String getHighestCompatibleJavaVersion(String gradleVersion) {
public static String getLatestCompatibleJavaVersion(String gradleVersion) {
GradleVersion version = GradleVersion.version(gradleVersion);
if (version.compareTo(GradleVersion.version("8.8")) >= 0) {
return "22";
Expand Down Expand Up @@ -188,6 +189,13 @@ public static String getHighestCompatibleJavaVersion(String gradleVersion) {
return "";
}

/**
* Get the oldest compatible Java version for the current Gradle version.
*/
public static String getOldestCompatibleJavaVersion() {
return "1.8";
}

public static File getInitScriptFile() {
return Paths.get(System.getProperty(Launcher.PROP_PLUGIN_DIR), INIT_GRADLE_SCRIPT).toFile();
}
Expand Down
Loading

0 comments on commit 395b977

Please sign in to comment.