mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-13 08:55:44 +01:00
Add cancel method to remove install and uninstall files
This commit is contained in:
@@ -93,4 +93,6 @@ public interface PluginManager {
|
|||||||
* Install all pending plugins and restart the scm context.
|
* Install all pending plugins and restart the scm context.
|
||||||
*/
|
*/
|
||||||
void executePendingAndRestart();
|
void executePendingAndRestart();
|
||||||
|
|
||||||
|
void cancelInstallations();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ import sonia.scm.lifecycle.RestartEvent;
|
|||||||
import sonia.scm.version.Version;
|
import sonia.scm.version.Version;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -72,7 +72,8 @@ public class DefaultPluginManager implements PluginManager {
|
|||||||
private final PluginLoader loader;
|
private final PluginLoader loader;
|
||||||
private final PluginCenter center;
|
private final PluginCenter center;
|
||||||
private final PluginInstaller installer;
|
private final PluginInstaller installer;
|
||||||
private final Collection<PendingPluginInstallation> pendingQueue = new ArrayList<>();
|
private final Collection<PendingPluginInstallation> pendingInstallQueue = new ArrayList<>();
|
||||||
|
private final Collection<PendingPluginUninstallation> pendingUninstallQueue = new ArrayList<>();
|
||||||
private final PluginDependencyTracker dependencyTracker = new PluginDependencyTracker();
|
private final PluginDependencyTracker dependencyTracker = new PluginDependencyTracker();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@@ -106,7 +107,7 @@ public class DefaultPluginManager implements PluginManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Optional<AvailablePlugin> getPending(String name) {
|
private Optional<AvailablePlugin> getPending(String name) {
|
||||||
return pendingQueue
|
return pendingInstallQueue
|
||||||
.stream()
|
.stream()
|
||||||
.map(PendingPluginInstallation::getPlugin)
|
.map(PendingPluginInstallation::getPlugin)
|
||||||
.filter(filterByName(name))
|
.filter(filterByName(name))
|
||||||
@@ -179,7 +180,7 @@ public class DefaultPluginManager implements PluginManager {
|
|||||||
if (restartAfterInstallation) {
|
if (restartAfterInstallation) {
|
||||||
restart("plugin installation");
|
restart("plugin installation");
|
||||||
} else {
|
} else {
|
||||||
pendingQueue.addAll(pendingInstallations);
|
pendingInstallQueue.addAll(pendingInstallations);
|
||||||
updateMayUninstallFlag();
|
updateMayUninstallFlag();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -192,15 +193,8 @@ public class DefaultPluginManager implements PluginManager {
|
|||||||
.orElseThrow(() -> NotFoundException.notFound(entity(InstalledPlugin.class, name)));
|
.orElseThrow(() -> NotFoundException.notFound(entity(InstalledPlugin.class, name)));
|
||||||
doThrow().violation("plugin is a core plugin and cannot be uninstalled").when(installed.isCore());
|
doThrow().violation("plugin is a core plugin and cannot be uninstalled").when(installed.isCore());
|
||||||
|
|
||||||
dependencyTracker.removeInstalled(installed.getDescriptor());
|
|
||||||
|
|
||||||
try {
|
markForUninstall(installed);
|
||||||
createMarkerFile(installed, InstalledPlugin.UNINSTALL_MARKER_FILENAME);
|
|
||||||
installed.setMarkedForUninstall(true);
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
dependencyTracker.addInstalled(installed.getDescriptor());
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (restartAfterInstallation) {
|
if (restartAfterInstallation) {
|
||||||
restart("plugin installation");
|
restart("plugin installation");
|
||||||
@@ -220,18 +214,22 @@ public class DefaultPluginManager implements PluginManager {
|
|||||||
&& dependencyTracker.mayUninstall(p.getDescriptor().getInformation().getName());
|
&& dependencyTracker.mayUninstall(p.getDescriptor().getInformation().getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createMarkerFile(InstalledPlugin plugin, String markerFile) {
|
private void markForUninstall(InstalledPlugin plugin) {
|
||||||
|
dependencyTracker.removeInstalled(plugin.getDescriptor());
|
||||||
try {
|
try {
|
||||||
Files.createFile(plugin.getDirectory().resolve(markerFile));
|
Path file = Files.createFile(plugin.getDirectory().resolve(InstalledPlugin.UNINSTALL_MARKER_FILENAME));
|
||||||
} catch (IOException e) {
|
pendingUninstallQueue.add(new PendingPluginUninstallation(plugin, file));
|
||||||
throw new PluginException("could not mark plugin " + plugin.getId() + " in path " + plugin.getDirectory() + "as " + markerFile, e);
|
plugin.setMarkedForUninstall(true);
|
||||||
|
} catch (Exception e) {
|
||||||
|
dependencyTracker.addInstalled(plugin.getDescriptor());
|
||||||
|
throw new PluginException("could not mark plugin " + plugin.getId() + " in path " + plugin.getDirectory() + "as " + InstalledPlugin.UNINSTALL_MARKER_FILENAME, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void executePendingAndRestart() {
|
public void executePendingAndRestart() {
|
||||||
PluginPermissions.manage().check();
|
PluginPermissions.manage().check();
|
||||||
if (!pendingQueue.isEmpty() || getInstalled().stream().anyMatch(InstalledPlugin::isMarkedForUninstall)) {
|
if (!pendingInstallQueue.isEmpty() || getInstalled().stream().anyMatch(InstalledPlugin::isMarkedForUninstall)) {
|
||||||
restart("execute pending plugin changes");
|
restart("execute pending plugin changes");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -274,4 +272,10 @@ public class DefaultPluginManager implements PluginManager {
|
|||||||
private boolean isUpdatable(String name) {
|
private boolean isUpdatable(String name) {
|
||||||
return getAvailable(name).isPresent() && !getPending(name).isPresent();
|
return getAvailable(name).isPresent() && !getPending(name).isPresent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancelInstallations() {
|
||||||
|
pendingUninstallQueue.forEach(PendingPluginUninstallation::cancel);
|
||||||
|
pendingInstallQueue.forEach(PendingPluginInstallation::cancel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package sonia.scm.plugin;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
class PendingPluginUninstallation {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(PendingPluginUninstallation.class);
|
||||||
|
|
||||||
|
private final InstalledPlugin plugin;
|
||||||
|
private final Path uninstallFile;
|
||||||
|
|
||||||
|
PendingPluginUninstallation(InstalledPlugin plugin, Path uninstallFile) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.uninstallFile = uninstallFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cancel() {
|
||||||
|
String name = plugin.getDescriptor().getInformation().getName();
|
||||||
|
LOG.info("cancel uninstallation of plugin {}", name);
|
||||||
|
try {
|
||||||
|
Files.delete(uninstallFile);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new PluginFailedToCancelInstallationException("failed to cancel uninstallation of plugin " + name, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,8 @@ import sonia.scm.ScmConstraintViolationException;
|
|||||||
import sonia.scm.event.ScmEventBus;
|
import sonia.scm.event.ScmEventBus;
|
||||||
import sonia.scm.lifecycle.RestartEvent;
|
import sonia.scm.lifecycle.RestartEvent;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@@ -445,6 +447,28 @@ class DefaultPluginManagerTest {
|
|||||||
|
|
||||||
verify(eventBus).post(any(RestartEvent.class));
|
verify(eventBus).post(any(RestartEvent.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldUndoPendingInstallations(@TempDirectory.TempDir Path temp) throws IOException {
|
||||||
|
InstalledPlugin mailPlugin = createInstalled("scm-ssh-plugin");
|
||||||
|
Path mailPluginPath = temp.resolve("scm-mail-plugin");
|
||||||
|
Files.createDirectories(mailPluginPath);
|
||||||
|
when(mailPlugin.getDirectory()).thenReturn(mailPluginPath);
|
||||||
|
when(loader.getInstalledPlugins()).thenReturn(singletonList(mailPlugin));
|
||||||
|
|
||||||
|
AvailablePlugin git = createAvailable("scm-git-plugin");
|
||||||
|
when(center.getAvailable()).thenReturn(ImmutableSet.of(git));
|
||||||
|
PendingPluginInstallation gitPendingPluginInformation = mock(PendingPluginInstallation.class);
|
||||||
|
when(installer.install(git)).thenReturn(gitPendingPluginInformation);
|
||||||
|
|
||||||
|
manager.install("scm-git-plugin", false);
|
||||||
|
manager.uninstall("scm-ssh-plugin", false);
|
||||||
|
|
||||||
|
manager.cancelInstallations();
|
||||||
|
|
||||||
|
assertThat(mailPluginPath.resolve("uninstall")).doesNotExist();
|
||||||
|
verify(gitPendingPluginInformation).cancel();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
|
|||||||
Reference in New Issue
Block a user