Archiviert
13
0

Fix a false positive with the updater

Dieser Commit ist enthalten in:
Dan Mulloy 2016-05-16 17:43:58 -04:00
Ursprung 4330bae47f
Commit 869b457810
2 geänderte Dateien mit 373 neuen und 363 gelöschten Zeilen

Datei anzeigen

@ -1,296 +1,306 @@
/** /**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2 * Copyright (C) 2015 dmulloy2
* *
* This program is free software; you can redistribute it and/or modify it under the terms of the * This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of * GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version. * the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License along with this program; * You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA * 02111-1307 USA
*/ */
package com.comphenix.protocol.updater; package com.comphenix.protocol.updater;
import java.io.File; import java.io.File;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.ProtocolLib; import com.comphenix.protocol.ProtocolLib;
import com.comphenix.protocol.error.ReportType; import com.comphenix.protocol.error.ReportType;
import com.comphenix.protocol.utility.MinecraftVersion; import com.comphenix.protocol.utility.MinecraftVersion;
import com.comphenix.protocol.utility.Util; import com.comphenix.protocol.utility.Util;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
/** /**
* @author dmulloy2 * @author dmulloy2
*/ */
public abstract class Updater { public abstract class Updater {
protected Plugin plugin; protected Plugin plugin;
protected String versionName; protected String versionName;
protected String versionLink; protected String versionLink;
protected String versionType; protected String versionType;
protected String versionGameVersion; protected String versionGameVersion;
protected String versionFileName; protected String versionFileName;
protected UpdateType type; protected UpdateType type;
protected boolean announce; protected boolean announce;
protected Thread thread; protected Thread thread;
protected UpdateResult result = UpdateResult.SUCCESS; protected UpdateResult result = UpdateResult.SUCCESS;
protected List<Runnable> listeners = new CopyOnWriteArrayList<Runnable>(); protected List<Runnable> listeners = new CopyOnWriteArrayList<Runnable>();
public static final ReportType REPORT_CANNOT_UPDATE_PLUGIN = new ReportType("Cannot update ProtocolLib."); public static final ReportType REPORT_CANNOT_UPDATE_PLUGIN = new ReportType("Cannot update ProtocolLib.");
protected Updater(Plugin plugin, UpdateType type, boolean announce) { protected Updater(Plugin plugin, UpdateType type, boolean announce) {
this.plugin = plugin; this.plugin = plugin;
this.type = type; this.type = type;
this.announce = announce; this.announce = announce;
} }
public boolean versionCheck(String title) { public boolean versionCheck(String title) {
if (this.type != UpdateType.NO_VERSION_CHECK) { if (this.type != UpdateType.NO_VERSION_CHECK) {
String version = this.plugin.getDescription().getVersion(); String version = this.plugin.getDescription().getVersion();
boolean devBuild = false; // Extract the version from the response
if (version.contains("-SNAPSHOT") || version.contains("-BETA")) { String[] split = title.split(" ");
devBuild = true; String remote = "Unknown";
version = version.substring(0, version.indexOf("-"));
} if (split.length == 2) { // BukkitDev
remote = split[1];
final String[] splitTitle = title.split(" "); } else if (this instanceof SpigotUpdater) { // Spigot resource
String remoteVersion; remote = split[0];
} else { // Misconfigured
if (splitTitle.length == 2) { // The file's name did not contain the string 'vVersion'
remoteVersion = splitTitle[1].split("-")[0]; String authorInfo = this.plugin.getDescription().getAuthors().size() == 0 ? "" : " (" + this.plugin.getDescription().getAuthors().get(0) + ")";
} else if (this instanceof SpigotUpdater) { plugin.getLogger().warning("The author of this plugin " + authorInfo + " has misconfigured their Auto Update system");
remoteVersion = splitTitle[0]; plugin.getLogger().warning("File versions should follow the format 'PluginName VERSION[-SNAPSHOT]'");
} else { plugin.getLogger().warning("Please notify the author of this error.");
// The file's name did not contain the string 'vVersion' this.result = BukkitUpdater.UpdateResult.FAIL_NOVERSION;
final String authorInfo = this.plugin.getDescription().getAuthors().size() == 0 ? "" : " (" + this.plugin.getDescription().getAuthors().get(0) + ")"; return false;
this.plugin.getLogger().warning("The author of this plugin " + authorInfo + " has misconfigured their Auto Update system"); }
this.plugin.getLogger().warning("File versions should follow the format 'PluginName VERSION[-SNAPSHOT]'");
this.plugin.getLogger().warning("Please notify the author of this error."); // Check if the local version is a dev build
this.result = BukkitUpdater.UpdateResult.FAIL_NOVERSION;
return false; boolean devBuild = false;
} if (version.contains("-SNAPSHOT") || version.contains("-BETA")) {
devBuild = true;
// Parse the version version = version.substring(0, version.indexOf("-"));
if (remoteVersion.startsWith("v")) { }
remoteVersion = remoteVersion.substring(1);
} // Remove the v
if (remote.startsWith("v")) {
MinecraftVersion parsedRemote = new MinecraftVersion(remoteVersion); remote = remote.substring(1);
MinecraftVersion parsedCurrent = new MinecraftVersion(plugin.getDescription().getVersion()); }
if (devBuild && parsedRemote.equals(parsedCurrent)) { // Remove the build number if it snuck in there
// They're using a dev build and this version has been released if (version.contains("-b")) {
return !remoteVersion.contains("-BETA") && !remoteVersion.contains("-SNAPSHOT"); version = version.substring(0, version.lastIndexOf("-"));
} }
// The remote version has to be greater // Parse it and our local version
if (parsedRemote.compareTo(parsedCurrent) <= 0) { MinecraftVersion parsedRemote = new MinecraftVersion(remote);
// We already have the latest version, or this build is tagged for no-update MinecraftVersion parsedCurrent = new MinecraftVersion(version);
this.result = BukkitUpdater.UpdateResult.NO_UPDATE;
return false; if (devBuild && parsedRemote.equals(parsedCurrent)) {
} // They're using a dev build and this version has been released
} return !remote.contains("-BETA") && !remote.contains("-SNAPSHOT");
return true; }
}
// The remote version has to be greater
/** if (parsedRemote.compareTo(parsedCurrent) <= 0) {
* Add a listener to be executed when we have determined if an update is available. // We already have the latest version, or this build is tagged for no-update
* <p> this.result = BukkitUpdater.UpdateResult.NO_UPDATE;
* The listener will be executed on the main thread. return false;
* @param listener - the listener to add. }
*/ }
public void addListener(Runnable listener) {
listeners.add(Preconditions.checkNotNull(listener, "listener cannot be NULL")); return true;
} }
/** /**
* Remove a listener. * Add a listener to be executed when we have determined if an update is available.
* @param listener - the listener to remove. * <p>
* @return TRUE if the listener was removed, FALSE otherwise. * The listener will be executed on the main thread.
*/ * @param listener - the listener to add.
public boolean removeListener(Runnable listener) { */
return listeners.remove(listener); public void addListener(Runnable listener) {
} listeners.add(Preconditions.checkNotNull(listener, "listener cannot be NULL"));
}
/**
* Get the result of the update process. /**
*/ * Remove a listener.
public String getResult() { * @param listener - the listener to remove.
this.waitForThread(); * @return TRUE if the listener was removed, FALSE otherwise.
return this.result.toString(); */
} public boolean removeListener(Runnable listener) {
return listeners.remove(listener);
/** }
* Get the latest version's release type (release, beta, or alpha).
*/ /**
public String getLatestType() { * Get the result of the update process.
this.waitForThread(); */
return this.versionType; public String getResult() {
} this.waitForThread();
return this.result.toString();
/** }
* Get the latest version's game version.
*/ /**
public String getLatestGameVersion() { * Get the latest version's release type (release, beta, or alpha).
this.waitForThread(); */
return this.versionGameVersion; public String getLatestType() {
} this.waitForThread();
return this.versionType;
/** }
* Get the latest version's name.
*/ /**
public String getLatestName() { * Get the latest version's game version.
this.waitForThread(); */
return this.versionName; public String getLatestGameVersion() {
} this.waitForThread();
return this.versionGameVersion;
/** }
* Get the latest version's file link.
*/ /**
public String getLatestFileLink() { * Get the latest version's name.
this.waitForThread(); */
return this.versionLink; public String getLatestName() {
} this.waitForThread();
return this.versionName;
/** }
* As the result of Updater output depends on the thread's completion, it is necessary to wait for the thread to finish
* before allowing anyone to check the result. /**
*/ * Get the latest version's file link.
protected void waitForThread() { */
if (thread != null && thread.isAlive()) { public String getLatestFileLink() {
try { this.waitForThread();
thread.join(); return this.versionLink;
} catch (InterruptedException ex) { }
ex.printStackTrace();
} /**
} * As the result of Updater output depends on the thread's completion, it is necessary to wait for the thread to finish
} * before allowing anyone to check the result.
*/
/** protected void waitForThread() {
* Determine if we are already checking for an update. if (thread != null && thread.isAlive()) {
* @return TRUE if we are, FALSE otherwise. try {
*/ thread.join();
public boolean isChecking() { } catch (InterruptedException ex) {
return this.thread != null && this.thread.isAlive(); ex.printStackTrace();
} }
}
/** }
* Allows the dev to specify the type of update that will be run.
*/ /**
public enum UpdateType { * Determine if we are already checking for an update.
/** * @return TRUE if we are, FALSE otherwise.
* Run a version check, and then if the file is out of date, download the newest version. */
*/ public boolean isChecking() {
DEFAULT, return this.thread != null && this.thread.isAlive();
/** }
* Don't run a version check, just find the latest update and download it.
*/ /**
NO_VERSION_CHECK, * Allows the dev to specify the type of update that will be run.
/** */
* Get information about the version and the download size, but don't actually download anything. public enum UpdateType {
*/ /**
NO_DOWNLOAD * Run a version check, and then if the file is out of date, download the newest version.
} */
DEFAULT,
/** /**
* Gives the dev the result of the update process. Can be obtained by called getResult(). * Don't run a version check, just find the latest update and download it.
*/ */
public enum UpdateResult { NO_VERSION_CHECK,
/** /**
* The updater found an update, and has readied it to be loaded the next time the server restarts/reloads. * Get information about the version and the download size, but don't actually download anything.
*/ */
SUCCESS("The updater found an update, and has readied it to be loaded the next time the server restarts/reloads."), NO_DOWNLOAD
}
/**
* The updater did not find an update, and nothing was downloaded. /**
*/ * Gives the dev the result of the update process. Can be obtained by called getResult().
NO_UPDATE("The updater did not find an update, and nothing was downloaded."), */
public enum UpdateResult {
/** /**
* The server administrator has disabled the updating system * The updater found an update, and has readied it to be loaded the next time the server restarts/reloads.
*/ */
DISABLED("The server administrator has disabled the updating system"), SUCCESS("The updater found an update, and has readied it to be loaded the next time the server restarts/reloads."),
/** /**
* The updater found an update, but was unable to download it. * The updater did not find an update, and nothing was downloaded.
*/ */
FAIL_DOWNLOAD("The updater found an update, but was unable to download it."), NO_UPDATE("The updater did not find an update, and nothing was downloaded."),
/** /**
* For some reason, the updater was unable to contact dev.bukkit.org to download the file. * The server administrator has disabled the updating system
*/ */
FAIL_DBO("For some reason, the updater was unable to contact dev.bukkit.org to download the file.") DISABLED("The server administrator has disabled the updating system"),
,
/** /**
* When running the version check, the file on DBO did not contain the a version in the format 'vVersion' such as 'v1.0'. * The updater found an update, but was unable to download it.
*/ */
FAIL_NOVERSION("When running the version check, the file on DBO did not contain the a version in the format 'vVersion' such as 'v1.0'."), FAIL_DOWNLOAD("The updater found an update, but was unable to download it."),
/** /**
* The id provided by the plugin running the updater was invalid and doesn't exist on DBO. * For some reason, the updater was unable to contact dev.bukkit.org to download the file.
*/ */
FAIL_BADID("The id provided by the plugin running the updater was invalid and doesn't exist on DBO."), FAIL_DBO("For some reason, the updater was unable to contact dev.bukkit.org to download the file.")
,
/** /**
* The server administrator has improperly configured their API key in the configuration * When running the version check, the file on DBO did not contain the a version in the format 'vVersion' such as 'v1.0'.
*/ */
FAIL_APIKEY("The server administrator has improperly configured their API key in the configuration"), FAIL_NOVERSION("When running the version check, the file on DBO did not contain the a version in the format 'vVersion' such as 'v1.0'."),
/** /**
* The updater found an update, but because of the UpdateType being set to NO_DOWNLOAD, it wasn't downloaded. * The id provided by the plugin running the updater was invalid and doesn't exist on DBO.
*/ */
UPDATE_AVAILABLE("The updater found an update, but because of the UpdateType being set to NO_DOWNLOAD, it wasn't downloaded."), FAIL_BADID("The id provided by the plugin running the updater was invalid and doesn't exist on DBO."),
/** /**
* The updater found an update at Spigot * The server administrator has improperly configured their API key in the configuration
*/ */
SPIGOT_UPDATE_AVAILABLE("The updater found an update: %s (Running %s). Download at %s"); FAIL_APIKEY("The server administrator has improperly configured their API key in the configuration"),
private final String description; /**
* The updater found an update, but because of the UpdateType being set to NO_DOWNLOAD, it wasn't downloaded.
private UpdateResult(String description) { */
this.description = description; UPDATE_AVAILABLE("The updater found an update, but because of the UpdateType being set to NO_DOWNLOAD, it wasn't downloaded."),
}
/**
@Override * The updater found an update at Spigot
public String toString() { */
return description; SPIGOT_UPDATE_AVAILABLE("The updater found an update: %s (Running %s). Download at %s");
}
} private final String description;
public static Updater create(ProtocolLib protocolLib, int id, File file, UpdateType type, boolean announce) { private UpdateResult(String description) {
if (Util.isUsingSpigot()) { this.description = description;
return new SpigotUpdater(protocolLib, type, announce); }
} else {
return new BukkitUpdater(protocolLib, id, file, type, announce); @Override
} public String toString() {
} return description;
}
public abstract void start(UpdateType type); }
public boolean shouldNotify() { public static Updater create(ProtocolLib protocolLib, int id, File file, UpdateType type, boolean announce) {
switch (result) { if (Util.isUsingSpigot()) {
case SPIGOT_UPDATE_AVAILABLE: return new SpigotUpdater(protocolLib, type, announce);
case SUCCESS: } else {
case UPDATE_AVAILABLE: return new BukkitUpdater(protocolLib, id, file, type, announce);
return true; }
default: }
return false;
} public abstract void start(UpdateType type);
}
public boolean shouldNotify() {
public abstract String getRemoteVersion(); switch (result) {
} case SPIGOT_UPDATE_AVAILABLE:
case SUCCESS:
case UPDATE_AVAILABLE:
return true;
default:
return false;
}
}
public abstract String getRemoteVersion();
}

