Skip to content
Open
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
Expand Up @@ -168,13 +168,11 @@ public void setListener(RecursiveImportListener listener) {

@Override
public IStatus run(IProgressMonitor monitor) {
IWorkspace workspace = ResourcesPlugin.getWorkspace();
boolean isAutoBuilding = workspace.isAutoBuilding();
try {
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceDescription description = workspace.getDescription();
boolean isAutoBuilding = workspace.isAutoBuilding();
if (isAutoBuilding) {
description.setAutoBuilding(false);
workspace.setDescription(description);
setAutoBuilding(workspace, false);
}

if (directoriesToImport != null) {
Expand All @@ -194,24 +192,29 @@ public IStatus run(IProgressMonitor monitor) {
SortedMap<File, IProject> leafToRootProjects = new TreeMap<>(Collections.reverseOrder(rootToLeafComparator));
final Set<IProject> alreadyConfiguredProjects = new HashSet<>();
loopMonitor.worked(1);
for (final File directoryToImport : directories) {
final boolean alreadyAnEclipseProject = new File(directoryToImport, IProjectDescription.DESCRIPTION_FILE_NAME).isFile();
try {
IProject newProject = toExistingOrNewProject(directoryToImport, loopMonitor.split(1),
IResource.BACKGROUND_REFRESH);
if (alreadyAnEclipseProject) {
alreadyConfiguredProjects.add(newProject);
}
leafToRootProjects.put(directoryToImport, newProject);
loopMonitor.worked(1);
} catch (CouldNotImportProjectException ex) {
IPath path = IPath.fromOSString(directoryToImport.getAbsolutePath());
if (listener != null) {
listener.errorHappened(path, ex);
// Create all projects in one workspace operation, so listeners see a single
// resource delta instead of one per project. No configurator runs here.
workspace.run(creationMonitor -> {
for (final File directoryToImport : directories) {
final boolean alreadyAnEclipseProject = new File(directoryToImport,
IProjectDescription.DESCRIPTION_FILE_NAME).isFile();
try {
IProject newProject = toExistingOrNewProject(directoryToImport, loopMonitor.split(1),
IResource.BACKGROUND_REFRESH);
if (alreadyAnEclipseProject) {
alreadyConfiguredProjects.add(newProject);
}
leafToRootProjects.put(directoryToImport, newProject);
loopMonitor.worked(1);
} catch (CouldNotImportProjectException ex) {
IPath path = IPath.fromOSString(directoryToImport.getAbsolutePath());
if (listener != null) {
listener.errorHappened(path, ex);
}
this.errors.put(path, ex);
}
this.errors.put(path, ex);
}
}
}, this.workspaceRoot, IWorkspace.AVOID_UPDATE, null);
if (configureProjects) {
JobGroup multiDirectoriesJobGroup = new JobGroup(
DataTransferMessages.SmartImportJob_configuringSelectedDirectories, 20, 1);
Expand Down Expand Up @@ -270,21 +273,32 @@ protected IStatus run(IProgressMonitor aMonitor) {
try {
project.close(monitor);
} catch (CoreException e) {
listener.errorHappened(project.getLocation(), e);
if (listener != null) {
listener.errorHappened(project.getLocation(), e);
}
}
});
}

if (isAutoBuilding) {
description.setAutoBuilding(true);
workspace.setDescription(description);
}
} catch (Exception ex) {
return new Status(IStatus.ERROR, IDEWorkbenchPlugin.IDE_WORKBENCH, ex.getMessage(), ex);
} finally {
if (isAutoBuilding) {
try {
setAutoBuilding(workspace, true);
} catch (CoreException ex) {
IDEWorkbenchPlugin.log("Could not restore auto-building after import", ex); //$NON-NLS-1$
}
}
}
return Status.OK_STATUS;
}

private static void setAutoBuilding(IWorkspace workspace, boolean autoBuilding) throws CoreException {
IWorkspaceDescription description = workspace.getDescription();
description.setAutoBuilding(autoBuilding);
workspace.setDescription(description);
}

protected boolean rootProjectWorthBeingRemoved() {
if (this.report.size() == 1) {
return false;
Expand Down Expand Up @@ -451,7 +465,9 @@ private Set<IProject> importProjectAndChildrenRecursively(final IContainer conta
}
}

if (!mainProjectConfigurators.isEmpty()) {
// The container was already refreshed above, so refresh again only if the project
// is a different resource (nested project created for a child folder).
if (!mainProjectConfigurators.isEmpty() && !project.equals(container)) {
project.refreshLocal(IResource.DEPTH_INFINITE, subMonitor.split(1));
}
for (ProjectConfigurator configurator : mainProjectConfigurators) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
Expand Down Expand Up @@ -189,6 +192,42 @@ public void testImport6Projects() throws IOException, OperationCanceledException
assertEquals(6, ResourcesPlugin.getWorkspace().getRoot().getProjects().length);
}

@Test
public void testProjectsAreCreatedInASingleWorkspaceOperation() throws Exception {
AtomicInteger eventsAddingProjects = new AtomicInteger();
IResourceChangeListener listener = event -> {
IResourceDelta delta = event.getDelta();
if (delta != null && delta.getAffectedChildren(IResourceDelta.ADDED).length > 0) {
eventsAddingProjects.incrementAndGet();
}
};
java.nio.file.Path tempDir = Files.createTempDirectory("smartImportBatch");
try {
Set<File> directories = new HashSet<>();
for (int i = 0; i < 3; i++) {
String name = "batchProject" + i;
File projectDirectory = new File(tempDir.toFile(), name);
projectDirectory.mkdirs();
Files.writeString(new File(projectDirectory, ".project").toPath(),
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><projectDescription><name>" + name
+ "</name></projectDescription>");
directories.add(projectDirectory);
}
SmartImportJob job = new SmartImportJob(tempDir.toFile(), Collections.emptySet(), false, false);
job.setDirectoriesToImport(directories);
ResourcesPlugin.getWorkspace().addResourceChangeListener(listener, IResourceChangeEvent.POST_CHANGE);
IStatus status = job.run(new NullProgressMonitor());

assertTrue("Import failed: " + status, status.isOK());
assertEquals(directories.size(), ResourcesPlugin.getWorkspace().getRoot().getProjects().length);
assertEquals("All projects should be created in a single workspace operation", 1,
eventsAddingProjects.get());
} finally {
ResourcesPlugin.getWorkspace().removeResourceChangeListener(listener);
org.eclipse.core.tests.harness.FileSystemHelper.clear(tempDir.toFile());
}
}

@Test
public void testImportModularProjectsWithSameName()
throws IOException, OperationCanceledException, InterruptedException {
Expand Down Expand Up @@ -572,4 +611,20 @@ public void testSmartImportJobSkipsDotFoldersInProposals() throws Exception {
org.eclipse.core.tests.harness.FileSystemHelper.clear(tempDir.toFile());
}
}

@Test
public void testAutoBuildingRestoredAfterFailedImport() throws Exception {
assertTrue("Test expects auto-building to be enabled", ResourcesPlugin.getWorkspace().isAutoBuilding());
// a regular file as import root makes the project creation fail
java.nio.file.Path notADirectory = Files.createTempFile("smartImportFailure", ".txt");
try {
SmartImportJob job = new SmartImportJob(notADirectory.toFile(), Collections.emptySet(), true, true);
IStatus status = job.run(new NullProgressMonitor());
assertEquals("Import was expected to fail", IStatus.ERROR, status.getSeverity());
assertTrue("Auto-building must be restored after a failed import",
ResourcesPlugin.getWorkspace().isAutoBuilding());
} finally {
Files.deleteIfExists(notADirectory);
}
}
}
Loading