Skip to content

Commit

Permalink
Add GitHubUpdater for GitHub updates
Browse files Browse the repository at this point in the history
  • Loading branch information
RednedEpic committed Jul 3, 2019
1 parent 3159f8e commit 0114c93
Show file tree
Hide file tree
Showing 7 changed files with 619 additions and 18 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>mc.alk</groupId>
<artifactId>BattlePluginUpdater</artifactId>
<version>2.1.1</version>
<version>2.2.0</version>
<packaging>jar</packaging>
<name>BattlePluginUpdater</name>
<url>https://github.com/BattlePlugins/PluginUpdater</url>
Expand Down
277 changes: 277 additions & 0 deletions src/main/java/mc/alk/battlepluginupdater/GitHubUpdater.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
package mc.alk.battlepluginupdater;

import mc.alk.battlepluginupdater.checker.GitHubUpdateChecker;

import org.bukkit.ChatColor;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
* Checks for plugin updates through GitHub and the
* {@link GitHubUpdateChecker} class.
*
*/
public class GitHubUpdater {

private Plugin plugin;
private String owner;
private String repo;

private String updateFolder;

/**
* Constructs a new GitHubUpdater instance
* <p>
* NOTE: The name of the repo must be the same name as the
* jar for this to properly work.
*
* @param plugin the plugin you want to update
* @param owner the owner of the repository
* @param repo the name of the repository
*/
public GitHubUpdater(Plugin plugin, String owner, String repo) {
this.plugin = plugin;
this.owner = owner;
this.repo = repo;

this.updateFolder = plugin.getServer().getUpdateFolder();
}

/**
* Updates the plugin from the latest GitHub release. Backwards compatible
* with Gravity's plugin updater config file.
*/
public void update() {
File pluginFile = plugin.getDataFolder().getParentFile();
File updaterFile = new File(pluginFile, "Updater");
File updaterConfigFile = new File(updaterFile, "config.yml");

YamlConfiguration config = new YamlConfiguration(); // Config file
config.options().header("This configuration file affects all plugins using the Updater system (version 2+ - http://forums.bukkit.org/threads/96681/ )" + '\n'
+ "If you wish to use your API key, read http://wiki.bukkit.org/ServerMods_API and place it below." + '\n'
+ "Some updating systems will not adhere to the disabled value, but these may be turned off in their plugin's configuration.");
config.addDefault("api-key", "PUT_API_KEY_HERE");
config.addDefault("disable", false);

if (!updaterFile.exists()) {
updaterFile.mkdir();
}

boolean createFile = !updaterConfigFile.exists();
try {
if (createFile) {
updaterConfigFile.createNewFile();
config.options().copyDefaults(true);
config.save(updaterConfigFile);
} else {
config.load(updaterConfigFile);
}
} catch (final Exception e) {
if (createFile) {
plugin.getLogger().severe("The updater could not create configuration at " + updaterFile.getAbsolutePath());
} else {
plugin.getLogger().severe("The updater could not load configuration at " + updaterFile.getAbsolutePath());
}
plugin.getLogger().log(Level.SEVERE, null, e);
}

boolean disabled = false;
if (config.contains("disable"))
disabled = config.getBoolean("disable", false);

if (disabled) {
plugin.getLogger().warning("You have opted-out of auto updating, so you won't know for certain if you're running the latest version.");
return;
}

GitHubUpdateChecker.init(plugin, owner, repo).requestUpdateCheck().whenComplete((result, exception) -> {
plugin.getLogger().info(ChatColor.GOLD + "Running " + plugin.getDescription().getName() + " v" + plugin.getDescription().getVersion() + ".");
switch (result.getReason()) {
case NEW_PRELEASE:
plugin.getLogger().info(ChatColor.DARK_GREEN + "You are currently running the latest release build. A prerelease is available for download.");
break;
case UP_TO_DATE:
plugin.getLogger().info(ChatColor.GREEN + "You are currently running the latest version.");
break;
case UNRELEASED_VERSION:
plugin.getLogger().info(ChatColor.DARK_GREEN + "You are currently running a version slightly ahead from release (development build?)");
break;
case INVALID_JSON:
case UNKNOWN_ERROR:
case COULD_NOT_CONNECT:
case UNAUTHORIZED_QUERY:
plugin.getLogger().warning("An error occurred when trying to update the plugin. If this persists, please contact the BattlePlugins team!");
break;
case UNSUPPORTED_VERSION_SCHEME:
plugin.getLogger().warning("An error occurred with the plugin version scheme, please contact the BatlePlugins team!");
case NEW_UPDATE:
plugin.getLogger().info(ChatColor.AQUA + "A new update was found: " + plugin.getDescription().getName() + " " + result.getNewestVersion());

String downloadLink = "https://github.com/" + owner + "/" + repo + "/releases/download/" + result.getNewestVersion() + "/" + repo + ".jar";
File folder = new File(plugin.getDataFolder().getParent(), updateFolder);
downloadFile(folder, plugin.getDescription().getName() + ".jar", result.getNewestVersion(), downloadLink);
}
});
}

/**
* Downloads a file from the specified URL into the server's update folder.
*
* @param folder the updates folder location.
* @param file the name of the file to save it as.
* @param link the url of the file.
* @param version the version of the plugin.
*/
private void downloadFile(File folder, String file, String version, String link) {
if (!folder.exists()) {
folder.mkdir();
}
BufferedInputStream in = null;
FileOutputStream fout = null;
try {
// Download the file
final URL url = new URL(link);
final int fileLength = url.openConnection().getContentLength();
in = new BufferedInputStream(url.openStream());
fout = new FileOutputStream(folder.getAbsolutePath() + File.separator + file);

final byte[] data = new byte[1024];
int count;
this.plugin.getLogger().info("About to download a new update: " + version);
long downloaded = 0;
while ((count = in.read(data, 0, 1024)) != -1) {
downloaded += count;
fout.write(data, 0, count);
}
//Just a quick check to make sure we didn't leave any files from last time...
for (final File xFile : new File(this.plugin.getDataFolder().getParent(), this.updateFolder).listFiles()) {
if (xFile.getName().endsWith(".zip")) {
xFile.delete();
}
}
// Check to see if it's a zip file, if it is, unzip it.
final File dFile = new File(folder.getAbsolutePath() + File.separator + file);
if (dFile.getName().endsWith(".zip")) {
// Unzip
this.unzip(dFile.getCanonicalPath());
}
this.plugin.getLogger().info("Finished updating.");
} catch (final Exception ex) {
this.plugin.getLogger().warning("The auto-updater tried to download a new update, but was unsuccessful.");
} finally {
try {
if (in != null) {
in.close();
}
if (fout != null) {
fout.close();
}
} catch (final Exception ex) {
}
}
}

/**
* Part of Zip-File-Extractor, modified by Gravity for use with Updater.
*
* @param file the location of the file to extract.
*/
private void unzip(String file) {
try {
final File fSourceZip = new File(file);
final String zipPath = file.substring(0, file.length() - 4);
ZipFile zipFile = new ZipFile(fSourceZip);
Enumeration<? extends ZipEntry> e = zipFile.entries();
while (e.hasMoreElements()) {
ZipEntry entry = e.nextElement();
File destinationFilePath = new File(zipPath, entry.getName());
destinationFilePath.getParentFile().mkdirs();
if (entry.isDirectory()) {
continue;
} else {
final BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(entry));
int b;
final byte buffer[] = new byte[1024];
final FileOutputStream fos = new FileOutputStream(destinationFilePath);
final BufferedOutputStream bos = new BufferedOutputStream(fos, 1024);
while ((b = bis.read(buffer, 0, 1024)) != -1) {
bos.write(buffer, 0, b);
}
bos.flush();
bos.close();
bis.close();
final String name = destinationFilePath.getName();
if (name.endsWith(".jar") && this.pluginFile(name)) {
destinationFilePath.renameTo(new File(this.plugin.getDataFolder().getParent(), this.updateFolder + File.separator + name));
}
}
entry = null;
destinationFilePath = null;
}
e = null;
zipFile.close();
zipFile = null;

// Move any plugin data folders that were included to the right place, Bukkit won't do this for us.
for (final File dFile : new File(zipPath).listFiles()) {
if (dFile.isDirectory()) {
if (this.pluginFile(dFile.getName())) {
final File oFile = new File(this.plugin.getDataFolder().getParent(), dFile.getName()); // Get current dir
final File[] contents = oFile.listFiles(); // List of existing files in the current dir
for (final File cFile : dFile.listFiles()) // Loop through all the files in the new dir
{
boolean found = false;
for (final File xFile : contents) // Loop through contents to see if it exists
{
if (xFile.getName().equals(cFile.getName())) {
found = true;
break;
}
}
if (!found) {
// Move the new file into the current dir
cFile.renameTo(new File(oFile.getCanonicalFile() + File.separator + cFile.getName()));
} else {
// This file already exists, so we don't need it anymore.
cFile.delete();
}
}
}
}
dFile.delete();
}
new File(zipPath).delete();
fSourceZip.delete();
} catch (final IOException e) {
this.plugin.getLogger().log(Level.SEVERE, "The auto-updater tried to unzip a new update file, but was unsuccessful.", e);
}
new File(file).delete();
}

