Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support parsing the compiler arguments #1407

Merged
merged 1 commit into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.microsoft.gradle.bs.importer;

import ch.epfl.scala.bsp4j.BuildServer;
import ch.epfl.scala.bsp4j.JavaBuildServer;

public interface BuildServerConnection extends BuildServer, JavaBuildServer {}
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,20 @@
import org.eclipse.jdt.ls.core.internal.managers.IBuildSupport;
import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager.CHANGE_TYPE;

import com.microsoft.gradle.bs.importer.jpms.JpmsArguments;
import com.microsoft.gradle.bs.importer.jpms.JpmsUtils;
import com.microsoft.gradle.bs.importer.model.GradleVersion;

import ch.epfl.scala.bsp4j.BuildServer;
import ch.epfl.scala.bsp4j.BuildTarget;
import ch.epfl.scala.bsp4j.BuildTargetIdentifier;
import ch.epfl.scala.bsp4j.BuildTargetTag;
import ch.epfl.scala.bsp4j.DependencyModule;
import ch.epfl.scala.bsp4j.DependencyModulesItem;
import ch.epfl.scala.bsp4j.DependencyModulesParams;
import ch.epfl.scala.bsp4j.DependencyModulesResult;
import ch.epfl.scala.bsp4j.JavacOptionsItem;
import ch.epfl.scala.bsp4j.JavacOptionsParams;
import ch.epfl.scala.bsp4j.JavacOptionsResult;
import ch.epfl.scala.bsp4j.OutputPathItem;
import ch.epfl.scala.bsp4j.OutputPathsItem;
import ch.epfl.scala.bsp4j.OutputPathsParams;
Expand Down Expand Up @@ -135,7 +139,7 @@ public void update(IProject project, boolean force, IProgressMonitor monitor) th
JavaLanguageServerPlugin.logError("Cannot find workspace root for project: " + project.getName());
return;
}
BuildServer buildServer = ImporterPlugin.getBuildServerConnection(rootPath);
BuildServerConnection buildServer = ImporterPlugin.getBuildServerConnection(rootPath);
buildServer.workspaceReload().join();

Map<URI, List<BuildTarget>> buildTargetMap = Utils.getBuildTargetsMappedByProjectPath(buildServer);
Expand Down Expand Up @@ -168,7 +172,7 @@ public void updateClasspath(IProject project, IProgressMonitor monitor) throws C
JavaLanguageServerPlugin.logError("Cannot find workspace root for project: " + project.getName());
return;
}
BuildServer buildServer = ImporterPlugin.getBuildServerConnection(rootPath);
BuildServerConnection buildServer = ImporterPlugin.getBuildServerConnection(rootPath);
// use map to dedupe the classpath entries having the same path field.
Map<IPath, IClasspathEntry> classpathMap = new LinkedHashMap<>();
List<BuildTarget> buildTargets = Utils.getBuildTargetsByProjectUri(buildServer, project.getLocationURI());
Expand Down Expand Up @@ -220,6 +224,7 @@ public void updateClasspath(IProject project, IProgressMonitor monitor) throws C
classpathMap = getSourceCpeWithExclusions(new LinkedList<>(classpathMap.values()))
.stream()
.collect(Collectors.toMap(IClasspathEntry::getPath, Function.identity(), (e1, e2) -> e1, LinkedHashMap::new));
// TODO: find a way to get if the project is modular without setting the classpath.
javaProject.setRawClasspath(classpathMap.values().toArray(new IClasspathEntry[0]), monitor);
boolean isModular = javaProject.getOwnModuleDescription() != null;

Expand All @@ -236,6 +241,21 @@ public void updateClasspath(IProject project, IProgressMonitor monitor) throws C
}

javaProject.setRawClasspath(classpathMap.values().toArray(new IClasspathEntry[0]), monitor);

// process jpms arguments.
JavacOptionsResult javacOptions = buildServer.buildTargetJavacOptions(new JavacOptionsParams(
buildTargets.stream().map(BuildTarget::getId).collect(Collectors.toList()))).join();
List<String> compilerArgs = new LinkedList<>();
for (JavacOptionsItem item : javacOptions.getItems()) {
compilerArgs.addAll(item.getOptions());
}

JpmsArguments jpmsArgs = JpmsUtils.categorizeJpmsArguments(compilerArgs);
if (jpmsArgs.isEmpty()) {
return;
}
JpmsUtils.appendJpmsAttributesToEntries(javaProject, classpathMap, jpmsArgs);
javaProject.setRawClasspath(classpathMap.values().toArray(new IClasspathEntry[0]), monitor);
}

