mirror of https://github.com/halo-dev/halo
Fix the problem that plugins without jar file may not be deleted (#6334)
#### What type of PR is this? /kind bug /area core /area plugin /milestone 2.18.x #### What this PR does / why we need it: This PR checks if the plugin is already unloaded while getting dependents to fix the problem that plugins without jar file may not be deleted or not be enabled or disabled. #### Which issue(s) this PR fixes: Fixes https://github.com/halo-dev/halo/issues/6072 #### Special notes for your reviewer: 1. Try to move plugins folder to another folder 2. Restart Halo 3. Try to change state of plugins or delete plugins directly 4. See the result #### Does this PR introduce a user-facing change? ```release-note 修复在没有插件文件的情况下可能无法删除插件的问题 ```pull/6363/head
parent
6791b5e3b8
commit
eae83ae949
|
@ -22,6 +22,7 @@ import org.pf4j.PluginStateEvent;
|
|||
import org.pf4j.PluginStateListener;
|
||||
import org.pf4j.PluginStatusProvider;
|
||||
import org.pf4j.PluginWrapper;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import run.halo.app.infra.SystemVersionSupplier;
|
||||
|
@ -36,33 +37,27 @@ import run.halo.app.plugin.event.PluginStartedEvent;
|
|||
* @since 2.0.0
|
||||
*/
|
||||
@Slf4j
|
||||
public class HaloPluginManager extends DefaultPluginManager implements SpringPluginManager {
|
||||
public class HaloPluginManager extends DefaultPluginManager
|
||||
implements SpringPluginManager, InitializingBean {
|
||||
|
||||
private final ApplicationContext rootContext;
|
||||
|
||||
private final Lazy<ApplicationContext> sharedContext;
|
||||
private Lazy<ApplicationContext> sharedContext;
|
||||
|
||||
private final PluginProperties pluginProperties;
|
||||
|
||||
private final PluginsRootGetter pluginsRootGetter;
|
||||
|
||||
private final SystemVersionSupplier systemVersionSupplier;
|
||||
|
||||
public HaloPluginManager(ApplicationContext rootContext,
|
||||
PluginProperties pluginProperties,
|
||||
SystemVersionSupplier systemVersionSupplier, PluginsRootGetter pluginsRootGetter) {
|
||||
SystemVersionSupplier systemVersionSupplier,
|
||||
PluginsRootGetter pluginsRootGetter) {
|
||||
this.pluginProperties = pluginProperties;
|
||||
this.rootContext = rootContext;
|
||||
// We have to initialize share context lazily because the root context has not refreshed
|
||||
this.sharedContext = Lazy.of(() -> SharedApplicationContextFactory.create(rootContext));
|
||||
this.pluginsRootGetter = pluginsRootGetter;
|
||||
super.runtimeMode = pluginProperties.getRuntimeMode();
|
||||
|
||||
setExactVersionAllowed(pluginProperties.isExactVersionAllowed());
|
||||
setSystemVersion(systemVersionSupplier.get().getNormalVersion());
|
||||
|
||||
super.initialize();
|
||||
|
||||
// the listener must be after the super#initialize
|
||||
addPluginStateListener(new PluginStartedListener());
|
||||
this.systemVersionSupplier = systemVersionSupplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -71,6 +66,18 @@ public class HaloPluginManager extends DefaultPluginManager implements SpringPlu
|
|||
// components before properties set.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
super.runtimeMode = pluginProperties.getRuntimeMode();
|
||||
this.sharedContext = Lazy.of(() -> SharedApplicationContextFactory.create(rootContext));
|
||||
setExactVersionAllowed(pluginProperties.isExactVersionAllowed());
|
||||
setSystemVersion(systemVersionSupplier.get().toStableVersion().toString());
|
||||
|
||||
super.initialize();
|
||||
// the listener must be after the super#initialize
|
||||
addPluginStateListener(new PluginStartedListener());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExtensionFactory createExtensionFactory() {
|
||||
return new SpringExtensionFactory(this);
|
||||
|
@ -154,6 +161,10 @@ public class HaloPluginManager extends DefaultPluginManager implements SpringPlu
|
|||
|
||||
@Override
|
||||
public List<PluginWrapper> getDependents(String pluginId) {
|
||||
if (getPlugin(pluginId) == null) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
var dependents = new ArrayList<PluginWrapper>();
|
||||
var stack = new Stack<String>();
|
||||
dependencyResolver.getDependents(pluginId).forEach(stack::push);
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
package run.halo.app.plugin;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.github.zafarkhaja.semver.Version;
|
||||
import java.nio.file.Path;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.pf4j.RuntimeMode;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import run.halo.app.infra.SystemVersionSupplier;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class HaloPluginManagerTest {
|
||||
|
||||
@Mock
|
||||
PluginProperties pluginProperties;
|
||||
|
||||
@Mock
|
||||
SystemVersionSupplier systemVersionSupplier;
|
||||
|
||||
@Mock
|
||||
PluginsRootGetter pluginsRootGetter;
|
||||
|
||||
@Mock
|
||||
ApplicationContext rootContext;
|
||||
|
||||
@InjectMocks
|
||||
HaloPluginManager pluginManager;
|
||||
|
||||
@TempDir
|
||||
Path tempDir;
|
||||
|
||||
@Test
|
||||
void shouldGetDependentsWhilePluginsNotResolved() throws Exception {
|
||||
when(pluginProperties.getRuntimeMode()).thenReturn(RuntimeMode.DEPLOYMENT);
|
||||
when(systemVersionSupplier.get()).thenReturn(Version.of(1, 2, 3));
|
||||
when(pluginsRootGetter.get()).thenReturn(tempDir);
|
||||
pluginManager.afterPropertiesSet();
|
||||
// if we don't invoke resolves
|
||||
var dependents = pluginManager.getDependents("fake-plugin");
|
||||
assertTrue(dependents.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldGetDependentsWhilePluginsResolved() throws Exception {
|
||||
when(pluginProperties.getRuntimeMode()).thenReturn(RuntimeMode.DEPLOYMENT);
|
||||
when(systemVersionSupplier.get()).thenReturn(Version.of(1, 2, 3));
|
||||
when(pluginsRootGetter.get()).thenReturn(tempDir);
|
||||
pluginManager.afterPropertiesSet();
|
||||
pluginManager.loadPlugins();
|
||||
// if we don't invoke resolves
|
||||
var dependents = pluginManager.getDependents("fake-plugin");
|
||||
assertTrue(dependents.isEmpty());
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue