Skip to content

Commit 395b977

Browse files
enhancement - Find compatible GradleJavaHome and notify client in case 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.
1 parent cd93aa3 commit 395b977

File tree

12 files changed

+1260
-554
lines changed

12 files changed

+1260
-554
lines changed

server/src/main/java/com/microsoft/java/bs/core/Launcher.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public static void main(String[] args) {
5656
launcher.startListening();
5757
}
5858

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

73-
private static org.eclipse.lsp4j.jsonrpc.Launcher<BuildClient>
73+
private static org.eclipse.lsp4j.jsonrpc.Launcher<BuildClient>
7474
createLauncher(OutputStream outputStream, InputStream inputStream) {
7575
BuildTargetManager buildTargetManager = new BuildTargetManager();
7676
PreferenceManager preferenceManager = new PreferenceManager();
@@ -80,15 +80,17 @@ private static org.eclipse.lsp4j.jsonrpc.Launcher<BuildClient> createLauncherUsi
8080
connector, preferenceManager);
8181
GradleBuildServer gradleBuildServer = new GradleBuildServer(lifecycleService,
8282
buildTargetService);
83-
org.eclipse.lsp4j.jsonrpc.Launcher<BuildClient> launcher = new
83+
org.eclipse.lsp4j.jsonrpc.Launcher<BuildClient> launcher = new
8484
org.eclipse.lsp4j.jsonrpc.Launcher.Builder<BuildClient>()
8585
.setOutput(outputStream)
8686
.setInput(inputStream)
8787
.setLocalService(gradleBuildServer)
8888
.setRemoteInterface(BuildClient.class)
8989
.setExecutorService(Executors.newCachedThreadPool())
9090
.create();
91-
buildTargetService.setClient(launcher.getRemoteProxy());
91+
BuildClient client = launcher.getRemoteProxy();
92+
lifecycleService.setClient(client);
93+
buildTargetService.setClient(client);
9294
return launcher;
9395
}
9496

server/src/main/java/com/microsoft/java/bs/core/internal/gradle/GradleApiConnector.java

Lines changed: 87 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import java.io.IOException;
1111
import java.net.URI;
1212
import java.util.HashMap;
13+
import java.util.HashSet;
1314
import java.util.List;
1415
import java.util.Map;
1516
import java.util.Set;
@@ -22,10 +23,12 @@
2223
import org.gradle.tooling.BuildLauncher;
2324
import org.gradle.tooling.GradleConnectionException;
2425
import org.gradle.tooling.GradleConnector;
26+
import org.gradle.tooling.ModelBuilder;
2527
import org.gradle.tooling.ProjectConnection;
2628
import org.gradle.tooling.TestLauncher;
2729
import org.gradle.tooling.events.OperationType;
2830
import org.gradle.tooling.model.build.BuildEnvironment;
31+
import org.gradle.tooling.model.gradle.GradleBuild;
2932
import org.gradle.util.GradleVersion;
3033

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

53+
private static final String UNSUPPORTED_BUILD_ENVIRONMENT_MESSAGE =
54+
"Could not create an instance of Tooling API implementation "
55+
+ "using the specified Gradle distribution";
56+
5057
public GradleApiConnector(PreferenceManager preferenceManager) {
5158
this.preferenceManager = preferenceManager;
5259
connectors = new HashMap<>();
5360
}
5461

5562
/**
56-
* Get the Gradle version of the project.
63+
* Extracts the GradleVersion for the given project.
64+
*
65+
* @param projectUri URI of the project used to fetch the gradle version.
66+
* @return Gradle version of the project or empty string upon failure.
5767
*/
5868
public String getGradleVersion(URI projectUri) {
5969
try (ProjectConnection connection = getGradleConnector(projectUri).connect()) {
60-
return getGradleVersion(connection);
70+
return getBuildEnvironment(connection).getGradle().getGradleVersion();
71+
} catch (BuildException e) {
72+
LOGGER.severe("Failed to get Gradle version: " + e.getMessage());
73+
return "";
74+
}
75+
}
76+
77+
/**
78+
* Extracts the GradleVersion for the given project connection.
79+
*
80+
* @param connection ProjectConnection used to fetch the gradle version.
81+
* @return Gradle version of the project or empty string upon failure.
82+
*/
83+
public String getGradleVersion(ProjectConnection connection) {
84+
try {
85+
return getBuildEnvironment(connection).getGradle().getGradleVersion();
6186
} catch (BuildException e) {
6287
LOGGER.severe("Failed to get Gradle version: " + e.getMessage());
6388
return "";
6489
}
6590
}
6691