/**
Expand All @@ -248,7 +268,7 @@ public void updateProjectDependencies(IProject project, IProgressMonitor monitor
JavaLanguageServerPlugin.logError("Cannot find workspace root for project: " + project.getName());
return;
}
BuildServer buildServer = ImporterPlugin.getBuildServerConnection(rootPath);
BuildServerConnection buildServer = ImporterPlugin.getBuildServerConnection(rootPath);
List<BuildTarget> buildTargets = Utils.getBuildTargetsByProjectUri(buildServer, project.getLocationURI());
Set<BuildTargetIdentifier> projectDependencies = new LinkedHashSet<>();
for (BuildTarget buildTarget : buildTargets) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
import com.microsoft.gradle.bs.importer.model.BuildServerPreferences;

import ch.epfl.scala.bsp4j.BuildClientCapabilities;
import ch.epfl.scala.bsp4j.BuildServer;
import ch.epfl.scala.bsp4j.BuildTarget;
import ch.epfl.scala.bsp4j.InitializeBuildParams;
import ch.epfl.scala.bsp4j.InitializeBuildResult;
Expand Down Expand Up @@ -90,7 +89,7 @@ public boolean applies(IProgressMonitor monitor) throws OperationCanceledExcepti
@Override
public void importToWorkspace(IProgressMonitor monitor) throws OperationCanceledException, CoreException {
IPath rootPath = ResourceUtils.filePathFromURI(rootFolder.toURI().toString());
BuildServer buildServer = ImporterPlugin.getBuildServerConnection(rootPath);
BuildServerConnection buildServer = ImporterPlugin.getBuildServerConnection(rootPath);

InitializeBuildParams params = new InitializeBuildParams(
CLIENT_NAME,
Expand Down Expand Up @@ -169,7 +168,7 @@ public static boolean updateConfigurationDigest(IProject project) {
*
* @throws CoreException
*/
private List<IProject> importProjects(BuildServer buildServer, IProgressMonitor monitor) throws CoreException {
private List<IProject> importProjects(BuildServerConnection buildServer, IProgressMonitor monitor) throws CoreException {
Map<URI, List<BuildTarget>> buildTargetMap = Utils.getBuildTargetsMappedByProjectPath(buildServer);
List<IProject> projects = new LinkedList<>();
for (Entry<URI, List<BuildTarget>> entrySet : buildTargetMap.entrySet()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,12 @@
import com.microsoft.java.builder.BuildStateManager;

import ch.epfl.scala.bsp4j.BuildClient;
import ch.epfl.scala.bsp4j.BuildServer;

public class ImporterPlugin extends Plugin {

public static final String PLUGIN_ID = "com.microsoft.gradle.buildServer.importer";

private Map<IPath, Pair<BuildServer, BuildClient>> buildServers = new ConcurrentHashMap<>();
private Map<IPath, Pair<BuildServerConnection, BuildClient>> buildServers = new ConcurrentHashMap<>();

private static ImporterPlugin instance;

Expand All @@ -53,7 +52,7 @@ public void start(BundleContext context) throws Exception {

@Override
public void stop(BundleContext context) throws Exception {
for (Pair<BuildServer, BuildClient> pair : buildServers.values()) {
for (Pair<BuildServerConnection, BuildClient> pair : buildServers.values()) {
pair.getLeft().buildShutdown();
pair.getLeft().onBuildExit();
}
Expand All @@ -67,8 +66,8 @@ public static DigestStore getDigestStore() {
return instance.digestStore;
}

public static BuildServer getBuildServerConnection(IPath rootPath) throws CoreException {
Pair<BuildServer, BuildClient> pair = instance.buildServers.get(rootPath);
public static BuildServerConnection getBuildServerConnection(IPath rootPath) throws CoreException {
Pair<BuildServerConnection, BuildClient> pair = instance.buildServers.get(rootPath);
if (pair != null) {
return pair.getLeft();
}
Expand All @@ -92,16 +91,16 @@ public static BuildServer getBuildServerConnection(IPath rootPath) throws CoreEx
try {
Process process = build.start();
BuildClient client = new GradleBuildClient();
Launcher<BuildServer> launcher = new Launcher.Builder<BuildServer>()
Launcher<BuildServerConnection> launcher = new Launcher.Builder<BuildServerConnection>()
.setOutput(process.getOutputStream())
.setInput(process.getInputStream())
.setLocalService(client)
.setExecutorService(Executors.newCachedThreadPool())
.setRemoteInterface(BuildServer.class)
.setRemoteInterface(BuildServerConnection.class)
.create();

launcher.startListening();
BuildServer server = launcher.getRemoteProxy();
BuildServerConnection server = launcher.getRemoteProxy();
client.onConnectWithServer(server);
instance.buildServers.put(rootPath, Pair.of(server, client));
return server;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@

import com.microsoft.gradle.bs.importer.builder.BuildServerBuilder;

import ch.epfl.scala.bsp4j.BuildServer;
import ch.epfl.scala.bsp4j.BuildTarget;
import ch.epfl.scala.bsp4j.WorkspaceBuildTargetsResult;

Expand All @@ -37,7 +36,7 @@ public static boolean isGradleBuildServerProject(IProject project) {
/**
* Get build targets mapped by their paths, the paths are get from the uri.
*/
public static Map<URI, List<BuildTarget>> getBuildTargetsMappedByProjectPath(BuildServer serverConnection) {
public static Map<URI, List<BuildTarget>> getBuildTargetsMappedByProjectPath(BuildServerConnection serverConnection) {
WorkspaceBuildTargetsResult workspaceBuildTargetsResult = serverConnection.workspaceBuildTargets().join();
List<BuildTarget> buildTargets = workspaceBuildTargetsResult.getTargets();
return buildTargets.stream().collect(Collectors.groupingBy(target -> getUriWithoutQuery(target.getId().getUri())));
Expand All @@ -52,7 +51,7 @@ public static URI getUriWithoutQuery(String uriString) {
}
}

public static List<BuildTarget> getBuildTargetsByProjectUri(BuildServer serverConnection, URI projectUri) {
public static List<BuildTarget> getBuildTargetsByProjectUri(BuildServerConnection serverConnection, URI projectUri) {
if (projectUri == null) {
throw new IllegalArgumentException("projectPath cannot be null.");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
import org.eclipse.jdt.ls.core.internal.ProjectUtils;

import com.microsoft.gradle.bs.importer.BuildServerConnection;
import com.microsoft.gradle.bs.importer.ImporterPlugin;
import com.microsoft.gradle.bs.importer.Utils;

import ch.epfl.scala.bsp4j.BuildServer;
import ch.epfl.scala.bsp4j.BuildTarget;
import ch.epfl.scala.bsp4j.BuildTargetIdentifier;
import ch.epfl.scala.bsp4j.CompileParams;
Expand All @@ -38,7 +38,7 @@ protected IProject[] build(int kind, Map<String, String> args, IProgressMonitor
JavaLanguageServerPlugin.logError("Cannot find workspace root for project: " + project.getName());
return null;
}
BuildServer buildServer = ImporterPlugin.getBuildServerConnection(rootPath);
BuildServerConnection buildServer = ImporterPlugin.getBuildServerConnection(rootPath);
if (buildServer != null) {
List<BuildTarget> targets = Utils.getBuildTargetsByProjectUri(buildServer, project.getLocationURI());
List<BuildTargetIdentifier> ids = targets.stream().map(BuildTarget::getId).collect(Collectors.toList());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.microsoft.gradle.bs.importer.jpms;

import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.core.IClasspathAttribute;

/**
* The type of JPMS argument that JDT supports.
*/
public enum JpmsArgType {
ADD_EXPORTS("--add-exports", IClasspathAttribute.ADD_EXPORTS,
Pattern.compile("^(([A-Za-z0-9\\.$_]*)/[A-Za-z0-9\\.$_]*=[A-Za-z0-9\\.$_-]*)$")),

ADD_OPENS("--add-opens", IClasspathAttribute.ADD_OPENS,
Pattern.compile("^(([A-Za-z0-9\\.$_]*)/[A-Za-z0-9\\.$_]*=[A-Za-z0-9\\.$_-]*)$")),

ADD_READS("--add-reads", IClasspathAttribute.ADD_READS,
Pattern.compile("^(([A-Za-z0-9\\.$_]*)=[A-Za-z0-9\\.$_-]*)$")),

PATCH_MODULE("--patch-module", IClasspathAttribute.PATCH_MODULE,
Pattern.compile("^(([A-Za-z0-9\\.$_]*)=.*)$"));

private String javacArgumentName;

private String eclipseArgumentName;

private Pattern extractPattern;

JpmsArgType(String javacArgumentName, String eclipseArgumentName,
Pattern extractPattern) {
this.javacArgumentName = javacArgumentName;
this.eclipseArgumentName = eclipseArgumentName;
this.extractPattern = extractPattern;
}

/**
* Get the JPMS argument type from the javac argument.
*/
public static JpmsArgType fromJavacArgumentName(String arg) {
return Arrays.stream(JpmsArgType.values())
.filter(type -> type.javacArgumentName.equals(arg))
.findFirst()
.orElse(null);
}

public String getEclipseArgumentName() {
return eclipseArgumentName;
}

/**
* Parse the JPMS argument value from the javac argument value.
*/
public JpmsArgValue parse(String value) {
if (StringUtils.isBlank(value)) {
return null;
}

String trimmed = value.trim();
Matcher matcher = extractPattern.matcher(trimmed);

if (matcher.matches()) {
String argValue = matcher.group(1);
String module = matcher.group(2);
return new JpmsArgValue(module, argValue);
}

return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.microsoft.gradle.bs.importer.jpms;

import java.util.Objects;

public class JpmsArgValue {
private final String module;

private final String value;

public JpmsArgValue(String module, String value) {
this.module = module;
this.value = value;
}

public String getModule() {
return this.module;
}

public String getValue() {
return this.value;
}

@Override
public int hashCode() {
return Objects.hash(module, value);
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
JpmsArgValue other = (JpmsArgValue) obj;
return Objects.equals(module, other.module) && Objects.equals(value, other.value);
}
}
Loading