From d589ce56cc16fe0732dd396a60c58510c03dbbce Mon Sep 17 00:00:00 2001 From: guqing <38999863+guqing@users.noreply.github.com> Date: Mon, 24 Apr 2023 18:20:06 +0800 Subject: [PATCH] fix: different jar file with the same name appears in the plugins directory after a failed installation (#3841) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### What type of PR is this? /kind bug /area core /milestone 2.5.x #### What this PR does / why we need it: 修复插件安装后无法启动会导致卸载后插件 JAR 文件残留的问题 how to test it? 1. 安装一个无法启动的插件,比如在插件声明周期方法中抛一个异常 2. 启动插件,然后卸载插件看插件 JAR 是否被正确删除 3. 如果是插件开发模式则不会删除文件 #### Which issue(s) this PR fixes: Fixes #3840 #### Does this PR introduce a user-facing change? ```release-note 修复插件安装后无法启动会导致卸载后插件 JAR 文件残留的问题 ``` --- .../reconciler/PluginReconciler.java | 45 +++++++++++++++---- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/application/src/main/java/run/halo/app/core/extension/reconciler/PluginReconciler.java b/application/src/main/java/run/halo/app/core/extension/reconciler/PluginReconciler.java index acc253bf9..6024bb28c 100644 --- a/application/src/main/java/run/halo/app/core/extension/reconciler/PluginReconciler.java +++ b/application/src/main/java/run/halo/app/core/extension/reconciler/PluginReconciler.java @@ -1,5 +1,6 @@ package run.halo.app.core.extension.reconciler; +import static org.pf4j.util.FileUtils.isJarFile; import static run.halo.app.plugin.PluginConst.DELETE_STAGE; import java.io.IOException; @@ -22,6 +23,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.pf4j.PluginDescriptor; +import org.pf4j.PluginRuntimeException; import org.pf4j.PluginState; import org.pf4j.PluginWrapper; import org.pf4j.RuntimeMode; @@ -277,6 +279,15 @@ public class PluginReconciler implements Reconciler { throw e; } } + + if (currentState != desiredState) { + log.error("Plugin [{}] state transition failed: {}", name, + haloPluginManager.getPluginStartingError(name)); + var e = new PluginRuntimeException("Plugin [" + name + "] state transition from [" + + currentState + "] to [" + desiredState + "] failed"); + persistenceFailureStatus(name, e); + throw e; + } } void persistenceFailureStatus(String pluginName, Throwable e) { @@ -554,25 +565,41 @@ public class PluginReconciler implements Reconciler { } PluginWrapper pluginWrapper = haloPluginManager.getPlugin(name); - if (pluginWrapper == null) { - return; - } - // pluginWrapper must not be null in below code - // stop and unload plugin, see also PluginBeforeStopSyncListener - if (!haloPluginManager.unloadPlugin(name)) { - throw new IllegalStateException("Failed to unload plugin: " + name); + if (pluginWrapper != null) { + // pluginWrapper must not be null in below code + // stop and unload plugin, see also PluginBeforeStopSyncListener + if (!haloPluginManager.unloadPlugin(name)) { + throw new IllegalStateException("Failed to unload plugin: " + name); + } } + // delete plugin resources - if (RuntimeMode.DEPLOYMENT.equals(pluginWrapper.getRuntimeMode())) { + Path pluginPath = determinePluginLocation(plugin); + if (pluginPath != null && !isDevelopmentMode(name) && isJarFile(pluginPath)) { // delete plugin file try { - Files.deleteIfExists(pluginWrapper.getPluginPath()); + Files.deleteIfExists(pluginPath); } catch (IOException e) { throw new RuntimeException(e); } } } + @Nullable + Path determinePluginLocation(Plugin plugin) { + final var name = plugin.getMetadata().getName(); + PluginWrapper pluginWrapper = haloPluginManager.getPlugin(name); + return Optional.ofNullable(pluginWrapper) + .map(PluginWrapper::getPluginPath) + .orElseGet(() -> { + var localtionUri = plugin.statusNonNull().getLoadLocation(); + if (localtionUri != null) { + return Path.of(localtionUri); + } + return null; + }); + } + void createInitialReverseProxyIfNotPresent(Plugin plugin) { String pluginName = plugin.getMetadata().getName(); String reverseProxyName = initialReverseProxyName(pluginName);