mirror of https://github.com/halo-dev/halo
refactor: plugin configuration loading to adapt to plugin development mode (#2183)
* refactor: plugin configuration loading to adapt to plugin development mode * refactor: extension locations * refactor: plugin labels * fix: unit testpull/2190/head
parent
273ffaad48
commit
c0758f32d1
|
@ -62,6 +62,8 @@ public class Plugin extends AbstractExtension {
|
||||||
private String pluginClass = BasePlugin.class.getName();
|
private String pluginClass = BasePlugin.class.getName();
|
||||||
|
|
||||||
private Boolean enabled = false;
|
private Boolean enabled = false;
|
||||||
|
|
||||||
|
private List<String> extensionLocations;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
|
|
@ -368,9 +368,15 @@ public class HaloPluginManager extends DefaultPluginManager
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PluginWrapper loadPluginFromPath(Path pluginPath) {
|
protected PluginWrapper loadPluginFromPath(Path pluginPath) {
|
||||||
|
try {
|
||||||
PluginWrapper pluginWrapper = super.loadPluginFromPath(pluginPath);
|
PluginWrapper pluginWrapper = super.loadPluginFromPath(pluginPath);
|
||||||
rootApplicationContext.publishEvent(new HaloPluginLoadedEvent(this, pluginWrapper));
|
rootApplicationContext.publishEvent(new HaloPluginLoadedEvent(this, pluginWrapper));
|
||||||
return pluginWrapper;
|
return pluginWrapper;
|
||||||
|
} catch (PluginRuntimeException e) {
|
||||||
|
// ignore this
|
||||||
|
log.warn(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// end-region
|
// end-region
|
||||||
|
|
|
@ -96,7 +96,7 @@ public class PluginAutoConfiguration {
|
||||||
PluginDescriptor pluginDescriptor) {
|
PluginDescriptor pluginDescriptor) {
|
||||||
PluginClassLoader pluginClassLoader =
|
PluginClassLoader pluginClassLoader =
|
||||||
new PluginClassLoader(pluginManager, pluginDescriptor,
|
new PluginClassLoader(pluginManager, pluginDescriptor,
|
||||||
getClass().getClassLoader());
|
getClass().getClassLoader(), ClassLoadingStrategy.APD);
|
||||||
|
|
||||||
loadClasses(pluginPath, pluginClassLoader);
|
loadClasses(pluginPath, pluginClassLoader);
|
||||||
loadJars(pluginPath, pluginClassLoader);
|
loadJars(pluginPath, pluginClassLoader);
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package run.halo.app.plugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plugin constants.
|
||||||
|
*
|
||||||
|
* @author guqing
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
public interface PluginConst {
|
||||||
|
/**
|
||||||
|
* Plugin metadata labels key.
|
||||||
|
*/
|
||||||
|
String PLUGIN_NAME_LABEL_NAME = "plugin.halo.run/plugin-name";
|
||||||
|
}
|
|
@ -1,10 +1,16 @@
|
||||||
package run.halo.app.plugin;
|
package run.halo.app.plugin;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import org.pf4j.PluginWrapper;
|
import org.pf4j.PluginWrapper;
|
||||||
import org.springframework.context.ApplicationListener;
|
import org.springframework.context.ApplicationListener;
|
||||||
|
import org.springframework.core.io.DefaultResourceLoader;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import run.halo.app.core.extension.Plugin;
|
import run.halo.app.core.extension.Plugin;
|
||||||
import run.halo.app.extension.ExtensionClient;
|
import run.halo.app.extension.ExtensionClient;
|
||||||
|
import run.halo.app.infra.utils.YamlUnstructuredLoader;
|
||||||
import run.halo.app.plugin.event.HaloPluginLoadedEvent;
|
import run.halo.app.plugin.event.HaloPluginLoadedEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,11 +21,8 @@ import run.halo.app.plugin.event.HaloPluginLoadedEvent;
|
||||||
public class PluginLoadedListener implements ApplicationListener<HaloPluginLoadedEvent> {
|
public class PluginLoadedListener implements ApplicationListener<HaloPluginLoadedEvent> {
|
||||||
private final ExtensionClient extensionClient;
|
private final ExtensionClient extensionClient;
|
||||||
|
|
||||||
private final PluginUnstructuredResourceLoader pluginUnstructuredResourceLoader;
|
|
||||||
|
|
||||||
public PluginLoadedListener(ExtensionClient extensionClient) {
|
public PluginLoadedListener(ExtensionClient extensionClient) {
|
||||||
this.extensionClient = extensionClient;
|
this.extensionClient = extensionClient;
|
||||||
pluginUnstructuredResourceLoader = new PluginUnstructuredResourceLoader();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -31,8 +34,24 @@ public class PluginLoadedListener implements ApplicationListener<HaloPluginLoade
|
||||||
Plugin plugin = yamlPluginFinder.find(pluginWrapper.getPluginPath());
|
Plugin plugin = yamlPluginFinder.find(pluginWrapper.getPluginPath());
|
||||||
extensionClient.create(plugin);
|
extensionClient.create(plugin);
|
||||||
|
|
||||||
// load plugin unstructured resource
|
// load unstructured
|
||||||
pluginUnstructuredResourceLoader.loadUnstructured(pluginWrapper)
|
DefaultResourceLoader resourceLoader =
|
||||||
.forEach(extensionClient::create);
|
new DefaultResourceLoader(pluginWrapper.getPluginClassLoader());
|
||||||
|
plugin.getSpec().getExtensionLocations()
|
||||||
|
.stream()
|
||||||
|
.map(resourceLoader::getResource)
|
||||||
|
.filter(Resource::exists)
|
||||||
|
.map(resource -> new YamlUnstructuredLoader(resource).load())
|
||||||
|
.flatMap(List::stream)
|
||||||
|
.forEach(unstructured -> {
|
||||||
|
Map<String, String> labels = unstructured.getMetadata().getLabels();
|
||||||
|
if (labels == null) {
|
||||||
|
unstructured.getMetadata().setLabels(new HashMap<>());
|
||||||
|
}
|
||||||
|
unstructured.getMetadata()
|
||||||
|
.getLabels()
|
||||||
|
.put(PluginConst.PLUGIN_NAME_LABEL_NAME, plugin.getMetadata().getName());
|
||||||
|
extensionClient.create(unstructured);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package run.halo.app.plugin;
|
package run.halo.app.plugin;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.pf4j.PluginState;
|
import org.pf4j.PluginState;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
@ -55,6 +56,7 @@ public class PluginServiceImpl implements PluginService {
|
||||||
jsBundleRule.cssRule(pluginName));
|
jsBundleRule.cssRule(pluginName));
|
||||||
status.setEntry(jsBundleRoute);
|
status.setEntry(jsBundleRoute);
|
||||||
status.setStylesheet(cssBundleRoute);
|
status.setStylesheet(cssBundleRoute);
|
||||||
|
status.setLastStartTime(Instant.now());
|
||||||
extensionClient.update(plugin);
|
extensionClient.update(plugin);
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,86 +0,0 @@
|
||||||
package run.halo.app.plugin;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.jar.JarFile;
|
|
||||||
import java.util.zip.ZipEntry;
|
|
||||||
import org.pf4j.PluginRuntimeException;
|
|
||||||
import org.pf4j.PluginWrapper;
|
|
||||||
import org.springframework.core.io.DefaultResourceLoader;
|
|
||||||
import org.springframework.core.io.Resource;
|
|
||||||
import org.springframework.lang.NonNull;
|
|
||||||
import run.halo.app.extension.Unstructured;
|
|
||||||
import run.halo.app.infra.utils.YamlUnstructuredLoader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Plug in unstructured data loader.
|
|
||||||
* TODO Rename this class to an appropriate name.
|
|
||||||
*
|
|
||||||
* @author guqing
|
|
||||||
* @see YamlUnstructuredLoader
|
|
||||||
* @see PluginWrapper
|
|
||||||
* @see DefaultResourceLoader
|
|
||||||
* @since 2.0.0
|
|
||||||
*/
|
|
||||||
public class PluginUnstructuredResourceLoader {
|
|
||||||
private static final String DEFAULT_RESOURCE_LOCATION = "extensions/";
|
|
||||||
private final String resourceLocation;
|
|
||||||
|
|
||||||
public PluginUnstructuredResourceLoader() {
|
|
||||||
resourceLocation = DEFAULT_RESOURCE_LOCATION;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PluginUnstructuredResourceLoader(String resourceLocation) {
|
|
||||||
this.resourceLocation = resourceLocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loading unstructured yaml configuration files in plugins.
|
|
||||||
*
|
|
||||||
* @param pluginWrapper Wrapper object holding plugin data
|
|
||||||
* @return a collection of {@link Unstructured} data(never null)
|
|
||||||
*/
|
|
||||||
@NonNull
|
|
||||||
public List<Unstructured> loadUnstructured(PluginWrapper pluginWrapper) {
|
|
||||||
List<String> unstructuredFilePaths =
|
|
||||||
getUnstructuredFilePathFromJar(pluginWrapper.getPluginPath());
|
|
||||||
|
|
||||||
DefaultResourceLoader resourceLoader =
|
|
||||||
new DefaultResourceLoader(pluginWrapper.getPluginClassLoader());
|
|
||||||
Resource[] resources = unstructuredFilePaths.stream()
|
|
||||||
.map(resourceLoader::getResource)
|
|
||||||
.filter(Resource::exists)
|
|
||||||
.toArray(Resource[]::new);
|
|
||||||
|
|
||||||
YamlUnstructuredLoader yamlUnstructuredLoader = new YamlUnstructuredLoader(resources);
|
|
||||||
return yamlUnstructuredLoader.load();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Lists the path of the unstructured yaml configuration file from the plugin jar.</p>
|
|
||||||
*
|
|
||||||
* @param jarPath plugin jar path
|
|
||||||
* @return Unstructured file paths relative to plugin classpath
|
|
||||||
* @throws PluginRuntimeException If loading the file fails
|
|
||||||
*/
|
|
||||||
public List<String> getUnstructuredFilePathFromJar(Path jarPath) {
|
|
||||||
try (JarFile jarFile = new JarFile(jarPath.toFile())) {
|
|
||||||
return jarFile.stream()
|
|
||||||
.filter(jarEntry -> {
|
|
||||||
String name = jarEntry.getName();
|
|
||||||
return name.startsWith(resourceLocation)
|
|
||||||
&& !jarEntry.isDirectory()
|
|
||||||
&& isYamlFile(name);
|
|
||||||
})
|
|
||||||
.map(ZipEntry::getName)
|
|
||||||
.toList();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new PluginRuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isYamlFile(String path) {
|
|
||||||
return path.endsWith(".yaml") || path.endsWith(".yml");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,15 +4,23 @@ import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.pf4j.PluginRuntimeException;
|
import org.pf4j.PluginRuntimeException;
|
||||||
import org.pf4j.PluginState;
|
import org.pf4j.PluginState;
|
||||||
import org.pf4j.util.FileUtils;
|
import org.pf4j.util.FileUtils;
|
||||||
import org.springframework.core.io.FileSystemResource;
|
import org.springframework.core.io.FileSystemResource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
import run.halo.app.core.extension.Plugin;
|
import run.halo.app.core.extension.Plugin;
|
||||||
import run.halo.app.extension.Unstructured;
|
import run.halo.app.extension.Unstructured;
|
||||||
|
import run.halo.app.infra.utils.PathUtils;
|
||||||
import run.halo.app.infra.utils.YamlUnstructuredLoader;
|
import run.halo.app.infra.utils.YamlUnstructuredLoader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -48,7 +56,7 @@ import run.halo.app.infra.utils.YamlUnstructuredLoader;
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class YamlPluginFinder {
|
public class YamlPluginFinder {
|
||||||
public static final String DEFAULT_PROPERTIES_FILE_NAME = "plugin.yaml";
|
public static final String DEFAULT_PROPERTIES_FILE_NAME = "plugin.yaml";
|
||||||
|
private static final String DEFAULT_RESOURCE_LOCATION = "extensions/";
|
||||||
private final String propertiesFileName;
|
private final String propertiesFileName;
|
||||||
|
|
||||||
public YamlPluginFinder() {
|
public YamlPluginFinder() {
|
||||||
|
@ -66,6 +74,12 @@ public class YamlPluginFinder {
|
||||||
pluginStatus.setPhase(PluginState.RESOLVED);
|
pluginStatus.setPhase(PluginState.RESOLVED);
|
||||||
plugin.setStatus(pluginStatus);
|
plugin.setStatus(pluginStatus);
|
||||||
}
|
}
|
||||||
|
// read unstructured files
|
||||||
|
if (FileUtils.isJarFile(pluginPath)) {
|
||||||
|
plugin.getSpec().setExtensionLocations(getUnstructuredFilePathFromJar(pluginPath));
|
||||||
|
} else {
|
||||||
|
plugin.getSpec().setExtensionLocations(getUnstructuredFileFromClasspath(pluginPath));
|
||||||
|
}
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +112,17 @@ public class YamlPluginFinder {
|
||||||
|
|
||||||
protected Path getManifestPath(Path pluginPath, String propertiesFileName) {
|
protected Path getManifestPath(Path pluginPath, String propertiesFileName) {
|
||||||
if (Files.isDirectory(pluginPath)) {
|
if (Files.isDirectory(pluginPath)) {
|
||||||
return pluginPath.resolve(Paths.get(propertiesFileName));
|
for (String location : getSearchLocations()) {
|
||||||
|
String s = PathUtils.combinePath(pluginPath.toString(),
|
||||||
|
location, propertiesFileName);
|
||||||
|
Path path = Paths.get(s);
|
||||||
|
Resource propertyResource = new FileSystemResource(path);
|
||||||
|
if (propertyResource.exists()) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new PluginRuntimeException(
|
||||||
|
"Unable to find plugin descriptor file: " + DEFAULT_PROPERTIES_FILE_NAME);
|
||||||
} else {
|
} else {
|
||||||
// it's a jar file
|
// it's a jar file
|
||||||
try {
|
try {
|
||||||
|
@ -108,4 +132,66 @@ public class YamlPluginFinder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Lists the path of the unstructured yaml configuration file from the plugin jar.</p>
|
||||||
|
*
|
||||||
|
* @param jarPath plugin jar path
|
||||||
|
* @return Unstructured file paths relative to plugin classpath
|
||||||
|
* @throws PluginRuntimeException If loading the file fails
|
||||||
|
*/
|
||||||
|
protected List<String> getUnstructuredFilePathFromJar(Path jarPath) {
|
||||||
|
try (JarFile jarFile = new JarFile(jarPath.toFile())) {
|
||||||
|
return jarFile.stream()
|
||||||
|
.filter(jarEntry -> {
|
||||||
|
String name = jarEntry.getName();
|
||||||
|
return name.startsWith(DEFAULT_RESOURCE_LOCATION)
|
||||||
|
&& !jarEntry.isDirectory()
|
||||||
|
&& isYamlFile(name);
|
||||||
|
})
|
||||||
|
.map(ZipEntry::getName)
|
||||||
|
.toList();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new PluginRuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getUnstructuredFileFromClasspath(Path pluginPath) {
|
||||||
|
final Path unstructuredLocation = decisionUnstructuredLocation(pluginPath);
|
||||||
|
if (unstructuredLocation == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
try (Stream<Path> stream = Files.walk(unstructuredLocation)) {
|
||||||
|
return stream.map(Path::normalize)
|
||||||
|
.filter(Files::isRegularFile)
|
||||||
|
.filter(path -> isYamlFile(path.getFileName().toString()))
|
||||||
|
.map(path -> unstructuredLocation.getParent().relativize(path).toString())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
} catch (IOException e) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private Path decisionUnstructuredLocation(Path pluginPath) {
|
||||||
|
for (String searchLocation : getSearchLocations()) {
|
||||||
|
String unstructuredLocationString = PathUtils.combinePath(pluginPath.toString(),
|
||||||
|
searchLocation, DEFAULT_RESOURCE_LOCATION);
|
||||||
|
Path path = Paths.get(unstructuredLocationString);
|
||||||
|
boolean exists = Files.exists(path);
|
||||||
|
if (exists) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isYamlFile(String path) {
|
||||||
|
return path.endsWith(".yaml") || path.endsWith(".yml");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> getSearchLocations() {
|
||||||
|
// TODO 优化路径获取
|
||||||
|
return Set.of("build/resources/main/", "target/classes/");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import run.halo.app.core.extension.ReverseProxy.ReverseProxyRule;
|
||||||
import run.halo.app.extension.ExtensionClient;
|
import run.halo.app.extension.ExtensionClient;
|
||||||
import run.halo.app.infra.utils.PathUtils;
|
import run.halo.app.infra.utils.PathUtils;
|
||||||
import run.halo.app.plugin.PluginApplicationContext;
|
import run.halo.app.plugin.PluginApplicationContext;
|
||||||
|
import run.halo.app.plugin.PluginConst;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Plugin's reverse proxy router factory.</p>
|
* <p>Plugin's reverse proxy router factory.</p>
|
||||||
|
@ -39,8 +40,6 @@ import run.halo.app.plugin.PluginApplicationContext;
|
||||||
public class ReverseProxyRouterFunctionFactory {
|
public class ReverseProxyRouterFunctionFactory {
|
||||||
private static final String REVERSE_PROXY_API_PREFIX = "/assets";
|
private static final String REVERSE_PROXY_API_PREFIX = "/assets";
|
||||||
|
|
||||||
public static final String REVERSE_PROXY_PLUGIN_LABEL_NAME = "plugin.halo.run/plugin-name";
|
|
||||||
|
|
||||||
private final ExtensionClient extensionClient;
|
private final ExtensionClient extensionClient;
|
||||||
|
|
||||||
private final JsBundleRuleProvider jsBundleRuleProvider;
|
private final JsBundleRuleProvider jsBundleRuleProvider;
|
||||||
|
@ -99,7 +98,7 @@ public class ReverseProxyRouterFunctionFactory {
|
||||||
reverseProxy -> {
|
reverseProxy -> {
|
||||||
String pluginName = reverseProxy.getMetadata()
|
String pluginName = reverseProxy.getMetadata()
|
||||||
.getLabels()
|
.getLabels()
|
||||||
.get(REVERSE_PROXY_PLUGIN_LABEL_NAME);
|
.get(PluginConst.PLUGIN_NAME_LABEL_NAME);
|
||||||
return pluginId.equals(pluginName);
|
return pluginId.equals(pluginName);
|
||||||
},
|
},
|
||||||
null)
|
null)
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
package run.halo.app.plugin;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.util.List;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.util.ResourceUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for {@link PluginUnstructuredResourceLoader}.
|
|
||||||
*
|
|
||||||
* @author guqing
|
|
||||||
* @since 2.0.0
|
|
||||||
*/
|
|
||||||
class PluginUnstructuredResourceLoaderTest {
|
|
||||||
|
|
||||||
private PluginUnstructuredResourceLoader unstructuredResourceLoader;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void setUp() {
|
|
||||||
unstructuredResourceLoader = new PluginUnstructuredResourceLoader();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void getUnstructuredFilePathFromJar() throws FileNotFoundException {
|
|
||||||
File file = ResourceUtils.getFile("classpath:plugin/test-unstructured-resource-loader.jar");
|
|
||||||
List<String> unstructuredFilePathFromJar =
|
|
||||||
unstructuredResourceLoader.getUnstructuredFilePathFromJar(file.toPath());
|
|
||||||
assertThat(unstructuredFilePathFromJar).hasSize(3);
|
|
||||||
assertThat(unstructuredFilePathFromJar).contains("extensions/roles.yaml",
|
|
||||||
"extensions/reverseProxy.yaml", "extensions/test.yml");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -25,13 +25,13 @@ import run.halo.app.infra.utils.JsonUtils;
|
||||||
class YamlPluginDescriptorFinderTest {
|
class YamlPluginDescriptorFinderTest {
|
||||||
|
|
||||||
private YamlPluginDescriptorFinder yamlPluginDescriptorFinder;
|
private YamlPluginDescriptorFinder yamlPluginDescriptorFinder;
|
||||||
private Path testPath;
|
|
||||||
|
private File testFile;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() throws FileNotFoundException {
|
void setUp() throws FileNotFoundException {
|
||||||
yamlPluginDescriptorFinder = new YamlPluginDescriptorFinder();
|
yamlPluginDescriptorFinder = new YamlPluginDescriptorFinder();
|
||||||
File file = ResourceUtils.getFile("classpath:plugin/plugin.yaml");
|
testFile = ResourceUtils.getFile("classpath:plugin/test-unstructured-resource-loader.jar");
|
||||||
testPath = file.toPath().getParent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -61,23 +61,17 @@ class YamlPluginDescriptorFinderTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void find() throws JsonProcessingException, JSONException {
|
void find() throws JsonProcessingException, JSONException {
|
||||||
PluginDescriptor pluginDescriptor = yamlPluginDescriptorFinder.find(testPath);
|
PluginDescriptor pluginDescriptor = yamlPluginDescriptorFinder.find(testFile.toPath());
|
||||||
String actual = JsonUtils.objectToJson(pluginDescriptor);
|
String actual = JsonUtils.objectToJson(pluginDescriptor);
|
||||||
JSONAssert.assertEquals("""
|
JSONAssert.assertEquals("""
|
||||||
{
|
{
|
||||||
"pluginId": "plugin-1",
|
"pluginId": "io.github.guqing.apples",
|
||||||
"pluginDescription": "Tell me more about this plugin.",
|
"pluginDescription": "这是一个用来测试的插件",
|
||||||
"pluginClass": "run.halo.app.plugin.BasePlugin",
|
"pluginClass": "run.halo.app.plugin.BasePlugin",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"requires": ">=2.0.0",
|
"requires": "*",
|
||||||
"provider": "guqing",
|
"provider": "guqing",
|
||||||
"dependencies": [
|
"dependencies": [],
|
||||||
{
|
|
||||||
"pluginId": "banana",
|
|
||||||
"pluginVersionSupport": "0.0.1",
|
|
||||||
"optional": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
}
|
}
|
||||||
""",
|
""",
|
||||||
|
|
|
@ -6,15 +6,20 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
import java.util.List;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.pf4j.PluginRuntimeException;
|
import org.pf4j.PluginRuntimeException;
|
||||||
import org.skyscreamer.jsonassert.JSONAssert;
|
import org.skyscreamer.jsonassert.JSONAssert;
|
||||||
|
import org.springframework.core.io.FileSystemResource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.security.util.InMemoryResource;
|
import org.springframework.security.util.InMemoryResource;
|
||||||
|
import org.springframework.util.FileCopyUtils;
|
||||||
import org.springframework.util.ResourceUtils;
|
import org.springframework.util.ResourceUtils;
|
||||||
import run.halo.app.core.extension.Plugin;
|
import run.halo.app.core.extension.Plugin;
|
||||||
import run.halo.app.extension.Unstructured;
|
import run.halo.app.extension.Unstructured;
|
||||||
|
@ -28,18 +33,45 @@ import run.halo.app.infra.utils.JsonUtils;
|
||||||
*/
|
*/
|
||||||
class YamlPluginFinderTest {
|
class YamlPluginFinderTest {
|
||||||
private YamlPluginFinder pluginFinder;
|
private YamlPluginFinder pluginFinder;
|
||||||
private Path testPath;
|
|
||||||
|
private File testFile;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() throws FileNotFoundException {
|
void setUp() throws FileNotFoundException {
|
||||||
pluginFinder = new YamlPluginFinder();
|
pluginFinder = new YamlPluginFinder();
|
||||||
File file = ResourceUtils.getFile("classpath:plugin/plugin.yaml");
|
testFile = ResourceUtils.getFile("classpath:plugin/plugin.yaml");
|
||||||
testPath = file.toPath().getParent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void findTest() throws JsonProcessingException, JSONException {
|
void find() throws IOException, JSONException {
|
||||||
Plugin plugin = pluginFinder.find(testPath);
|
Path tempDirectory = Files.createTempDirectory("halo-test-plugin");
|
||||||
|
|
||||||
|
Path directories = Files.createDirectories(tempDirectory.resolve("build/resources/main"));
|
||||||
|
FileCopyUtils.copy(testFile, directories.resolve("plugin.yaml").toFile());
|
||||||
|
Path extensions = Files.createDirectory(directories.resolve("extensions"));
|
||||||
|
Files.createFile(extensions.resolve("roles.yaml"));
|
||||||
|
|
||||||
|
Plugin plugin = pluginFinder.find(tempDirectory);
|
||||||
|
assertThat(plugin).isNotNull();
|
||||||
|
JSONAssert.assertEquals("""
|
||||||
|
{
|
||||||
|
"phase": "RESOLVED",
|
||||||
|
"reason": null,
|
||||||
|
"message": null,
|
||||||
|
"lastStartTime": null,
|
||||||
|
"lastTransitionTime": null,
|
||||||
|
"entry": null,
|
||||||
|
"stylesheet": null
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
JsonUtils.objectToJson(plugin.getStatus()),
|
||||||
|
true);
|
||||||
|
assertThat(plugin.getSpec().getExtensionLocations()).contains("extensions/roles.yaml");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void unstructuredToPluginTest() throws JsonProcessingException, JSONException {
|
||||||
|
Plugin plugin = pluginFinder.unstructuredToPlugin(new FileSystemResource(testFile));
|
||||||
assertThat(plugin).isNotNull();
|
assertThat(plugin).isNotNull();
|
||||||
JSONAssert.assertEquals("""
|
JSONAssert.assertEquals("""
|
||||||
{
|
{
|
||||||
|
@ -61,17 +93,10 @@ class YamlPluginFinderTest {
|
||||||
],
|
],
|
||||||
"requires": ">=2.0.0",
|
"requires": ">=2.0.0",
|
||||||
"pluginClass": "run.halo.app.plugin.BasePlugin",
|
"pluginClass": "run.halo.app.plugin.BasePlugin",
|
||||||
"enabled": false
|
"enabled": false,
|
||||||
},
|
"extensionLocations": null
|
||||||
"status": {
|
|
||||||
"phase": "RESOLVED",
|
|
||||||
"reason": null,
|
|
||||||
"message": null,
|
|
||||||
"lastStartTime": null,
|
|
||||||
"lastTransitionTime": null,
|
|
||||||
"entry": null,
|
|
||||||
"stylesheet": null
|
|
||||||
},
|
},
|
||||||
|
"status": null,
|
||||||
"apiVersion": "plugin.halo.run/v1alpha1",
|
"apiVersion": "plugin.halo.run/v1alpha1",
|
||||||
"kind": "Plugin",
|
"kind": "Plugin",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
|
@ -94,7 +119,7 @@ class YamlPluginFinderTest {
|
||||||
assertThatThrownBy(() -> {
|
assertThatThrownBy(() -> {
|
||||||
pluginFinder.find(test);
|
pluginFinder.find(test);
|
||||||
}).isInstanceOf(PluginRuntimeException.class)
|
}).isInstanceOf(PluginRuntimeException.class)
|
||||||
.hasMessage("Cannot find '/tmp/plugin.yaml' path");
|
.hasMessage("Unable to find plugin descriptor file: plugin.yaml");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -186,4 +211,14 @@ class YamlPluginFinderTest {
|
||||||
assertThat(plugin.getSpec()).isNotNull();
|
assertThat(plugin.getSpec()).isNotNull();
|
||||||
JSONAssert.assertEquals(pluginJson, JsonUtils.objectToJson(plugin), false);
|
JSONAssert.assertEquals(pluginJson, JsonUtils.objectToJson(plugin), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getUnstructuredFilePathFromJar() throws FileNotFoundException {
|
||||||
|
File file = ResourceUtils.getFile("classpath:plugin/test-unstructured-resource-loader.jar");
|
||||||
|
List<String> unstructuredFilePathFromJar =
|
||||||
|
pluginFinder.getUnstructuredFilePathFromJar(file.toPath());
|
||||||
|
assertThat(unstructuredFilePathFromJar).hasSize(3);
|
||||||
|
assertThat(unstructuredFilePathFromJar).contains("extensions/roles.yaml",
|
||||||
|
"extensions/reverseProxy.yaml", "extensions/test.yml");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import run.halo.app.core.extension.ReverseProxy;
|
||||||
import run.halo.app.extension.ExtensionClient;
|
import run.halo.app.extension.ExtensionClient;
|
||||||
import run.halo.app.extension.Metadata;
|
import run.halo.app.extension.Metadata;
|
||||||
import run.halo.app.plugin.PluginApplicationContext;
|
import run.halo.app.plugin.PluginApplicationContext;
|
||||||
|
import run.halo.app.plugin.PluginConst;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link ReverseProxyRouterFunctionFactory}.
|
* Tests for {@link ReverseProxyRouterFunctionFactory}.
|
||||||
|
@ -64,7 +65,7 @@ class ReverseProxyRouterFunctionFactoryTest {
|
||||||
ReverseProxy reverseProxy = new ReverseProxy();
|
ReverseProxy reverseProxy = new ReverseProxy();
|
||||||
Metadata metadata = new Metadata();
|
Metadata metadata = new Metadata();
|
||||||
metadata.setLabels(
|
metadata.setLabels(
|
||||||
Map.of(ReverseProxyRouterFunctionFactory.REVERSE_PROXY_PLUGIN_LABEL_NAME, "fakeA"));
|
Map.of(PluginConst.PLUGIN_NAME_LABEL_NAME, "fakeA"));
|
||||||
reverseProxy.setMetadata(metadata);
|
reverseProxy.setMetadata(metadata);
|
||||||
reverseProxy.setRules(List.of(reverseProxyRule));
|
reverseProxy.setRules(List.of(reverseProxyRule));
|
||||||
return reverseProxy;
|
return reverseProxy;
|
||||||
|
|
Loading…
Reference in New Issue