/**
* Check if the name of a jar is one of the plugins currently installed,
* used for extracting the correct files out of a zip.
*
* @param name a name to check for inside the plugins folder.
* @return true if a file inside the plugins folder is named this.
*/
private boolean pluginFile(String name) {
for (final File file : new File("plugins").listFiles()) {
if (file.getName().equals(name)) {
return true;
}
}
return false;
}
}
4 changes: 1 addition & 3 deletions src/main/java/mc/alk/battlepluginupdater/PluginUpdater.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,19 @@

import java.io.File;
import java.util.HashSet;
import java.util.logging.Level;

import mc.euro.version.Version;
import mc.euro.version.VersionFactory;

import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.Plugin;

/**
* @deprecated this class is known for causing issues with plugin downloads.
* Instead, use {@link mc.alk.battlepluginupdater.SpigotUpdater}
* Instead, use {@link SpigotUpdater} or {@link GitHubUpdater}
*/
public class PluginUpdater {

Expand Down
6 changes: 3 additions & 3 deletions src/main/java/mc/alk/battlepluginupdater/SpigotUpdater.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package mc.alk.battlepluginupdater;

import mc.alk.battlepluginupdater.checker.UpdateChecker;
import mc.alk.battlepluginupdater.checker.SpigotUpdateChecker;

import org.bukkit.ChatColor;
import org.bukkit.configuration.file.YamlConfiguration;
Expand All @@ -19,7 +19,7 @@

/**
* Checks for plugin updates through spigot and the
* {@link mc.alk.battlepluginupdater.checker.UpdateChecker} class.
* {@link SpigotUpdateChecker} class.
*
*/
public class SpigotUpdater {
Expand Down Expand Up @@ -97,7 +97,7 @@ public void update() {
return;
}

UpdateChecker.init(plugin, pluginId).requestUpdateCheck().whenComplete((result, exception) -> {
SpigotUpdateChecker.init(plugin, pluginId).requestUpdateCheck().whenComplete((result, exception) -> {
plugin.getLogger().info(ChatColor.GOLD + "Running " + plugin.getDescription().getName() + " v" + plugin.getDescription().getVersion() + ".");
switch (result.getReason()) {
case UP_TO_DATE:
Expand Down
6 changes: 4 additions & 2 deletions src/main/java/mc/alk/battlepluginupdater/Updater.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package mc.alk.battlepluginupdater;

import mc.alk.battlepluginupdater.checker.UpdateChecker;
import mc.alk.battlepluginupdater.checker.SpigotUpdateChecker;
import mc.alk.battlepluginupdater.checker.GitHubUpdateChecker;

import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin;
import org.json.simple.JSONArray;
Expand Down Expand Up @@ -47,7 +49,7 @@
* @version 2.1
*
* @deprecated
* Instead, use {@link mc.alk.battlepluginupdater.checker.UpdateChecker}
* Instead, use {@link SpigotUpdateChecker} or {@link GitHubUpdateChecker}
*/
public class Updater {

Expand Down
Loading

0 comments on commit 0114c93

Please sign in to comment.