diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/DigestStore.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/DigestStore.java index 27f6e09a11..f34ca18a18 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/DigestStore.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/DigestStore.java @@ -23,6 +23,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -63,19 +64,40 @@ public DigestStore(File stateLocation) { * if a digest cannot be computed */ public boolean updateDigest(Path p) throws CoreException { + return updateDigests(Arrays.asList(p)); + } + + /** + * Updates the digests for the given paths. + * + * @param paths + * Paths to the files in question + * @return whether at least one file is considered changed and the associated + * project should be updated + * @throws CoreException + * if a digest cannot be computed + */ + public boolean updateDigests(Collection paths) throws CoreException { try { - String digest = computeDigest(p); + Map digests = new HashMap<>(); + for (Path path : paths) { + digests.put(path.toString(), computeDigest(path)); + } synchronized (fileDigests) { - if (!digest.equals(fileDigests.get(p.toString()))) { - fileDigests.put(p.toString(), digest); + boolean changed = false; + for (Map.Entry entry : digests.entrySet()) { + if (!entry.getValue().equals(fileDigests.get(entry.getKey()))) { + fileDigests.put(entry.getKey(), entry.getValue()); + changed = true; + } + } + if (changed) { serializeFileDigests(); - return true; - } else { - return false; } + return changed; } } catch (NoSuchAlgorithmException | IOException e) { - throw new CoreException(StatusFactory.newErrorStatus("Exception updating digest for " + p, e)); + throw new CoreException(StatusFactory.newErrorStatus("Exception updating digest for " + paths, e)); } } diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/GradleProjectImporter.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/GradleProjectImporter.java index d8f332613c..b38b8549c6 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/GradleProjectImporter.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/GradleProjectImporter.java @@ -246,26 +246,30 @@ public void importToWorkspace(IProgressMonitor monitor) throws CoreException { checkWrapperChecksum(directory); } // store the digest for the imported gradle projects. + List digestPaths = new ArrayList<>(); ProjectUtils.getGradleProjects().forEach(project -> { File buildFile = project.getFile(BUILD_GRADLE_DESCRIPTOR).getLocation().toFile(); File settingsFile = project.getFile(SETTINGS_GRADLE_DESCRIPTOR).getLocation().toFile(); File buildKtsFile = project.getFile(BUILD_GRADLE_KTS_DESCRIPTOR).getLocation().toFile(); File settingsKtsFile = project.getFile(SETTINGS_GRADLE_KTS_DESCRIPTOR).getLocation().toFile(); + if (buildFile.exists()) { + digestPaths.add(buildFile.toPath()); + } else if (buildKtsFile.exists()) { + digestPaths.add(buildKtsFile.toPath()); + } + if (settingsFile.exists()) { + digestPaths.add(settingsFile.toPath()); + } else if (settingsKtsFile.exists()) { + digestPaths.add(settingsKtsFile.toPath()); + } + }); + if (!digestPaths.isEmpty()) { try { - if (buildFile.exists()) { - JavaLanguageServerPlugin.getDigestStore().updateDigest(buildFile.toPath()); - } else if (buildKtsFile.exists()) { - JavaLanguageServerPlugin.getDigestStore().updateDigest(buildKtsFile.toPath()); - } - if (settingsFile.exists()) { - JavaLanguageServerPlugin.getDigestStore().updateDigest(settingsFile.toPath()); - } else if (settingsKtsFile.exists()) { - JavaLanguageServerPlugin.getDigestStore().updateDigest(settingsKtsFile.toPath()); - } + JavaLanguageServerPlugin.getDigestStore().updateDigests(digestPaths); } catch (CoreException e) { JavaLanguageServerPlugin.logException("Failed to update digest for gradle build file", e); } - }); + } for (IProject gradleProject : ProjectUtils.getGradleProjects()) { gradleProject.deleteMarkers(COMPATIBILITY_MARKER_ID, true, IResource.DEPTH_ZERO); gradleProject.deleteMarkers(GRADLE_UPGRADE_WRAPPER_MARKER_ID, true, IResource.DEPTH_INFINITE); diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/MavenProjectImporter.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/MavenProjectImporter.java index ca391e5b73..d6bca2f943 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/MavenProjectImporter.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/MavenProjectImporter.java @@ -171,6 +171,7 @@ public void importToWorkspace(IProgressMonitor monitor) throws CoreException, Op IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); Collection projects = new LinkedHashSet<>(); Collection toImport = new LinkedHashSet<>(); + Collection toUpdateDigest = new LinkedHashSet<>(); long lastWorkspaceStateSaved = getLastWorkspaceStateModified(); Set artifactIds = new LinkedHashSet<>(); //Separate existing projects from new ones @@ -188,7 +189,7 @@ public void importToWorkspace(IProgressMonitor monitor) throws CoreException, Op } } if (container == null) { - digestStore.updateDigest(pom.toPath()); + toUpdateDigest.add(pom.toPath()); toImport.add(projectInfo); artifactIds.add(projectInfo.getModel().getArtifactId()); } else { @@ -198,7 +199,7 @@ public void importToWorkspace(IProgressMonitor monitor) throws CoreException, Op projects.add(container.getProject()); } else if (project != null) { //Project doesn't have the Maven nature, so we (re)import it - digestStore.updateDigest(pom.toPath()); + toUpdateDigest.add(pom.toPath()); // need to delete project due to m2e failing to create if linked and not the same name project.delete(IProject.FORCE | IProject.NEVER_DELETE_PROJECT_CONTENT, subMonitor.split(5)); toImport.add(projectInfo); @@ -207,6 +208,9 @@ public void importToWorkspace(IProgressMonitor monitor) throws CoreException, Op } } + if (!toUpdateDigest.isEmpty()) { + digestStore.updateDigests(toUpdateDigest); + } if (!toImport.isEmpty()) { ProjectImportConfiguration importConfig = new ProjectImportConfiguration(); if (toImport.size() > artifactIds.size()) { diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/managers/MavenProjectImporterTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/managers/MavenProjectImporterTest.java index b81be68301..6d14ebbb3e 100644 --- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/managers/MavenProjectImporterTest.java +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/managers/MavenProjectImporterTest.java @@ -174,6 +174,29 @@ public void testChangedProjectShouldBeUpdated() throws Exception { assertEquals(1, jobSpy.updateProjectJobCalled, "Changed Project should be updated"); } + @Test + public void testDigestStoreBatchUpdate() throws Exception { + Path stateLocation = Files.createTempDirectory("digest-store-test"); + try { + Path first = stateLocation.resolve("first-pom.xml"); + Path second = stateLocation.resolve("second-pom.xml"); + Files.write(first, List.of("first")); + Files.write(second, List.of("second")); + + DigestStore digestStore = new DigestStore(stateLocation.toFile()); + assertTrue(digestStore.updateDigests(List.of(first, second))); + assertFalse(digestStore.updateDigests(List.of(first, second))); + + DigestStore persistedDigestStore = new DigestStore(stateLocation.toFile()); + assertFalse(persistedDigestStore.updateDigests(List.of(first, second))); + + Files.write(first, List.of("changed")); + assertTrue(persistedDigestStore.updateDigests(List.of(first, second))); + } finally { + FileUtils.deleteDirectory(stateLocation.toFile()); + } + } + @Test public void testPreexistingIProjectDifferentName() throws Exception { File from = new File(getSourceProjectDirectory(), "maven/salut");