fix: different jar file with the same name appears in the plugins directory after a failed installation (#3841)

#### 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 文件残留的问题
```
pull/3845/head
guqing 2023-04-24 18:20:06 +08:00 committed by GitHub
parent 2dcbceea5e
commit d589ce56cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 36 additions and 9 deletions

View File

@ -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<Request> {
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<Request> {
}
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);