67-
private String getGradleVersion(ProjectConnection connection) {
68-
BuildEnvironment model = connection
92+
/**
93+
* Extracts the BuildEnvironment model for the given project.
94+
*
95+
* @param projectUri URI of the project used to fetch the gradle java home.
96+
* @return BuildEnvironment of the project or {@code null} upon failure.
97+
*/
98+
public BuildEnvironment getBuildEnvironment(URI projectUri) {
99+
try (ProjectConnection connection = getGradleConnector(projectUri).connect()) {
100+
return getBuildEnvironment(connection);
101+
} catch (BuildException e) {
102+
LOGGER.severe("Failed to get Build Environment: " + e.getMessage());
103+
return null;
104+
}
105+
}
106+
107+
/**
108+
* Extracts the BuildEnvironment model for the given project.
109+
*
110+
* @param connection ProjectConnection used to fetch the gradle version.
111+
* @return BuildEnvironment of the project.
112+
*/
113+
private BuildEnvironment getBuildEnvironment(ProjectConnection connection) {
114+
return connection
69115
.model(BuildEnvironment.class)
70116
.get();
71-
return model.getGradle().getGradleVersion();
117+
}
118+
119+
/**
120+
* Runs a probe build to check if the build fails due to java home incompatibility.
121+
*
122+
* @param projectUri URI of the project for which the check needs to be performed.
123+
* @return true if the given project has compatible java home, false otherwise.
124+
*/
125+
public boolean checkCompatibilityWithProbeBuild(URI projectUri) {
126+
try (ProjectConnection connection = getGradleConnector(projectUri).connect()) {
127+
ModelBuilder<GradleBuild> modelBuilder = Utils.setLauncherProperties(
128+
connection.model(GradleBuild.class), preferenceManager.getPreferences()
129+
);
130+
modelBuilder.get();
131+
return true;
132+
} catch (BuildException e) {
133+
return hasUnsupportedBuildEnvironmentMessage(e);
134+
}
135+
}
136+
137+
private boolean hasUnsupportedBuildEnvironmentMessage(BuildException e) {
138+
Set<Throwable> seen = new HashSet<>();
139+
Throwable current = e;
140+
while (current != null) {
141+
if (current.getMessage().contains(UNSUPPORTED_BUILD_ENVIRONMENT_MESSAGE)) {
142+
return true;
143+
}
144+
if (!seen.add(current)) {
145+
break;
146+
}
147+
current = current.getCause();
148+
}
149+
return false;
72150
}
73151

74152
/**
@@ -152,13 +230,15 @@ public StatusCode runTasks(URI projectUri, ProgressReporter reporter, String...
152230
/**
153231
* request Gradle to run tests.
154232
*/
155-
public StatusCode runTests(URI projectUri,
233+
public StatusCode runTests(
234+
URI projectUri,
156235
Map<BuildTargetIdentifier, Map<String, Set<String>>> testClassesMethodsMap,
157236
List<String> jvmOptions,
158237
List<String> args,
159238
Map<String, String> envVars,
160239
BuildClient client, String originId,
161-
CompileProgressReporter compileProgressReporter) {
240+
CompileProgressReporter compileProgressReporter
241+
) {
162242

163243
StatusCode statusCode = StatusCode.OK;
164244
ProgressReporter reporter = new DefaultProgressReporter(client);

server/src/main/java/com/microsoft/java/bs/core/internal/gradle/Utils.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,12 +146,13 @@ public static <T extends ConfigurableLauncher<T>> T setLauncherProperties(T laun
146146
}
147147

148148
/**
149-
* Get the highest compatible Java version for the current Gradle version, according
150-
* to https://docs.gradle.org/current/userguide/compatibility.html
149+
* Get the latest compatible Java version for the current Gradle version, according
150+
* to <a href="https://docs.gradle.org/current/userguide/compatibility.html">
151+
* compatibility matrix</a>
151152
*
152-
* <p>If none of the compatible Java versions is found, an empty string will be returned.
153+
* <p>If a compatible Java versions is not found, an empty string will be returned.
153154
*/
154-
public static String getHighestCompatibleJavaVersion(String gradleVersion) {
155+
public static String getLatestCompatibleJavaVersion(String gradleVersion) {
155156
GradleVersion version = GradleVersion.version(gradleVersion);
156157
if (version.compareTo(GradleVersion.version("8.8")) >= 0) {
157158
return "22";
@@ -188,6 +189,13 @@ public static String getHighestCompatibleJavaVersion(String gradleVersion) {
188189
return "";
189190
}
190191

192+
/**
193+
* Get the oldest compatible Java version for the current Gradle version.
194+
*/
195+
public static String getOldestCompatibleJavaVersion() {
196+
return "1.8";
197+
}
198+
191199
public static File getInitScriptFile() {
192200
return Paths.get(System.getProperty(Launcher.PROP_PLUGIN_DIR), INIT_GRADLE_SCRIPT).toFile();
193201
}

0 commit comments

Comments
 (0)