Datei anzeigen

@ -1,68 +1,68 @@
/** /**
* (c) 2016 dmulloy2 * (c) 2016 dmulloy2
*/ */
package com.comphenix.protocol.updater; package com.comphenix.protocol.updater;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.PluginDescriptionFile;
import com.comphenix.protocol.updater.Updater.UpdateType; import com.comphenix.protocol.updater.Updater.UpdateType;
/** /**
* @author dmulloy2 * @author dmulloy2
*/ */
public class UpdaterTest { public class UpdaterTest {
private static final int BUKKIT_DEV_ID = 45564; private static final int BUKKIT_DEV_ID = 45564;
private static Plugin plugin; private static Plugin plugin;
//@BeforeClass //@BeforeClass
public static void preparePlugin() { public static void preparePlugin() {
Server server = mock(Server.class); Server server = mock(Server.class);
when(server.getUpdateFolder()).thenReturn(null); when(server.getUpdateFolder()).thenReturn(null);
plugin = mock(Plugin.class); plugin = mock(Plugin.class);
String version = System.getProperty("projectVersion"); String version = System.getProperty("projectVersion");
if (version == null) version = "3.7.0-BETA"; if (version == null) version = "4.0.1-SNAPSHOT-b281";
when(plugin.getDescription()).thenReturn(new PluginDescriptionFile("ProtocolLib", version, null)); when(plugin.getDescription()).thenReturn(new PluginDescriptionFile("ProtocolLib", version, null));
when(plugin.getLogger()).thenReturn(Logger.getLogger("ProtocolLib")); when(plugin.getLogger()).thenReturn(Logger.getLogger("ProtocolLib"));
when(plugin.getDataFolder()).thenReturn(null); when(plugin.getDataFolder()).thenReturn(null);
when(plugin.getServer()).thenReturn(server); when(plugin.getServer()).thenReturn(server);
} }
//@Test //@Test
public void testSpigotUpdater() { public void testSpigotUpdater() {
SpigotUpdater updater = new SpigotUpdater(plugin, UpdateType.NO_DOWNLOAD, true); SpigotUpdater updater = new SpigotUpdater(plugin, UpdateType.NO_DOWNLOAD, true);
String remote = null; String remote = null;
try { try {
remote = updater.getSpigotVersion(); remote = updater.getSpigotVersion();
} catch (Throwable ex) { } catch (Throwable ex) {
ex.printStackTrace(); ex.printStackTrace();
fail("Failed to check for updates"); fail("Failed to check for updates");
} }
System.out.println("Determined remote Spigot version: " + remote); System.out.println("Determined remote Spigot version: " + remote);
System.out.println("Update available: " + updater.versionCheck(remote)); System.out.println("Update available: " + updater.versionCheck(remote));
} }
//@Test //@Test
public void testBukkitUpdater() { public void testBukkitUpdater() {
BukkitUpdater updater = new BukkitUpdater(plugin, BUKKIT_DEV_ID, null, UpdateType.NO_DOWNLOAD, true); BukkitUpdater updater = new BukkitUpdater(plugin, BUKKIT_DEV_ID, null, UpdateType.NO_DOWNLOAD, true);
if (! updater.read()) { if (! updater.read()) {
fail("Failed to check for updates"); fail("Failed to check for updates");
} }
String remote = updater.getLatestName(); String remote = updater.getLatestName();
System.out.println("Determined remote Bukkit Dev version: " + remote); System.out.println("Determined remote Bukkit Dev version: " + remote);
System.out.println("Update available: " + updater.versionCheck(remote)); System.out.println("Update available: " + updater.versionCheck(remote));
} }
} }