mirror of
https://github.com/BentoBoxWorld/BentoBox.git
synced 2024-11-24 11:45:31 +01:00
Fixes reload of locales from addons
This was a bigger job than expected. I moved the addon loading locale stuff into the LocalesManager class from the AddonsManager and put a jar file lister in Utils. There could be some more combining of plugin jar and addon jar file finding there. Finally, I added a sophisticated test that creates a temporary addon jar with a locale file and checks that it is saved correctly. Phew!
This commit is contained in:
parent
b82f59e948
commit
d7851b923e
@ -6,7 +6,6 @@ import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
@ -33,7 +32,6 @@ import world.bentobox.bentobox.api.events.addon.AddonEvent;
|
||||
*/
|
||||
public class AddonsManager {
|
||||
|
||||
private static final String LOCALE_FOLDER = "locales";
|
||||
private List<Addon> addons;
|
||||
private Map<Addon, AddonClassLoader> loaders;
|
||||
private final Map<String, Class<?>> classes = new HashMap<>();
|
||||
@ -125,26 +123,30 @@ public class AddonsManager {
|
||||
// try loading the addon
|
||||
// Get description in the addon.yml file
|
||||
YamlConfiguration data = addonDescription(jar);
|
||||
|
||||
// Load the addon
|
||||
AddonClassLoader addonClassLoader = new AddonClassLoader(this, data, f, this.getClass().getClassLoader());
|
||||
|
||||
// Get the addon itself
|
||||
addon = addonClassLoader.getAddon();
|
||||
|
||||
// Initialize some settings
|
||||
addon.setDataFolder(new File(f.getParent(), addon.getDescription().getName()));
|
||||
addon.setFile(f);
|
||||
|
||||
File localeDir = new File(plugin.getDataFolder(), LOCALE_FOLDER + File.separator + addon.getDescription().getName());
|
||||
// Obtain any locale files and save them
|
||||
for (String localeFile : listJarFiles(jar, LOCALE_FOLDER, ".yml")) {
|
||||
addon.saveResource(localeFile, localeDir, false, true);
|
||||
}
|
||||
// Locales
|
||||
plugin.getLocalesManager().copyLocalesFromAddonJar(addon);
|
||||
plugin.getLocalesManager().loadLocalesFromFile(addon.getDescription().getName());
|
||||
|
||||
// Fire the load event
|
||||
Bukkit.getPluginManager().callEvent(new AddonEvent().builder().addon(addon).reason(AddonEvent.Reason.LOAD).build());
|
||||
|
||||
// Add it to the list of addons
|
||||
addons.add(addon);
|
||||
|
||||
// Add to the list of loaders
|
||||
loaders.put(addon, addonClassLoader);
|
||||
|
||||
// Run the onLoad.
|
||||
addon.onLoad();
|
||||
} catch (Exception e) {
|
||||
@ -205,33 +207,6 @@ public class AddonsManager {
|
||||
classes.putIfAbsent(name, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists files found in the jar in the folderPath with the suffix given
|
||||
* @param jar - the jar file
|
||||
* @param folderPath - the path within the jar
|
||||
* @param suffix - the suffix required
|
||||
* @return a list of files
|
||||
*/
|
||||
public List<String> listJarFiles(JarFile jar, String folderPath, String suffix) {
|
||||
List<String> result = new ArrayList<>();
|
||||
|
||||
Enumeration<JarEntry> entries = jar.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
JarEntry entry = entries.nextElement();
|
||||
String path = entry.getName();
|
||||
|
||||
if (!path.startsWith(folderPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.getName().endsWith(suffix)) {
|
||||
result.add(entry.getName());
|
||||
}
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void sortAddons() {
|
||||
// Lists all available addons as names.
|
||||
List<String> names = addons.stream().map(a -> a.getDescription().getName()).collect(Collectors.toList());
|
||||
|
@ -11,13 +11,16 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.addons.Addon;
|
||||
import world.bentobox.bentobox.api.localization.BentoBoxLocale;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.util.FileLister;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
|
||||
/**
|
||||
* @author tastybento, Poslovitch
|
||||
@ -31,7 +34,7 @@ public class LocalesManager {
|
||||
|
||||
public LocalesManager(BentoBox plugin) {
|
||||
this.plugin = plugin;
|
||||
copyLocalesFromJar(BENTOBOX);
|
||||
copyLocalesFromPluginJar(BENTOBOX);
|
||||
loadLocalesFromFile(BENTOBOX); // Default
|
||||
}
|
||||
|
||||
@ -101,12 +104,29 @@ public class LocalesManager {
|
||||
return result == null ? defaultText : result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies locale files from the addon jar to the file system
|
||||
* @param addon - addon
|
||||
*/
|
||||
void copyLocalesFromAddonJar(Addon addon) {
|
||||
try (JarFile jar = new JarFile(addon.getFile())) {
|
||||
File localeDir = new File(plugin.getDataFolder(), LOCALE_FOLDER + File.separator + addon.getDescription().getName());
|
||||
if (!localeDir.exists()) {
|
||||
localeDir.mkdirs();
|
||||
// Obtain any locale files and save them
|
||||
Util.listJarFiles(jar, LOCALE_FOLDER, ".yml").forEach(lf -> addon.saveResource(lf, localeDir, false, true));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
plugin.logError(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies all the locale files from the plugin jar to the filesystem.
|
||||
* Only done if the locale folder does not already exist.
|
||||
* @param folderName - the name of the destination folder
|
||||
*/
|
||||
private void copyLocalesFromJar(String folderName) {
|
||||
private void copyLocalesFromPluginJar(String folderName) {
|
||||
// Run through the files and store the locales
|
||||
File localeDir = new File(plugin.getDataFolder(), LOCALE_FOLDER + File.separator + folderName);
|
||||
// If the folder does not exist, then make it and fill with the locale files from the jar
|
||||
@ -210,9 +230,12 @@ public class LocalesManager {
|
||||
*/
|
||||
public void reloadLanguages() {
|
||||
languages.clear();
|
||||
copyLocalesFromJar(BENTOBOX);
|
||||
copyLocalesFromPluginJar(BENTOBOX);
|
||||
loadLocalesFromFile(BENTOBOX);
|
||||
plugin.getAddonsManager().getAddons().forEach(addon -> loadLocalesFromFile(addon.getDescription().getName()));
|
||||
plugin.getAddonsManager().getAddons().forEach(addon -> {
|
||||
copyLocalesFromAddonJar(addon);
|
||||
loadLocalesFromFile(addon.getDescription().getName());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
@ -16,6 +16,7 @@ import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.api.addons.Addon;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.schems.Clipboard;
|
||||
import world.bentobox.bentobox.util.Util;
|
||||
|
||||
public class SchemsManager {
|
||||
|
||||
@ -42,9 +43,7 @@ public class SchemsManager {
|
||||
}
|
||||
// Save any schems that
|
||||
try (JarFile jar = new JarFile(addon.getFile())) {
|
||||
plugin.getAddonsManager().listJarFiles(jar, "schems", ".schem").forEach(name -> {
|
||||
addon.saveResource(name, false);
|
||||
});
|
||||
Util.listJarFiles(jar, "schems", ".schem").forEach(name -> addon.saveResource(name, false));
|
||||
} catch (IOException e) {
|
||||
plugin.logError("Could not load schem files from addon jar " + e.getMessage());
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
package world.bentobox.bentobox.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
@ -195,6 +198,33 @@ public class Util {
|
||||
return world.getEnvironment().equals(Environment.NORMAL) ? world : Bukkit.getWorld(world.getName().replaceAll(NETHER, "").replaceAll(THE_END, ""));
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists files found in the jar in the folderPath with the suffix given
|
||||
* @param jar - the jar file
|
||||
* @param folderPath - the path within the jar
|
||||
* @param suffix - the suffix required
|
||||
* @return a list of files
|
||||
*/
|
||||
public static List<String> listJarFiles(JarFile jar, String folderPath, String suffix) {
|
||||
List<String> result = new ArrayList<>();
|
||||
|
||||
Enumeration<JarEntry> entries = jar.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
JarEntry entry = entries.nextElement();
|
||||
String path = entry.getName();
|
||||
|
||||
if (!path.startsWith(folderPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.getName().endsWith(suffix)) {
|
||||
result.add(entry.getName());
|
||||
}
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts block face direction to radial degrees. Returns 0 if block face
|
||||
* is not radial.
|
||||
|
@ -9,13 +9,20 @@ import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
@ -79,7 +86,7 @@ public class LocalesManagerTest {
|
||||
*/
|
||||
@After
|
||||
public void cleanUp() throws Exception {
|
||||
|
||||
// Delete locale folder
|
||||
File localeDir = new File(plugin.getDataFolder(), LOCALE_FOLDER);
|
||||
if (localeDir.exists()) {
|
||||
// Remove it
|
||||
@ -90,6 +97,16 @@ public class LocalesManagerTest {
|
||||
|
||||
}
|
||||
|
||||
// Delete addon folder
|
||||
localeDir = new File(plugin.getDataFolder(), "addons");
|
||||
if (localeDir.exists()) {
|
||||
// Remove it
|
||||
Files.walk(localeDir.toPath())
|
||||
.map(Path::toFile)
|
||||
.sorted((o1, o2) -> -o1.compareTo(o2))
|
||||
.forEach(File::delete);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -283,17 +300,98 @@ public class LocalesManagerTest {
|
||||
List<Addon> none = new ArrayList<>();
|
||||
Addon addon = mock(Addon.class);
|
||||
AddonDescription desc = new AddonDescription();
|
||||
desc.setName(BENTOBOX);
|
||||
desc.setName("AcidIsland");
|
||||
when(addon.getDescription()).thenReturn(desc);
|
||||
// Create a tmp folder to jar up
|
||||
File localeDir = new File(LOCALE_FOLDER);
|
||||
localeDir.mkdirs();
|
||||
// Create a fake locale file for this jar
|
||||
File english = new File(localeDir, Locale.US.toLanguageTag() + ".yml");
|
||||
YamlConfiguration yaml = new YamlConfiguration();
|
||||
yaml.set("test.test", "test string");
|
||||
yaml.save(english);
|
||||
// Create a temporary jar file
|
||||
File jar = new File("addons", "AcidIsland.jar");
|
||||
jar.getParentFile().mkdirs();
|
||||
Manifest manifest = new Manifest();
|
||||
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
|
||||
JarOutputStream target = new JarOutputStream(new FileOutputStream("addons" + File.separator + "AcidIsland.jar"), manifest);
|
||||
add(english, target);
|
||||
target.close();
|
||||
// When the file is requested, return it
|
||||
when(addon.getFile()).thenReturn(jar);
|
||||
none.add(addon);
|
||||
when(am.getAddons()).thenReturn(none);
|
||||
when(plugin.getAddonsManager()).thenReturn(am);
|
||||
makeFakeLocaleFile();
|
||||
LocalesManager lm = new LocalesManager(plugin);
|
||||
|
||||
// RELOAD!!!
|
||||
lm.reloadLanguages();
|
||||
Mockito.verify(addon).getDescription();
|
||||
File localeDir = new File(plugin.getDataFolder(), LOCALE_FOLDER + File.separator + BENTOBOX);
|
||||
assertTrue(localeDir.exists());
|
||||
|
||||
// Verify that the resources have been saved (note that they are not actually saved because addon is a mock)
|
||||
Mockito.verify(addon).saveResource(
|
||||
Mockito.eq("locales/en-US.yml"),
|
||||
Mockito.any(),
|
||||
Mockito.eq(false),
|
||||
Mockito.eq(true)
|
||||
);
|
||||
|
||||
// Clean up
|
||||
// Delete the temp folder we made. Other clean up is done globally
|
||||
localeDir = new File(plugin.getDataFolder(), "AcidIsland");
|
||||
if (localeDir.exists()) {
|
||||
// Remove it
|
||||
Files.walk(localeDir.toPath())
|
||||
.map(Path::toFile)
|
||||
.sorted((o1, o2) -> -o1.compareTo(o2))
|
||||
.forEach(File::delete);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void add(File source, JarOutputStream target) throws IOException
|
||||
{
|
||||
BufferedInputStream in = null;
|
||||
try
|
||||
{
|
||||
if (source.isDirectory())
|
||||
{
|
||||
String name = source.getPath().replace("\\", "/");
|
||||
if (!name.isEmpty())
|
||||
{
|
||||
if (!name.endsWith("/"))
|
||||
name += "/";
|
||||
JarEntry entry = new JarEntry(name);
|
||||
entry.setTime(source.lastModified());
|
||||
target.putNextEntry(entry);
|
||||
target.closeEntry();
|
||||
}
|
||||
for (File nestedFile: source.listFiles())
|
||||
add(nestedFile, target);
|
||||
return;
|
||||
}
|
||||
|
||||
JarEntry entry = new JarEntry(source.getPath().replace("\\", "/"));
|
||||
entry.setTime(source.lastModified());
|
||||
target.putNextEntry(entry);
|
||||
in = new BufferedInputStream(new FileInputStream(source));
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
while (true)
|
||||
{
|
||||
int count = in.read(buffer);
|
||||
if (count == -1)
|
||||
break;
|
||||
target.write(buffer, 0, count);
|
||||
}
|
||||
target.closeEntry();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (in != null)
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user