From e0a1f240658a7ec73731ba831be110ad988e486e Mon Sep 17 00:00:00 2001 From: Sheng Chen Date: Thu, 19 Oct 2023 16:15:16 +0800 Subject: [PATCH 1/2] Import projects by configurations - Group the configuration files by file names and import them group by group. Signed-off-by: Sheng Chen --- .../internal/managers/ProjectsManager.java | 24 ++++++++++------- .../managers/ProjectsManagerTest.java | 27 ++++++++++--------- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManager.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManager.java index e04e83f4f6..d2dc2be10e 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManager.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManager.java @@ -173,17 +173,23 @@ protected void importProjectsFromConfigurationFiles(Collection rootPaths, MultiStatus importStatusCollection = new MultiStatus(IConstants.PLUGIN_ID, -1, "Failed to import projects", null); for (IPath rootPath : rootPaths) { File rootFolder = rootPath.toFile(); - try { - for (IProjectImporter importer : importers()) { - importer.initialize(rootFolder); - if (importer.applies(projectConfigurations, subMonitor.split(1))) { - importer.importToWorkspace(subMonitor.split(70)); + Map> configurationsByFileName = projectConfigurations.stream() + .filter(rootPath::isPrefixOf) + .collect(Collectors.groupingBy(IPath::lastSegment)); + for (List configurations : configurationsByFileName.values()) { + try { + for (IProjectImporter importer : importers()) { + importer.initialize(rootFolder); + if (importer.applies(configurations, subMonitor.split(1))) { + importer.importToWorkspace(subMonitor.split(70)); + break; + } } + } catch (CoreException e) { + // if one type of the project import failed, keep importing the next type + importStatusCollection.add(e.getStatus()); + JavaLanguageServerPlugin.logException("Failed to import projects", e); } - } catch (CoreException e) { - // if a rootPath import failed, keep importing the next rootPath - importStatusCollection.add(e.getStatus()); - JavaLanguageServerPlugin.logException("Failed to import projects", e); } } if (!importStatusCollection.isOK()) { diff --git a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManagerTest.java b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManagerTest.java index 795c510f56..24a90ec863 100644 --- a/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManagerTest.java +++ b/org.eclipse.jdt.ls.tests/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManagerTest.java @@ -231,13 +231,14 @@ public void dontFilterGitLikePackages() throws Exception { @Test public void testImportMavenSubModule() throws IOException, OperationCanceledException, CoreException { - Path projectDir = copyFiles("maven/multimodule", true).toPath(); + File projectDir = copyFiles("maven/multimodule", true); + Path projectDirPath = projectDir.toPath(); Collection configurationPaths = new ArrayList<>(); - Path subModuleConfiguration = projectDir.resolve("module1/pom.xml"); + Path subModuleConfiguration = projectDirPath.resolve("module1/pom.xml"); IPath filePath = ResourceUtils.canonicalFilePathFromURI(subModuleConfiguration.toUri().toString()); configurationPaths.add(filePath); preferenceManager.getPreferences().setProjectConfigurations(configurationPaths); - projectsManager.initializeProjects(Collections.singleton(new org.eclipse.core.runtime.Path(projectDir.toString())), monitor); + projectsManager.initializeProjects(Collections.singleton(new org.eclipse.core.runtime.Path(projectDir.getAbsolutePath())), monitor); IProject[] allProjects = ProjectUtils.getAllProjects(); Set expectedProjects = new HashSet<>(Arrays.asList( "module1", @@ -252,13 +253,14 @@ public void testImportMavenSubModule() throws IOException, OperationCanceledExce @Test public void testImportMixedProjects() throws IOException, OperationCanceledException, CoreException { - Path projectDir = copyFiles("mixed", true).toPath(); + File projectDir = copyFiles("mixed", true); + Path projectDirPath = projectDir.toPath(); Collection configurationPaths = new ArrayList<>(); - configurationPaths.add(ResourceUtils.canonicalFilePathFromURI(projectDir.resolve("hello/.project").toUri().toString())); - configurationPaths.add(ResourceUtils.canonicalFilePathFromURI(projectDir.resolve("simple-gradle/build.gradle").toUri().toString())); - configurationPaths.add(ResourceUtils.canonicalFilePathFromURI(projectDir.resolve("salut/pom.xml").toUri().toString())); + configurationPaths.add(ResourceUtils.canonicalFilePathFromURI(projectDirPath.resolve("hello/.project").toUri().toString())); + configurationPaths.add(ResourceUtils.canonicalFilePathFromURI(projectDirPath.resolve("simple-gradle/build.gradle").toUri().toString())); + configurationPaths.add(ResourceUtils.canonicalFilePathFromURI(projectDirPath.resolve("salut/pom.xml").toUri().toString())); preferenceManager.getPreferences().setProjectConfigurations(configurationPaths); - projectsManager.initializeProjects(Collections.singleton(new org.eclipse.core.runtime.Path(projectDir.toString())), monitor); + projectsManager.initializeProjects(Collections.singleton(new org.eclipse.core.runtime.Path(projectDir.getAbsolutePath())), monitor); IProject[] allProjects = ProjectUtils.getAllProjects(); Set expectedProjects = new HashSet<>(Arrays.asList( "jdt.ls-java-project", @@ -274,12 +276,13 @@ public void testImportMixedProjects() throws IOException, OperationCanceledExcep @Test public void testImportMixedProjectsPartially() throws IOException, OperationCanceledException, CoreException { - Path projectDir = copyFiles("mixed", true).toPath(); + File projectDir = copyFiles("mixed", true); + Path projectDirPath = projectDir.toPath(); Collection configurationPaths = new ArrayList<>(); - configurationPaths.add(ResourceUtils.canonicalFilePathFromURI(projectDir.resolve("simple-gradle/build.gradle").toUri().toString())); - configurationPaths.add(ResourceUtils.canonicalFilePathFromURI(projectDir.resolve("salut/pom.xml").toUri().toString())); + configurationPaths.add(ResourceUtils.canonicalFilePathFromURI(projectDirPath.resolve("simple-gradle/build.gradle").toUri().toString())); + configurationPaths.add(ResourceUtils.canonicalFilePathFromURI(projectDirPath.resolve("salut/pom.xml").toUri().toString())); preferenceManager.getPreferences().setProjectConfigurations(configurationPaths); - projectsManager.initializeProjects(Collections.singleton(new org.eclipse.core.runtime.Path(projectDir.toString())), monitor); + projectsManager.initializeProjects(Collections.singleton(new org.eclipse.core.runtime.Path(projectDir.getAbsolutePath())), monitor); IProject[] allProjects = ProjectUtils.getAllProjects(); Set expectedProjects = new HashSet<>(Arrays.asList( "jdt.ls-java-project", From 96a08e0671052fbf296d1cd7db9e7badd4ab85d0 Mon Sep 17 00:00:00 2001 From: Sheng Chen Date: Mon, 13 Nov 2023 13:03:06 +0800 Subject: [PATCH 2/2] Address comments Signed-off-by: Sheng Chen --- .../internal/AbstractProjectImporter.java | 21 ++++++++-- .../managers/GradleProjectImporter.java | 18 ++++++-- .../internal/managers/ProjectsManager.java | 42 ++++++++++++------- 3 files changed, 58 insertions(+), 23 deletions(-) diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/AbstractProjectImporter.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/AbstractProjectImporter.java index f5f15f61a0..0721ab174e 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/AbstractProjectImporter.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/AbstractProjectImporter.java @@ -45,8 +45,20 @@ public void initialize(File rootFolder) { public abstract boolean applies(IProgressMonitor monitor) throws OperationCanceledException, CoreException; @Override - public boolean isResolved(File folder) throws OperationCanceledException, CoreException { - return directories != null && directories.contains(folder.toPath()); + public boolean isResolved(File file) throws OperationCanceledException, CoreException { + if (directories == null) { + return false; + } + // if input is a directory (usually the root folder), + // check if the importer has imported it. + if (file.isDirectory()) { + return directories.contains(file.toPath()); + } + + // if the input is a file, check if the parent directory is imported. + return directories.stream().anyMatch((directory) -> { + return file.toPath().getParent().equals(directory); + }); }; @Override @@ -82,6 +94,10 @@ protected Collection findProjectPathByConfigurationName(Collection return filteredPaths; } + return eliminateNestedPaths(filteredPaths); + } + + protected List eliminateNestedPaths(List filteredPaths) { Path parentDir = null; List result = new LinkedList<>(); for (Path path : filteredPaths) { @@ -95,7 +111,6 @@ protected Collection findProjectPathByConfigurationName(Collection parentDir = path; } } - return result; } } 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 8def245767..ab094dbcdc 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 @@ -127,6 +127,11 @@ public class GradleProjectImporter extends AbstractProjectImporter { .replaceAll("\n", System.lineSeparator()); //@formatter:on + /** + * A flag whether this importer is activated by manual selection mode. + */ + private boolean manualSelection = false; + /* (non-Javadoc) * @see org.eclipse.jdt.ls.core.internal.managers.IProjectImporter#applies(org.eclipse.core.runtime.IProgressMonitor) */ @@ -158,6 +163,7 @@ public boolean applies(IProgressMonitor monitor) throws CoreException { @Override public boolean applies(Collection buildFiles, IProgressMonitor monitor) { + manualSelection = true; if (!getPreferences().isImportGradleEnabled()) { return false; } @@ -167,7 +173,7 @@ public boolean applies(Collection buildFiles, IProgressMonitor monitor) { SETTINGS_GRADLE_DESCRIPTOR, BUILD_GRADLE_KTS_DESCRIPTOR, SETTINGS_GRADLE_KTS_DESCRIPTOR - ), false /*includeNested*/); + ), true /*includeNested*/); if (configurationDirs == null || configurationDirs.isEmpty()) { return false; } @@ -199,16 +205,20 @@ public void importToWorkspace(IProgressMonitor monitor) throws CoreException { if (!applies(monitor)) { return; } - int projectSize = directories.size(); + List directoriesToImport = new ArrayList<>(this.directories); + if (manualSelection) { + directoriesToImport = eliminateNestedPaths(directoriesToImport); + } + int projectSize = directoriesToImport.size(); SubMonitor subMonitor = SubMonitor.convert(monitor, projectSize + 1); subMonitor.setTaskName(IMPORTING_GRADLE_PROJECTS); JavaLanguageServerPlugin.logInfo(IMPORTING_GRADLE_PROJECTS); subMonitor.worked(1); // run just once at the first project, assuming that all projects are using the same gradle version. - inferGradleJavaHome(directories.iterator().next(), monitor); + inferGradleJavaHome(directoriesToImport.iterator().next(), monitor); MultiStatus compatibilityStatus = new MultiStatus(IConstants.PLUGIN_ID, -1, "Compatibility issue occurs when importing Gradle projects", null); MultiStatus gradleUpgradeWrapperStatus = new MultiStatus(IConstants.PLUGIN_ID, -1, "Gradle upgrade wrapper", null); - for (Path directory : directories) { + for (Path directory : directoriesToImport) { IStatus importStatus = importDir(directory, subMonitor.newChild(1)); if (isFailedStatus(importStatus) && importStatus instanceof GradleCompatibilityStatus) { compatibilityStatus.add(importStatus); diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManager.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManager.java index d2dc2be10e..43921f9a60 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManager.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/managers/ProjectsManager.java @@ -23,10 +23,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; +import java.util.Set; import java.util.TreeMap; -import java.util.Map.Entry; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -173,23 +174,20 @@ protected void importProjectsFromConfigurationFiles(Collection rootPaths, MultiStatus importStatusCollection = new MultiStatus(IConstants.PLUGIN_ID, -1, "Failed to import projects", null); for (IPath rootPath : rootPaths) { File rootFolder = rootPath.toFile(); - Map> configurationsByFileName = projectConfigurations.stream() - .filter(rootPath::isPrefixOf) - .collect(Collectors.groupingBy(IPath::lastSegment)); - for (List configurations : configurationsByFileName.values()) { - try { - for (IProjectImporter importer : importers()) { - importer.initialize(rootFolder); - if (importer.applies(configurations, subMonitor.split(1))) { - importer.importToWorkspace(subMonitor.split(70)); - break; - } + Set buildFiles = projectConfigurations.stream() + .filter(rootPath::isPrefixOf).collect(Collectors.toSet()); + try { + for (IProjectImporter importer : importers()) { + importer.initialize(rootFolder); + if (importer.applies(buildFiles, subMonitor.split(1))) { + importer.importToWorkspace(subMonitor.split(70)); + buildFiles = removeImportedConfigurations(buildFiles, importer); } - } catch (CoreException e) { - // if one type of the project import failed, keep importing the next type - importStatusCollection.add(e.getStatus()); - JavaLanguageServerPlugin.logException("Failed to import projects", e); } + } catch (CoreException e) { + // if a rootPath import failed, keep importing the next rootPath + importStatusCollection.add(e.getStatus()); + JavaLanguageServerPlugin.logException("Failed to import projects", e); } } if (!importStatusCollection.isOK()) { @@ -197,6 +195,18 @@ protected void importProjectsFromConfigurationFiles(Collection rootPaths, } } + private Set removeImportedConfigurations(Set configurations, IProjectImporter importer) { + return configurations.stream() + .filter(config -> { + try { + return !importer.isResolved(config.toFile()); + } catch (OperationCanceledException | CoreException e) { + return true; + } + }) + .collect(Collectors.toSet()); + } + public void importProjects(IProgressMonitor monitor) { WorkspaceJob job = new WorkspaceJob("Importing projects in workspace...") {