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

Enhanced IBuildSupport usage to support other build tools such as bazel #1694

Merged
merged 4 commits into from
Apr 14, 2021
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,54 @@
/*******************************************************************************
* Copyright (c) 2021 Red Hat Inc. 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
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.ls.core.internal;

import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;

import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Platform;

/**
* The class simplifies extracting extensions from the extension points.
*
* @author D.Bushenko
*
*/
public class ExtensionsExtractor {
public static <T> List<T> extractOrderedExtensions(final String namespace, final String extensionPointName) {

final var extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(namespace, extensionPointName);
final var configs = extensionPoint.getConfigurationElements();

Map<Integer, T> extensionMap = new TreeMap<>();

for (int i = 0; i < configs.length; i++) {
Integer order = Integer.valueOf(configs[i].getAttribute("order"));
extensionMap.put(order, makeExtension(configs[i]));
}
return extensionMap.values().stream().collect(Collectors.toUnmodifiableList());
}

@SuppressWarnings("unchecked")
private static <T> T makeExtension(IConfigurationElement config) {
try {
return (T) config.createExecutableExtension("class");

} catch (Exception ex) {
throw new IllegalArgumentException("Could not create the extension", ex);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
Expand All @@ -48,6 +49,9 @@
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.ls.core.internal.managers.BuildSupportManager;
import org.eclipse.jdt.ls.core.internal.managers.IBuildSupport;
import org.eclipse.jdt.ls.core.internal.managers.InternalBuildSupports;
import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager;
import org.eclipse.jdt.ls.core.internal.preferences.PreferenceManager;
import org.eclipse.m2e.core.internal.IMavenConstants;
Expand Down Expand Up @@ -91,7 +95,12 @@ public static boolean isGradleProject(IProject project) {
}

public static boolean isGeneralJavaProject(IProject project) {
return isJavaProject(project) && !isMavenProject(project) && !isGradleProject(project);
return isJavaProject(project) && isInternalBuildSupport(BuildSupportManager.find(project).orElse(null));
}

public static boolean isInternalBuildSupport(IBuildSupport buildSupport) {
return buildSupport != null && Arrays.stream(InternalBuildSupports.values())
.anyMatch(bsn -> Objects.equals(buildSupport.buildToolName(), bsn.toString()));
}

public static String getJavaSourceLevel(IProject project) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,24 @@
import org.eclipse.jdt.ls.core.internal.Messages;
import org.eclipse.jdt.ls.core.internal.ProjectUtils;
import org.eclipse.jdt.ls.core.internal.ResourceUtils;
import org.eclipse.jdt.ls.core.internal.managers.BuildSupportManager;
import org.eclipse.jdt.ls.core.internal.managers.IBuildSupport;
import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager;
import org.eclipse.jdt.ls.core.internal.preferences.PreferenceManager;

public class BuildPathCommand {
public static final String UNSUPPORTED_ON_MAVEN = "Unsupported operation. Please use pom.xml file to manage the source directories of maven project.";
public static final String UNSUPPORTED_ON_GRADLE = "Unsupported operation. Please use build.gradle file to manage the source directories of gradle project.";
private static final String UNSUPPORTED_OPERATION = "Unsupported operation. Please use your build tool project file to manage the source directories of the project.";

private static String unsupportedOperationMessage(IProject targetProject) {
return BuildSupportManager.obtainBuildSupports().stream().filter(bs -> bs.applies(targetProject)).findFirst().map(IBuildSupport::unsupportedOperationMessage).orElse(UNSUPPORTED_OPERATION);
}

public static Result addToSourcePath(String sourceFolderUri) {
IPath sourceFolderPath = ResourceUtils.filePathFromURI(sourceFolderUri);
IProject targetProject = findBelongedProject(sourceFolderPath);

if (targetProject != null && !ProjectUtils.isGeneralJavaProject(targetProject)) {
String message = ProjectUtils.isGradleProject(targetProject) ? UNSUPPORTED_ON_GRADLE : UNSUPPORTED_ON_MAVEN;
return new Result(false, message);
return new Result(false, unsupportedOperationMessage(targetProject));
}

IPath projectLocation = null;
Expand Down Expand Up @@ -99,8 +104,7 @@ public static Result removeFromSourcePath(String sourceFolderUri) {
IPath sourceFolderPath = ResourceUtils.filePathFromURI(sourceFolderUri);
IProject targetProject = findBelongedProject(sourceFolderPath);
if (targetProject != null && !ProjectUtils.isGeneralJavaProject(targetProject)) {
String message = ProjectUtils.isGradleProject(targetProject) ? UNSUPPORTED_ON_GRADLE : UNSUPPORTED_ON_MAVEN;
return new Result(false, message);
return new Result(false, unsupportedOperationMessage(targetProject));
}

IPath projectLocation = null;
Expand Down Expand Up @@ -141,52 +145,58 @@ public static Result removeFromSourcePath(String sourceFolderUri) {
}

public static Result listSourcePaths() {
try {
List<SourcePath> sourcePathList = new ArrayList<>();
IProject[] projects = ProjectUtils.getAllProjects();
for (IProject project : projects) {
if (!ProjectsManager.DEFAULT_PROJECT_NAME.equals(project.getName()) && ProjectUtils.isJavaProject(project)) {
sourcePathList.addAll(tryAddProjectToSourcePath(project));
}
}

return new ListCommandResult(true, null, sourcePathList.toArray(new SourcePath[0]));

} catch (JavaModelException e) {
JavaLanguageServerPlugin.logException("Failed to resolve the existing source paths in current workspace.", e);
return new ListCommandResult(false, e.getMessage());
}
}

private static List<SourcePath> tryAddProjectToSourcePath(IProject project) throws JavaModelException {
List<SourcePath> sourcePathList = new ArrayList<>();
IProject[] projects = ProjectUtils.getAllProjects();
for (IProject project : projects) {
if (!ProjectsManager.DEFAULT_PROJECT_NAME.equals(project.getName()) && ProjectUtils.isJavaProject(project)) {
try {
IPath[] paths = ProjectUtils.listSourcePaths(JavaCore.create(project));
for (IPath path : paths) {
IPath entryPath = path;
String projectName = project.getName();
String projectType = "General";
if (ProjectUtils.isMavenProject(project)) {
projectType = "Maven";
}

if (ProjectUtils.isGradleProject(project)) {
projectType = "Gradle";
}

IContainer projectRoot = project;
if (!ProjectUtils.isVisibleProject(project)) {
projectType = "Workspace";
IFolder workspaceLinkFolder = project.getFolder(ProjectUtils.WORKSPACE_LINK);
if (!workspaceLinkFolder.isLinked()) {
continue;
}

projectRoot = workspaceLinkFolder;
}

IPath relativePath = entryPath.makeRelativeTo(projectRoot.getFullPath());
IPath location = projectRoot.getRawLocation().append(relativePath);
IPath displayPath = getWorkspacePath(location);
sourcePathList.add(new SourcePath(location != null ? location.toOSString() : "",
displayPath != null ? displayPath.toOSString() : entryPath.toOSString(),
entryPath.toOSString(),
projectName,
projectType));
}
} catch (JavaModelException e) {
JavaLanguageServerPlugin.logException("Failed to resolve the existing source paths in current workspace.", e);
return new ListCommandResult(false, e.getMessage());
IPath[] paths = ProjectUtils.listSourcePaths(JavaCore.create(project));

for (IPath path : paths) {
IPath entryPath = path;
String projectName = project.getName();
String projectType = determineProjectType(project);

IContainer projectRoot = project;
if (!ProjectUtils.isVisibleProject(project)) {
projectType = "Workspace";
IFolder workspaceLinkFolder = project.getFolder(ProjectUtils.WORKSPACE_LINK);
if (!workspaceLinkFolder.isLinked()) {
continue;
}

projectRoot = workspaceLinkFolder;
}

IPath relativePath = entryPath.makeRelativeTo(projectRoot.getFullPath());
IPath location = projectRoot.getRawLocation().append(relativePath);
IPath displayPath = getWorkspacePath(location);
sourcePathList.add(new SourcePath(location != null ? location.toOSString() : "",
displayPath != null ? displayPath.toOSString() : entryPath.toOSString(),
entryPath.toOSString(),
projectName,
projectType));
}

return new ListCommandResult(true, null, sourcePathList.toArray(new SourcePath[0]));
return sourcePathList;
}

private static String determineProjectType(IProject project) {
return BuildSupportManager.find(project).map(buildSupport -> buildSupport.buildToolName()).orElseGet(() -> "General");
}

private static String[] getInvisibleProjectRelativeSourcePaths(IJavaProject javaProject) throws JavaModelException {
Expand All @@ -199,10 +209,9 @@ private static String[] getInvisibleProjectRelativeSourcePaths(IJavaProject java
}
IPath[] paths = ProjectUtils.listSourcePaths(javaProject);
return Arrays.stream(paths)
.map(p -> p.makeRelativeTo(workspaceLinkFolder.getFullPath()).toString())
.toArray(String[]::new);
.map(p -> p.makeRelativeTo(workspaceLinkFolder.getFullPath()).toString())
.toArray(String[]::new);
}

private static IProject findBelongedProject(IPath sourceFolder) {
List<IProject> projects = Stream.of(ProjectUtils.getAllProjects()).filter(ProjectUtils::isJavaProject).sorted(new Comparator<IProject>() {
@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*******************************************************************************
* Copyright (c) 2021 Red Hat Inc. 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
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.ls.core.internal.managers;

import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;

import org.eclipse.core.resources.IProject;
import org.eclipse.jdt.ls.core.internal.ExtensionsExtractor;
import org.eclipse.jdt.ls.core.internal.IConstants;

/**
* This is an orchestrator who is responsible for fetching and searching
* IBuildSupport objects.
*
* @author D.Bushenko
*
*/
public class BuildSupportManager {
private static final BuildSupportManager instance = new BuildSupportManager();
private List<IBuildSupport> lazyLoadedBuildSupportList;

private BuildSupportManager() {}

public static List<IBuildSupport> obtainBuildSupports() {
if (instance.lazyLoadedBuildSupportList == null) {
instance.lazyLoadedBuildSupportList = ExtensionsExtractor.extractOrderedExtensions(IConstants.PLUGIN_ID, "buildSupport");
}

return instance.lazyLoadedBuildSupportList;
}

public static Optional<IBuildSupport> find(IProject project) {
return instance.find(bs -> bs.applies(project));
}

public static Optional<IBuildSupport> find(String buildToolName) {
return instance.find(bs -> bs.buildToolName().equalsIgnoreCase(buildToolName));
}

private Optional<IBuildSupport> find(Predicate<? super IBuildSupport> predicate) {
return obtainBuildSupports().stream().filter(predicate).findFirst();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,9 @@ public boolean applies(IProject project) {
return JavaLanguageServerPlugin.getProjectsManager().getDefaultProject().equals(project);
}

@Override
public String buildToolName() {
return InternalBuildSupports.DEFAULT.toString();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -103,5 +103,9 @@ public void discoverSource(IClassFile classFile, IProgressMonitor monitor) throw
}
}

@Override
public String buildToolName() {
return InternalBuildSupports.ECLIPSE.toString();
}

}
Loading