Skip to content

Commit

Permalink
Use linked resource instead of filesystem
Browse files Browse the repository at this point in the history
Use linked resources instead of filesystem hack as this one can return
invalid locations through standard API.

This removes the filesystem bundle, the logic is now moved in ProjectManagers
and a workspace listener takes care of using linked resources for metadata.

This also remove the
InvisibleProjectMetadataTest.testMetadataFileLocation() test because
creating a new project in Eclipse workspace now enforces creation of a
.settings/org.eclipse.core.resources.prefs file. Where the metadata for
the invisible project is stored doesn't matter as the internal project
is internal and not visible to user anyway.

Also removes some usage of gson types which can cause conflicts when
multiple versions are loaded.

[WIP] Remove filesystem plugin

Linked resource for .project works more reliably
  • Loading branch information
mickaelistria committed Jul 2, 2023
1 parent 2803413 commit fae8c0e
Show file tree
Hide file tree
Showing 32 changed files with 445 additions and 616 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*******************************************************************************
* Copyright (c) 2023 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
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.jdt.ls.core.internal;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributeView;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.Instant;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.core.internal.events.ILifecycleListener;
import org.eclipse.core.internal.events.LifecycleEvent;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.WorkspaceJob;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.ICoreRunnable;
import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager;

public class FixDotProjectPathResourceListener implements IResourceChangeListener, ILifecycleListener {

private Map<IProject, Instant> createdProjects = new HashMap<>();

@Override
public void resourceChanged(IResourceChangeEvent event) {
if (ProjectsManager.generatesMetadataFilesAtProjectRoot() || event.getDelta() == null) {
return;
}
try {
event.getDelta().accept(delta -> {
if (delta.getResource() instanceof IProject project && //
project.isOpen() && //
createdProjects.containsKey(project)) {
Instant projectCreation = createdProjects.remove(project);
Path dotProjectOnDisk = project.getLocation().append(IProjectDescription.DESCRIPTION_FILE_NAME).toPath();
try {
BasicFileAttributes attributes = Files.getFileAttributeView(dotProjectOnDisk, BasicFileAttributeView.class).readAttributes();
if (attributes.creationTime().toInstant().isAfter(projectCreation)) {
// cannot link to resource in current workspace task, plan it next
WorkspaceJob.createSystem("Use linked .project for " + project, (ICoreRunnable) (monitor -> {
ProjectsManager.linkDotProject(project);
ProjectsManager.linkResources(project);
})).schedule();
}
} catch (IOException ex) {
JavaLanguageServerPlugin.logException(ex);
}
}
return delta.getResource().getType() == IResource.ROOT;
});
} catch (CoreException e) {
JavaLanguageServerPlugin.logException(e);
}
}

@Override
public void handleEvent(LifecycleEvent event) throws CoreException {
if (event.kind == LifecycleEvent.PRE_PROJECT_CREATE) {
if (event.resource instanceof IProject project) {
createdProjects.put(project, Instant.now());
}
} else if (event.kind == LifecycleEvent.PRE_REFRESH) {
unlinkIfLocal(event.resource);
}
}

private void unlinkIfLocal(IResource resource) {
if (resource instanceof IProject project && project.isOpen()) {
try {
Arrays.stream(project.members())
.filter(IFile.class::isInstance)
.map(IFile.class::cast)
.filter(IFile::isLinked)
.filter(file -> file.getProject().getLocation().append(file.getProjectRelativePath()).toFile().isFile())
.forEach(file -> {
try {
file.delete(true, false, null);
file.getProject().refreshLocal(IResource.DEPTH_ONE, null);
} catch (CoreException e) {
JavaLanguageServerPlugin.logException(e);
}
});
} catch (CoreException e) {
JavaLanguageServerPlugin.logException(e);
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@

import org.apache.commons.lang3.StringUtils;
import org.eclipse.core.internal.net.ProxySelector;
import org.eclipse.core.internal.resources.Workspace;
import org.eclipse.core.net.proxy.IProxyData;
import org.eclipse.core.net.proxy.IProxyService;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
Expand Down Expand Up @@ -113,7 +115,7 @@ public class JavaLanguageServerPlugin extends Plugin {
private ProjectsManager projectsManager;
private DigestStore digestStore;
private ContentProviderManager contentProviderManager;

private FixDotProjectPathResourceListener fixDotProjectListener;
private BaseJDTLanguageServer protocol;

private PreferenceManager preferenceManager;
Expand Down Expand Up @@ -155,6 +157,9 @@ public void start(BundleContext bundleContext) throws Exception {
preferenceManager = new StandardPreferenceManager();
projectsManager = new StandardProjectsManager(preferenceManager);
}
fixDotProjectListener = new FixDotProjectPathResourceListener();
ResourcesPlugin.getWorkspace().addResourceChangeListener(fixDotProjectListener, IResourceChangeEvent.POST_CHANGE);
((Workspace)ResourcesPlugin.getWorkspace()).addLifecycleListener(fixDotProjectListener);
digestStore = new DigestStore(getStateLocation().toFile());
try {
ResourcesPlugin.getWorkspace().addSaveParticipant(IConstants.PLUGIN_ID, projectsManager);
Expand Down Expand Up @@ -365,6 +370,7 @@ public void stop(BundleContext bundleContext) throws Exception {
JavaLanguageServerPlugin.pluginInstance = null;
JavaLanguageServerPlugin.context = null;
ResourcesPlugin.getWorkspace().removeSaveParticipant(IConstants.PLUGIN_ID);
ResourcesPlugin.getWorkspace().removeResourceChangeListener(fixDotProjectListener);
projectsManager = null;
contentProviderManager = null;
languageServer = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Dictionary;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
Expand All @@ -48,6 +50,7 @@
import org.eclipse.buildship.core.internal.DefaultGradleBuild;
import org.eclipse.buildship.core.internal.preferences.PersistentModel;
import org.eclipse.buildship.core.internal.util.gradle.GradleVersion;
import org.eclipse.buildship.core.internal.workspace.WorkspaceOperations;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
Expand Down Expand Up @@ -83,6 +86,9 @@
import org.eclipse.lsp4j.MessageType;
import org.gradle.tooling.model.build.BuildEnvironment;
import org.gradle.tooling.model.build.GradleEnvironment;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;

/**
* @author Fred Bricon
Expand Down Expand Up @@ -127,6 +133,17 @@ public class GradleProjectImporter extends AbstractProjectImporter {
.replaceAll("\n", System.lineSeparator());
//@formatter:on


public GradleProjectImporter() {
// replace the project creation in buildship to hook in usage of linked resources
BundleContext context = CorePlugin.getInstance().getBundle().getBundleContext();
ServiceReference<WorkspaceOperations> serviceReference = context.getServiceReference(WorkspaceOperations.class);
Dictionary<String, Object> props = new Hashtable<>(1, 1);
props.put(Constants.SERVICE_RANKING, 2);
context.ungetService(serviceReference);
context.registerService(WorkspaceOperations.class, new WorkspaceOperationsWithLink(), props);
}

/* (non-Javadoc)
* @see org.eclipse.jdt.ls.core.internal.managers.IProjectImporter#applies(org.eclipse.core.runtime.IProgressMonitor)
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import org.eclipse.m2e.core.lifecyclemapping.model.PluginExecutionAction;
import org.eclipse.m2e.core.project.IMavenProjectImportResult;
import org.eclipse.m2e.core.project.IProjectConfigurationManager;
import org.eclipse.m2e.core.project.IProjectCreationListener;
import org.eclipse.m2e.core.project.LocalProjectScanner;
import org.eclipse.m2e.core.project.MavenProjectInfo;
import org.eclipse.m2e.core.project.ProjectImportConfiguration;
Expand Down Expand Up @@ -208,6 +209,14 @@ public void importToWorkspace(IProgressMonitor monitor) throws CoreException, Op
}
if (!toImport.isEmpty()) {
ProjectImportConfiguration importConfig = new ProjectImportConfiguration();
IProjectCreationListener linkFoldersUponProjectCreation = ProjectsManager.generatesMetadataFilesAtProjectRoot() ? null :
p -> {
try {
ProjectsManager.linkResources(p);
} catch (CoreException ex) {
JavaLanguageServerPlugin.logException(ex);
}
};
if (toImport.size() > artifactIds.size()) {
// Ensure project name is unique when same artifactId
importConfig.setProjectNameTemplate(DUPLICATE_ARTIFACT_TEMPLATE);
Expand All @@ -226,7 +235,7 @@ public void importToWorkspace(IProgressMonitor monitor) throws CoreException, Op
while (i++ < MAX_PROJECTS_TO_IMPORT && iter.hasNext()) {
importPartial.add(iter.next());
}
List<IMavenProjectImportResult> result = configurationManager.importProjects(importPartial, importConfig, monitor2.split(MAX_PROJECTS_TO_IMPORT));
List<IMavenProjectImportResult> result = configurationManager.importProjects(importPartial, importConfig, linkFoldersUponProjectCreation, monitor2.split(MAX_PROJECTS_TO_IMPORT));
results.addAll(result);
monitor2.setWorkRemaining(toImport.size() * 2 - it * MAX_PROJECTS_TO_IMPORT);
}
Expand All @@ -238,7 +247,7 @@ public void importToWorkspace(IProgressMonitor monitor) throws CoreException, Op
updateProjects(imported, lastWorkspaceStateSaved, monitor2.split(projects.size()));
monitor2.done();
} else {
configurationManager.importProjects(toImport, importConfig, subMonitor.split(75));
configurationManager.importProjects(toImport, importConfig, linkFoldersUponProjectCreation, subMonitor.split(75));
}
}
subMonitor.setWorkRemaining(20);
Expand Down

0 comments on commit fae8c0e

Please sign in to comment.