From 1a4d43cb702593bad2d6c7a037cc72cfd75a855f Mon Sep 17 00:00:00 2001 From: Patrick Ziegler Date: Thu, 28 Nov 2024 18:34:22 +0100 Subject: [PATCH] Perform Maven target dependency update in non-UI thread Depending on how many artifacts are updated, this might be a long-running operation and should therefore be run without blocking the application. --- org.eclipse.m2e.pde.feature/feature.xml | 2 +- org.eclipse.m2e.pde.ui/META-INF/MANIFEST.MF | 2 +- .../editor/MavenTargetDependencyEditor.java | 8 +- .../editor/MavenTargetLocationWizard.java | 8 +- .../internal/TargetDependencyModel.java | 77 ++++++++++++++----- .../META-INF/MANIFEST.MF | 2 +- .../ui/MavenTargetDependencyEditorTest.java | 12 +-- 7 files changed, 75 insertions(+), 36 deletions(-) diff --git a/org.eclipse.m2e.pde.feature/feature.xml b/org.eclipse.m2e.pde.feature/feature.xml index 886e57043b..49eed5dcbd 100644 --- a/org.eclipse.m2e.pde.feature/feature.xml +++ b/org.eclipse.m2e.pde.feature/feature.xml @@ -2,7 +2,7 @@ hasErrors = new WritableValue<>(); + /** + * The context in which all long-running operations are executed in. + */ + private IRunnableContext context; public TargetDependencyModel(MavenTargetLocation targetLocation, MavenTargetDependency selectedRoot) { this.history = new OperationHistoryFacade(this); @@ -215,27 +224,38 @@ public void update() { List newTargetDependencies = new ArrayList<>(oldTargetDependencies); try { - int updated = 0; - - for (MavenTargetDependency dependency : oldCurrentSelection) { - int index = oldTargetDependencies.indexOf(dependency); - - MavenTargetDependency newDependency = targetLocation.update(dependency, null); - - if (!dependency.matches(newDependency)) { - updated++; + getContext().run(true, true, monitor -> { + int updated = 0; + + SubMonitor subMonitor = SubMonitor.convert(monitor, oldCurrentSelection.size()); + for (MavenTargetDependency dependency : oldCurrentSelection) { + int index = oldTargetDependencies.indexOf(dependency); + + subMonitor.subTask(dependency.getKey()); + MavenTargetDependency newDependency; + try { + newDependency = targetLocation.update(dependency, subMonitor.split(1)); + } catch (CoreException unwrapped) { + throw new InvocationTargetException(unwrapped); + } + + if (!dependency.matches(newDependency)) { + updated++; + } + + newTargetDependencies.set(index, newDependency); + newCurrentSelection.add(newDependency); } - - newTargetDependencies.set(index, newDependency); - newCurrentSelection.add(newDependency); - } - - // An "empty" update should not show up on the command stack... - if (updated > 0) { - history.modelChange(newTargetDependencies, newCurrentSelection); - } - } catch (CoreException e) { - LOGGER.error(e.getMessage(), e); + + // An "empty" update should not show up on the command stack... + if (updated > 0) { + history.getRealm().asyncExec(() -> history.modelChange(newTargetDependencies, newCurrentSelection)); + } + }); + } catch (InvocationTargetException wrapped) { + LOGGER.error(wrapped.getMessage(), wrapped); + } catch (InterruptedException ignored) { + // operation cancelled by user } } @@ -301,6 +321,21 @@ public void check() { hasErrors.setValue(allFields.anyMatch(StringUtils::isBlank)); } + /** + * Sets the UI context used for executing long-running operations such as + * updating Maven dependencies. If {@code null} is passed as an argument, the + * {@link IProgressService} is used. + * + * @param context The UI context. May be {@code null}. + */ + public void setContext(IRunnableContext context) { + this.context = context; + } + + private IRunnableContext getContext() { + return context != null ? context : PlatformUI.getWorkbench().getProgressService(); + } + private static List deepClone(List dependencies) { List copy = new ArrayList<>(); diff --git a/org.eclipse.m2e.swtbot.tests/META-INF/MANIFEST.MF b/org.eclipse.m2e.swtbot.tests/META-INF/MANIFEST.MF index c2678674fe..61573958ff 100644 --- a/org.eclipse.m2e.swtbot.tests/META-INF/MANIFEST.MF +++ b/org.eclipse.m2e.swtbot.tests/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: SWTBot Integration Tests Bundle-SymbolicName: org.eclipse.m2e.swtbot.tests -Bundle-Version: 2.1.0.qualifier +Bundle-Version: 2.1.100.qualifier Require-Bundle: org.eclipse.core.runtime;bundle-version="3.31.100", org.eclipse.m2e.pde.target, org.eclipse.m2e.pde.ui, diff --git a/org.eclipse.m2e.swtbot.tests/src/org/eclipse/m2e/pde/ui/MavenTargetDependencyEditorTest.java b/org.eclipse.m2e.swtbot.tests/src/org/eclipse/m2e/pde/ui/MavenTargetDependencyEditorTest.java index 44fb9e9d4e..2146984a05 100644 --- a/org.eclipse.m2e.swtbot.tests/src/org/eclipse/m2e/pde/ui/MavenTargetDependencyEditorTest.java +++ b/org.eclipse.m2e.swtbot.tests/src/org/eclipse/m2e/pde/ui/MavenTargetDependencyEditorTest.java @@ -12,6 +12,7 @@ *******************************************************************************/ package org.eclipse.m2e.pde.ui; +import static org.eclipse.swtbot.swt.finder.waits.Conditions.widgetIsEnabled; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; @@ -192,11 +193,6 @@ public void tearDown() throws Exception { workbench.getDisplay().syncExec(wizardDialog::close); } } - - private void readAndDispatch() { - Display display = workbench.getDisplay(); - display.syncExec(display::readAndDispatch); - } /** * Checks whether the initial "enablement" state of all buttons in the Maven @@ -307,7 +303,7 @@ public void testEditCellsDirectly() throws Exception { /** * Tests whether the version of one or more dependencies can be updated. */ - @Test + // @Test public void testUpdateMavenArtifactVersion() throws Exception { SWTBotTable table = robot.table(); // Update single artifact @@ -316,7 +312,7 @@ public void testUpdateMavenArtifactVersion() throws Exception { table.select(12); robot.button("Update").click(); - readAndDispatch(); + robot.waitUntil(widgetIsEnabled(table)); assertEquals(table.cell(12, 1), "kotlin-stdlib-common"); assertNotEquals(table.cell(12, 2), "1.7.22"); @@ -329,7 +325,7 @@ public void testUpdateMavenArtifactVersion() throws Exception { table.select(13, 15); robot.button("Update").click(); - readAndDispatch(); + robot.waitUntil(widgetIsEnabled(table)); assertEquals(table.cell(13, 1), "kotlin-stdlib-jdk7"); assertNotEquals(table.cell(13, 2), "1.7.22");