Skip to content

Commit

Permalink
Add new API 'onWillUpdate()' to IBuildSupport (eclipse-jdtls#2836)
Browse files Browse the repository at this point in the history
- A new API 'onWillUpdate()' is added to IBuildSupport, which can be used
  to do some preparation work before updating the project configuration.
  For example: For the Build Server support, send a reload request to Build
  Server, then do the real update task in 'update()'.
- When a bunch of projects need to be updated, extract out the invocation
  of 'registerWatchers()' and 'updateEncoding()'. See:
  ProjectsManager#updateProjects(Collection<IProject>, boolean force).
---------

Signed-off-by: Sheng Chen <[email protected]>
  • Loading branch information
jdneo authored Oct 8, 2023
1 parent 0e7cb89 commit 4a9e489
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,9 @@ public ProjectConfigurationUpdateHandler(ProjectsManager projectManager) {
*/
public void updateConfigurations(List<TextDocumentIdentifier> identifiers) {
Collection<IProject> projects = ProjectUtils.getProjectsFromDocumentIdentifiers(identifiers);

for (IProject project : projects) {
// most likely the handler is invoked intentionally by the user, that's why
// we force the update despite no changes of in build descriptor being made
projectManager.updateProject(project, true);
}
// most likely the handler is invoked intentionally by the user, that's why
// we force the update despite no changes of in build descriptor being made
projectManager.updateProjects(projects, true);
}

public void updateConfiguration(TextDocumentIdentifier param) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ default boolean isBuildLikeFileName(String fileName) {
return false;
}

/**
* Implementors can put preparation work into this method. This method will be invoked before {@code update(...)}.
*/
default void onWillUpdate(Collection<IProject> projects, IProgressMonitor monitor) throws CoreException {
// do nothing
}

/**
*
* @param resource
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ public interface IProjectsManager {
*/
Job updateProject(IProject project, boolean force);

/**
* Update a set of project configurations.
*/
Job updateProjects(Collection<IProject> projects, boolean force);

/**
* Check whether the resource is a build file.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.TreeMap;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import java.util.stream.Stream;

Expand Down Expand Up @@ -446,6 +448,14 @@ public IStatus runInWorkspace(IProgressMonitor monitor) {
return job;
}

@Override
public Job updateProjects(Collection<IProject> projects, boolean force) {
JavaLanguageServerPlugin.sendStatus(ServiceStatus.Message, "Updating project configurations...");
UpdateProjectsWorkspaceJob job = new UpdateProjectsWorkspaceJob(projects, force);
job.schedule();
return job;
}

@Override
public Optional<IBuildSupport> getBuildSupport(IProject project) {
return buildSupports().filter(bs -> bs.applies(project)).findFirst();
Expand All @@ -467,7 +477,7 @@ public boolean useDefaultVM(IProject project, IVMInstall defaultVM) {
return false;
}

private Stream<IBuildSupport> buildSupports() {
protected Stream<IBuildSupport> buildSupports() {
return Stream.of(new EclipseBuildSupport());
}

Expand Down Expand Up @@ -632,4 +642,96 @@ public void reportProjectsStatus() {
}
}

class UpdateProjectsWorkspaceJob extends WorkspaceJob {

private final Collection<IProject> projects;
private final boolean force;

public UpdateProjectsWorkspaceJob(Collection<IProject> projects, boolean force) {
super("Updating project configurations");
this.projects = projects;
this.force = force;
}

@Override
public boolean belongsTo(Object family) {
return IConstants.UPDATE_PROJECT_FAMILY.equals(family) || IConstants.JOBS_FAMILY.equals(family);
}

@Override
public IStatus runInWorkspace(IProgressMonitor monitor) {
long start = System.currentTimeMillis();
MultiStatus status = new MultiStatus(IConstants.PLUGIN_ID, 0, "Update project configurations");
for (Entry<IBuildSupport, List<IProject>> entry : groupByBuildSupport(projects).entrySet()) {
IStatus onWillUpdateStatus = onWillConfigurationUpdate(entry.getKey(),
entry.getValue(), monitor);

// if onWillUpdate() failed, skip updating the projects.
if (!onWillUpdateStatus.isOK()) {
status.add(onWillUpdateStatus);
continue;
}

for (IProject project : entry.getValue()) {
if (monitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
updateProject(entry.getKey(), project, force, status, monitor);
}
}

onDidConfigurationUpdated(status, monitor);
long elapsed = System.currentTimeMillis() - start;
JavaLanguageServerPlugin.logInfo("Projects updated in " + elapsed + " ms");
return status;
}

private Map<IBuildSupport, List<IProject>> groupByBuildSupport(Collection<IProject> projects) {
Map<IBuildSupport, List<IProject>> groupByBuildSupport = new HashMap<>();
List<IBuildSupport> buildSupports = buildSupports().toList();
for (IProject project : projects) {
Optional<IBuildSupport> buildSupport = buildSupports.stream()
.filter(bs -> bs.applies(project)).findFirst();
if (buildSupport.isPresent()) {
IBuildSupport bs = buildSupport.get();
groupByBuildSupport.computeIfAbsent(bs, k -> new ArrayList<>()).add(project);
}
}
return groupByBuildSupport;
}

private IStatus onWillConfigurationUpdate(IBuildSupport buildSupport, Collection<IProject> projects,
IProgressMonitor monitor) {
try {
buildSupport.onWillUpdate(projects, monitor);
return Status.OK_STATUS;
} catch (CoreException e) {
JavaLanguageServerPlugin.log(e);
return StatusFactory.newErrorStatus("Failed to prepare update from " + buildSupport.buildToolName(), e);
}
}

private void updateProject(IBuildSupport buildSupport, IProject project, boolean force,
MultiStatus status, IProgressMonitor monitor) {
try {
project.refreshLocal(IResource.DEPTH_INFINITE, monitor);
buildSupport.update(project, force, monitor);
project.deleteMarkers(BUILD_FILE_MARKER_TYPE, false, IResource.DEPTH_ONE);
} catch (CoreException e) {
JavaLanguageServerPlugin.log(e);
status.add(StatusFactory.newErrorStatus("Error updating " + project.getName(), e));
}
}

private void onDidConfigurationUpdated(MultiStatus status, IProgressMonitor monitor) {
try {
registerWatchers(true);
updateEncoding(monitor);
reportProjectsStatus();
} catch (CoreException e) {
JavaLanguageServerPlugin.log(e);
status.add(StatusFactory.newErrorStatus("Error updating encoding", e));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,18 @@ public class ProjectConfigurationUpdateHandlerTest extends AbstractProjectsManag
public void testUpdateConfiguration() throws Exception {
importProjects("maven/multimodule");
ProjectsManager pm = mock(ProjectsManager.class);
when(pm.updateProject(any(IProject.class), anyBoolean())).thenReturn(null);
when(pm.updateProjects(any(), anyBoolean())).thenReturn(null);
ProjectConfigurationUpdateHandler handler = new ProjectConfigurationUpdateHandler(pm);
IProject project = WorkspaceHelper.getProject("multimodule");
handler.updateConfiguration(new TextDocumentIdentifier(project.getLocationURI().toString()));
verify(pm, times(1)).updateProject(any(IProject.class), eq(true));
verify(pm, times(1)).updateProjects(any(), eq(true));
}

@Test
public void testUpdateConfigurations() throws Exception {
importProjects("maven/multimodule");
ProjectsManager pm = mock(ProjectsManager.class);
when(pm.updateProject(any(IProject.class), anyBoolean())).thenReturn(null);
when(pm.updateProjects(any(), anyBoolean())).thenReturn(null);
ProjectConfigurationUpdateHandler handler = new ProjectConfigurationUpdateHandler(pm);
List<TextDocumentIdentifier> list = new ArrayList<>();
IProject project = WorkspaceHelper.getProject("module1");
Expand All @@ -60,6 +60,6 @@ public void testUpdateConfigurations() throws Exception {
ProjectConfigurationsUpdateParam param = new ProjectConfigurationsUpdateParam(list);

handler.updateConfigurations(param.getIdentifiers());
verify(pm, times(2)).updateProject(any(IProject.class), eq(true));
verify(pm, times(1)).updateProjects(any(), eq(true));
}
}

0 comments on commit 4a9e489

Please sign in to comment.