diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BuildCommandProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BuildCommandProvider.java index a5223ec267..01f4ff1a8f 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BuildCommandProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BuildCommandProvider.java @@ -10,13 +10,26 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java; +import java.util.LinkedHashMap; +import java.util.Map; + import org.eclipse.lsp4j.Command; import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.protocol.java.Jre; public interface BuildCommandProvider { Command executeMavenGoal(IJavaProject project, String goal); Command executeGradleBuild(IJavaProject project, String command); - + + static Map buildEnv(IJavaProject project) { + Map env = new LinkedHashMap<>(); + Jre jre = project.getClasspath().getJre(); + if (jre != null && jre.installationPath() != null) { + env.put("JAVA_HOME", jre.installationPath()); + } + return env; + } + } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/DefaultBuildCommandProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/DefaultBuildCommandProvider.java index effecc2f68..e81b68c2b0 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/DefaultBuildCommandProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/DefaultBuildCommandProvider.java @@ -14,7 +14,11 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; @@ -22,7 +26,7 @@ import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.util.OS; import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; - +import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; public class DefaultBuildCommandProvider implements BuildCommandProvider { @@ -38,9 +42,10 @@ public DefaultBuildCommandProvider(SimpleLanguageServer server) { server.onCommand(CMD_EXEC_MAVEN_GOAL, params -> { String pomPath = extractString(params.getArguments().get(0)); String goal = extractString(params.getArguments().get(1)); + Map env = params.getArguments().size() > 2 ? extractEnv(params.getArguments().get(2)) : null; return CompletableFuture.runAsync(() -> { try { - executeMaven(Paths.get(pomPath), goal.trim().split("\\s+")).get(); + executeMaven(Paths.get(pomPath), goal.trim().split("\\s+"), env).get(); } catch (Exception e) { throw new CompletionException(e); } @@ -51,9 +56,10 @@ public DefaultBuildCommandProvider(SimpleLanguageServer server) { server.onCommand(CMD_EXEC_GRADLE_BUILD, params -> { String gradleBuildPath = extractString(params.getArguments().get(0)); String command = extractString(params.getArguments().get(1)); + Map env = params.getArguments().size() > 2 ? extractEnv(params.getArguments().get(2)) : null; return CompletableFuture.runAsync(() -> { try { - executeGradle(Paths.get(gradleBuildPath), command.trim().split("\\s+")).get(); + executeGradle(Paths.get(gradleBuildPath), command.trim().split("\\s+"), env).get(); } catch (Exception e) { throw new CompletionException(e); } @@ -66,7 +72,13 @@ public Command executeMavenGoal(IJavaProject project, String goal) { Command cmd = new Command(); cmd.setCommand(CMD_EXEC_MAVEN_GOAL); cmd.setTitle("Execute Maven Goal"); - cmd.setArguments(List.of(Paths.get(project.getProjectBuild().getBuildFile()).toFile().toString(), goal)); + List args = new ArrayList<>(List.of( + Paths.get(project.getProjectBuild().getBuildFile()).toFile().toString(), goal)); + Map env = BuildCommandProvider.buildEnv(project); + if (!env.isEmpty()) { + args.add(env); + } + cmd.setArguments(args); return cmd; } @@ -75,7 +87,13 @@ public Command executeGradleBuild(IJavaProject project, String command) { Command cmd = new Command(); cmd.setCommand(CMD_EXEC_GRADLE_BUILD); cmd.setTitle("Execute Gradle Build"); - cmd.setArguments(List.of(Paths.get(project.getProjectBuild().getBuildFile()).toFile().toString(), command)); + List args = new ArrayList<>(List.of( + Paths.get(project.getProjectBuild().getBuildFile()).toFile().toString(), command)); + Map env = BuildCommandProvider.buildEnv(project); + if (env != null && !env.isEmpty()) { + args.add(env); + } + cmd.setArguments(args); return cmd; } @@ -83,17 +101,30 @@ private static String extractString(Object o) { return o instanceof JsonPrimitive ? ((JsonPrimitive) o).getAsString() : o.toString(); } - private CompletableFuture executeMaven(Path pom, String[] goal) { + private static Map extractEnv(Object o) { + Map env = new LinkedHashMap<>(); + if (o instanceof JsonObject jo) { + jo.entrySet().forEach(e -> env.put(e.getKey(), e.getValue().getAsString())); + } + return env; + } + + private CompletableFuture executeMaven(Path pom, String[] goal, Map env) { synchronized(MAVEN_LOCK) { - String[] cmd = new String[1 + goal.length]; Path projectPath = pom.getParent(); Path mvnw = projectPath.resolve(OS.isWindows() ? "mvnw.cmd" : "mvnw"); - cmd[0] = Files.isRegularFile(mvnw) ? mvnw.toFile().toString() : "mvn"; - System.arraycopy(goal, 0, cmd, 1, goal.length); + List cmdList = new ArrayList<>(); + cmdList.add(Files.isRegularFile(mvnw) ? mvnw.toFile().toString() : "mvn"); + cmdList.addAll(Arrays.asList(goal)); try { - return Runtime.getRuntime().exec(cmd, null, projectPath.toFile()).onExit().thenAccept(process -> { + ProcessBuilder pb = new ProcessBuilder(cmdList); + pb.directory(projectPath.toFile()); + if (env != null && !env.isEmpty()) { + pb.environment().putAll(env); + } + return pb.start().onExit().thenAccept(process -> { if (process.exitValue() != 0) { - throw new CompletionException("Failed to execute Maven goal", new IllegalStateException("Errors running maven command: %s".formatted(String.join(" ", cmd)))); + throw new CompletionException("Failed to execute Maven goal", new IllegalStateException("Errors running maven command: %s".formatted(String.join(" ", cmdList)))); } }); } catch (IOException e) { @@ -102,16 +133,21 @@ private CompletableFuture executeMaven(Path pom, String[] goal) { } } - private CompletableFuture executeGradle(Path gradleBuildPath, String[] command) { - String[] cmd = new String[1 + command.length]; + private CompletableFuture executeGradle(Path gradleBuildPath, String[] command, Map env) { Path projectPath = gradleBuildPath.getParent(); - Path mvnw = projectPath.resolve(OS.isWindows() ? "gradlew.cmd" : "gradlew"); - cmd[0] = Files.isRegularFile(mvnw) ? mvnw.toFile().toString() : "gradle"; - System.arraycopy(command, 0, cmd, 1, command.length); + Path gradlew = projectPath.resolve(OS.isWindows() ? "gradlew.cmd" : "gradlew"); + List cmdList = new ArrayList<>(); + cmdList.add(Files.isRegularFile(gradlew) ? gradlew.toFile().toString() : "gradle"); + cmdList.addAll(Arrays.asList(command)); try { - return Runtime.getRuntime().exec(cmd, null, projectPath.toFile()).onExit().thenAccept(process -> { + ProcessBuilder pb = new ProcessBuilder(cmdList); + pb.directory(projectPath.toFile()); + if (env != null && !env.isEmpty()) { + pb.environment().putAll(env); + } + return pb.start().onExit().thenAccept(process -> { if (process.exitValue() != 0) { - throw new CompletionException("Failed to execute Gradle build", new IllegalStateException("Errors running gradle command: %s".formatted(String.join(" ", cmd)))); + throw new CompletionException("Failed to execute Gradle build", new IllegalStateException("Errors running gradle command: %s".formatted(String.join(" ", cmdList)))); } }); } catch (IOException e) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/VSCodeBuildCommandProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/VSCodeBuildCommandProvider.java index e3096de82d..1b89c54454 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/VSCodeBuildCommandProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/VSCodeBuildCommandProvider.java @@ -11,7 +11,9 @@ package org.springframework.ide.vscode.boot.java; import java.nio.file.Paths; +import java.util.ArrayList; import java.util.List; +import java.util.Map; import org.eclipse.lsp4j.Command; import org.springframework.ide.vscode.commons.java.IJavaProject; @@ -23,7 +25,13 @@ public Command executeMavenGoal(IJavaProject project, String goal) { Command cmd = new Command(); cmd.setCommand("maven.goal.custom"); cmd.setTitle("Execute Maven Goal"); - cmd.setArguments(List.of(Paths.get(project.getProjectBuild().getBuildFile()).toFile().toString(), goal)); + List args = new ArrayList<>(List.of( + Paths.get(project.getProjectBuild().getBuildFile()).toFile().toString(), goal)); + Map env = BuildCommandProvider.buildEnv(project); + if (env != null && !env.isEmpty()) { + args.add(env); + } + cmd.setArguments(args); return cmd; } @@ -32,7 +40,13 @@ public Command executeGradleBuild(IJavaProject project, String command) { Command cmd = new Command(); cmd.setCommand("gradle.runBuild"); cmd.setTitle("Execute Gradle Build"); - cmd.setArguments(List.of(Paths.get(project.getProjectBuild().getBuildFile()).toFile().toString(), command)); + List args = new ArrayList<>(List.of( + Paths.get(project.getProjectBuild().getBuildFile()).toFile().toString(), command)); + Map env = BuildCommandProvider.buildEnv(project); + if (env != null && !env.isEmpty()) { + args.add(env); + } + cmd.setArguments(args); return cmd; }