diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..67c3b85 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,8 @@ +version: 2 +updates: +- package-ecosystem: maven + directory: "/" + schedule: + interval: daily + time: "04:00" + open-pull-requests-limit: 10 diff --git a/.gitignore b/.gitignore index 30caf63..2f4b166 100644 --- a/.gitignore +++ b/.gitignore @@ -38,4 +38,10 @@ .DS_Store* ehthumbs.db Icon? -Thumbs.db \ No newline at end of file +Thumbs.db +/bin/ + +.classpath +*.project +.settings/org.eclipse.jdt.core.prefs +*.prefs \ No newline at end of file diff --git a/README.md b/README.md index 7271cec..9fd121d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ -*CURRENT BUILD: Bukkit 1.10.x +CURRENT BUILD: Bukkit 1.12 ================================ +**Should work on 1.7-1.12** Since simple save is no longer available, I was looking for a nice simple way to back up my server maps with minimal configuration. Just set the folder and the interval, and your away. Most of the plugins I found had too many features for such a simple task (in my own opinion) so I decided to create this little plugin. @@ -13,7 +14,7 @@ Plus more features as development goes on, but not too many because this is a si **Providing error reports:** -When pasting large ammounts of text please use [pastebin.com](http://pastebin.com). Its completely free and makes it easier for me to read any error messages you provide. You can even set it as a private paste so only people with the link can view it. +When pasting large amounts of text please use [pastebin.com](http://pastebin.com). Its completely free and makes it easier for me to read any error messages you provide. You can even set it as a private paste so only people with the link can view it. Also provide your SimpleBackup **config file** when stating you have a problem, so I can see if that's the problem instead. diff --git a/configuring b/configuring deleted file mode 100644 index 350767f..0000000 --- a/configuring +++ /dev/null @@ -1,83 +0,0 @@ - Interval between map saves in hours, 0.25 is 15 minutes, 1.0 is 1 hour and so on. (1 hour is default). -# backup-interval-hours: 1.0 -# # -# List of worlds to backup, leave it empty to backup all worlds -# backup-worlds: -# # -# List of additional folders to backup (relative paths only). The 'plugins' folder can contain open or locked files! -# Depending on what plugins you have installed, it may not be a good idea to try to backup that folder. -# Usually plugins that write a large amounts of data frequently (like some loggers) are risky. -# backup-folders: -# - plugins -# # -# The folder where backups are stored. Can be absolute path or relative to the working directory. -# backup-file: backups/ -# # -# The backup file name. See Java's SimpleDateFormat for formatting help. -# backup-date-format: yyyy-MM-dd-HH-mm-ss -# # -# Should a backup be created if no one was online since the last backup? -# backup-empty-server: false -# # -# If zipping is disabled, the world files will be copied to a folder. -# If zipping is enabled, the world files will be compressed in a zip file. -# disable-zipping: false -# # -# Backup delete schedule -# For each interval a desired backup frequency is specified, for example: -# delete-schedule: -# intervals: -# - 3d -# - 4w -# - 6m -# interval-frequencies: -# - 1d -# - 1w -# - 0 -# Translates to: -# for backups older than 3 days, leave only 1 backup per day; -# for backups older than 4 weeks + 3 days, leave only 1 backup per week; -# for backups older than 6 months + 4 weeks + 3 days, do not keep any; -# Supported symbols are ('h' = hour, 'd' = day, 'w' = week, 'm' = month, 'y' = year). -# Fractional numbers are not supported. -# # -# true if a message should be broadcast when backup starts or ends -# broadcast-message: true -# # -# Message tag shown in the chat when the server is backing up. -# Example: if the message was set to '[Bukkit is awesome]' you -# would see "[Bukkit is awesome] Starting Backup" when the -# plugin backs up -# backup-message: '[SimpleBackup]' -# # -# The 'backup starting' message that is broadcast when backup starts -# custom-backup-message: Backup starting -# # -# The 'backup completed' message that is broadcast when backup ends -# custom-backup-message-end: Backup completed -# # -#The plugin now has a permissions node as well, it defaults to OP's but you can grant other users access with 'simplebackup.use' - -backup-interval-hours: 1.0 -backup-worlds: -backup-folders: -backup-file: backups/ -backup-date-format: yyyy-MM-dd-HH-mm-ss -backup-empty-server: false -disable-zipping: false -delete-schedule: - intervals: - - 1d - - 3d - - 4w - - 30w - interval-frequencies: - - 4h - - 1d - - 5d - - 30d - -broadcast-message: true -backup-message: '[SimpleBackup]' -custom-backup-message: Backup starting -custom-backup-message-end: Backup completed \ No newline at end of file diff --git a/pom.xml b/pom.xml index 062c1ef..f710c8e 100644 --- a/pom.xml +++ b/pom.xml @@ -1,50 +1,55 @@ - - 4.0.0 - com.exolius.simplebackup - SimpleBackup - 1.8 - - src - - - src - true - - **/*.java - - - - - - maven-compiler-plugin - 2.3.2 - - 1.7 - 1.7 - - - - - - - spigot-repo - https://hub.spigotmc.org/nexus/content/repositories/snapshots/ - - - - - - org.spigotmc - spigot-api - 1.11.2-R0.1-SNAPSHOT/ - provided - - - - org.bukkit - bukkit - 1.11.2-R0.1-SNAPSHOT/ - provided - - + + 4.0.0 + com.exolius.simplebackup + simplebackup + 1.9.1 + + SimpleBackupReloaded + + + ${project.name}-${project.version} + + src + + + + src + true + + **/*.java + + + + + + + maven-compiler-plugin + 3.14.0 + + 1.8 + 1.8 + + + + + + + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + + + + + org.spigotmc + spigot-api + 1.8.8-R0.1-SNAPSHOT + provided + + + diff --git a/src/META-INF/MANIFEST.MF b/src/META-INF/MANIFEST.MF deleted file mode 100644 index 6216e18..0000000 --- a/src/META-INF/MANIFEST.MF +++ /dev/null @@ -1,3 +0,0 @@ -Manifest-Version: 1.0 -Main-Class: com.exolius.simplebackup.SimpleBackup - diff --git a/src/com/exolius/simplebackup/BackupFileManager.java b/src/com/exolius/simplebackup/BackupFileManager.java deleted file mode 100644 index 57f8322..0000000 --- a/src/com/exolius/simplebackup/BackupFileManager.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.exolius.simplebackup; - -import java.io.File; -import java.text.ParsePosition; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.logging.Logger; - -public abstract class BackupFileManager implements IBackupFileManager { - protected File backupFolder; - protected SimpleDateFormat fileNameDateFormat; - protected Logger logger; - - protected BackupFileManager(String backupFolder, String fileNameDateFormat, Logger logger) { - this.backupFolder = new File(backupFolder); - this.fileNameDateFormat = new SimpleDateFormat(fileNameDateFormat); - this.logger = logger; - } - - protected String formatDate(Date date) { - return fileNameDateFormat.format(date); - } - - @Override - public SortedSet backupList() { - File[] files = backupFolder.listFiles(); - if (files == null) { - return new TreeSet(); - } - SortedSet backups = new TreeSet(); - for (File file : files) { - Date date = fileNameDateFormat.parse(file.getName(), new ParsePosition(0)); - if (date != null && file.getName().equals(getFileName(date))) { - backups.add(date); - } - } - return backups; - } - - protected abstract String getFileName(Date date); -} diff --git a/src/com/exolius/simplebackup/BackupHooks.java b/src/com/exolius/simplebackup/BackupHooks.java index 0d5df32..247788e 100644 --- a/src/com/exolius/simplebackup/BackupHooks.java +++ b/src/com/exolius/simplebackup/BackupHooks.java @@ -2,14 +2,15 @@ public class BackupHooks { - public void notifyBackupCreated(String command, String filename) { - if(!command.isEmpty()) { - try { - ProcessBuilder pb = new ProcessBuilder(command, filename); - pb.start(); - } catch(Exception ex) { - - } - } - } + public void notifyBackupCreated(final String command, final String filename) { + if (!command.isEmpty()) { + try { + final ProcessBuilder pb = new ProcessBuilder(command, filename); + pb.start(); + } catch (final Exception ex) { + + } + } + } + } diff --git a/src/com/exolius/simplebackup/Commands.java b/src/com/exolius/simplebackup/Commands.java index 926688f..ec1c8fe 100644 --- a/src/com/exolius/simplebackup/Commands.java +++ b/src/com/exolius/simplebackup/Commands.java @@ -1,32 +1,25 @@ package com.exolius.simplebackup; +import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; public class Commands implements CommandExecutor { - private SimpleBackup plugin; - public Commands(SimpleBackup plugin) { + private final SimpleBackup plugin; + + public Commands(final SimpleBackup plugin) { this.plugin = plugin; } - /*------------------------------------------------------- - This is ran when the plugin command is sent by a player - --------------------------------------------------------*/ @Override - public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) { - if (cmd.getName().equalsIgnoreCase("sbackup")) { - if (sender.hasPermission("simplebackup.use")) { - new Thread(new Runnable() { - @Override - public void run() { - plugin.doBackup(); - } - }).start(); - } + public boolean onCommand(final CommandSender sender, final Command cmd, final String label, final String[] args) { + if (sender.hasPermission("simplebackup.use")) { + Bukkit.getScheduler().runTaskAsynchronously(this.plugin, () -> Commands.this.plugin.doBackup()); return true; + } else { + return false; } - return false; } -} \ No newline at end of file +} diff --git a/src/com/exolius/simplebackup/CopyBackup.java b/src/com/exolius/simplebackup/CopyBackup.java deleted file mode 100644 index 40bd609..0000000 --- a/src/com/exolius/simplebackup/CopyBackup.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.exolius.simplebackup; - -import java.io.File; -import java.io.IOException; -import java.util.Date; -import java.util.logging.Logger; - -public class CopyBackup extends BackupFileManager { - - public CopyBackup(String backupFolder, String fileNameDateFormat, Logger logger) { - super(backupFolder, fileNameDateFormat, logger); - } - - @Override - public String createBackup(Iterable worldFolders) throws IOException { - Date date = new Date(); - File destination = new File(backupFolder, getFileName(date)); - for (File worldFolder : worldFolders) { - logger.info("Backing up " + worldFolder); - FileUtils.copyFiles(worldFolder, new File(destination, worldFolder.getName()), logger); - } - return destination.getAbsolutePath(); - } - - @Override - public void deleteBackup(Date date) throws IOException { - File backupFile = new File(backupFolder, getFileName(date)); - logger.info("Deleting backup " + backupFile.getPath()); - deleteFile(backupFile); - } - - @Override - protected String getFileName(Date date) { - return formatDate(date); - } - - void deleteFile(File f) throws IOException { - if (f.isDirectory()) { - for (File c : f.listFiles()) { - deleteFile(c); - } - } - f.delete(); - } -} diff --git a/src/com/exolius/simplebackup/SimpleBackup.java b/src/com/exolius/simplebackup/SimpleBackup.java index d6f41d5..43ba9e9 100644 --- a/src/com/exolius/simplebackup/SimpleBackup.java +++ b/src/com/exolius/simplebackup/SimpleBackup.java @@ -1,18 +1,27 @@ package com.exolius.simplebackup; +import java.io.File; +import java.io.IOException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collection; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.List; +import java.util.logging.Level; +import java.util.stream.Collectors; + import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.World; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.plugin.java.JavaPlugin; -import java.io.File; -import java.io.IOException; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.concurrent.Callable; -import java.util.logging.Level; +import com.exolius.simplebackup.manager.CopyBackup; +import com.exolius.simplebackup.manager.ZipBackup; +import com.exolius.simplebackup.util.DeleteSchedule; public class SimpleBackup extends JavaPlugin { private double interval; @@ -35,7 +44,6 @@ public class SimpleBackup extends JavaPlugin { private IBackupFileManager backupFileManager; private DeleteSchedule deleteSchedule; - protected FileConfiguration config; private final LoginListener loginListener = new LoginListener(); private final BackupHooks backupHooks= new BackupHooks(); @@ -44,8 +52,8 @@ public class SimpleBackup extends JavaPlugin { -----------------------------------------*/ @Override public void onDisable() { - getServer().getScheduler().cancelTasks(this); - getLogger().info("Disabled SimpleBackup"); + this.getServer().getScheduler().cancelTasks(this); + this.getLogger().info("Disabled SimpleBackup"); } /*---------------------------------------- @@ -53,43 +61,40 @@ public void onDisable() { -----------------------------------------*/ @Override public void onEnable() { - // When plugin is enabled, load the "config.yml" - loadConfiguration(); + this.saveDefaultConfig(); + this.loadConfiguration(); - if (!backupEmpty) { - getServer().getPluginManager().registerEvents(loginListener, this); + if (!this.backupEmpty) { + this.getServer().getPluginManager().registerEvents(this.loginListener, this); } //Plugin commands - getCommand("sbackup").setExecutor(new Commands(this)); + this.getCommand("sbackup").setExecutor(new Commands(this)); // Shameless self promotion in the source code :D - if (selfPromotion) { - getLogger().info("Developed by Exolius"); + if (this.selfPromotion) { + this.getLogger().info("Developed by Exolius"); } // Set the backup interval, 72000.0D is 1 hour, multiplying it by the value interval will change the backup cycle time - long ticks = (long) (72000 * this.interval); + final long ticks = (long) (72000 * this.interval); if (ticks > 0) { - long delay = this.startHour != null ? syncStart(this.startHour) : ticks; + final long delay = this.startHour != null ? this.syncStart(this.startHour) : ticks; // Add the repeating task, set it to repeat the specified time - this.getServer().getScheduler().runTaskTimerAsynchronously(this, new Runnable() { - @Override - public void run() { - // When the task is run, start the map backup - if (backupEmpty || Bukkit.getServer().getOnlinePlayers().size() > 0 || loginListener.someoneWasOnline()) { - doBackup(); - } else { - getLogger().info("Skipping backup (no one was online)"); - } - } - }, delay, ticks); - getLogger().info("Backup scheduled starting in " + delay / 72000. + " hours, repeat interval: " + this.interval + " hours"); + this.getServer().getScheduler().runTaskTimerAsynchronously(this, () -> { + // When the task is run, start the map backup + if (SimpleBackup.this.backupEmpty || Bukkit.getServer().getOnlinePlayers().size() > 0 || SimpleBackup.this.loginListener.someoneWasOnline()) { + SimpleBackup.this.doBackup(); + } else { + SimpleBackup.this.getLogger().info("Skipping backup (no one was online)"); + } + }, delay, ticks); + this.getLogger().info("Backup scheduled starting in " + delay / 72000. + " hours, repeat interval: " + this.interval + " hours"); } // After enabling, print to console to say if it was successful - getLogger().info("Enabled."); + this.getLogger().info("Enabled."); } /*--------------------------------------------------------- @@ -97,55 +102,52 @@ public void run() { ---------------------------------------------------------*/ public void loadConfiguration() { // Set the config object - config = getConfig(); + final FileConfiguration config = this.getConfig(); // Set default values for variables - interval = config.getDouble("backup-interval-hours"); - broadcast = config.getBoolean("broadcast-message"); - backupFile = config.getString("backup-file"); - backupWorlds = config.getStringList("backup-worlds"); - additionalFolders = config.getStringList("backup-folders"); - dateFormat = config.getString("backup-date-format"); - backupEmpty = config.getBoolean("backup-empty-server"); - message = config.getString("backup-message"); - customMessage = config.getString("custom-backup-message"); - customMessageEnd = config.getString("custom-backup-message-end"); - backupCommand = config.getString("backup-completed-hook"); - disableZipping = config.getBoolean("disable-zipping"); - selfPromotion = config.getBoolean("self-promotion"); - String startTime = config.getString("start-time"); - List intervalsStr = config.getStringList("delete-schedule.intervals"); - List frequenciesStr = config.getStringList("delete-schedule.interval-frequencies"); - - //Save the configuration file - config.options().copyDefaults(true); - saveConfig(); - - if (disableZipping) { - backupFileManager = new CopyBackup(backupFile, dateFormat, getLogger()); + this.interval = config.getDouble("backup-interval-hours"); + this.broadcast = config.getBoolean("broadcast-message"); + this.backupFile = config.getString("backup-file"); + this.backupWorlds = config.getStringList("backup-worlds"); + this.additionalFolders = config.getStringList("backup-folders"); + this.dateFormat = config.getString("backup-date-format"); + this.backupEmpty = config.getBoolean("backup-empty-server"); + this.message = config.getString("backup-message"); + this.customMessage = config.getString("custom-backup-message"); + this.customMessageEnd = config.getString("custom-backup-message-end"); + this.backupCommand = config.getString("backup-completed-hook"); + this.disableZipping = config.getBoolean("disable-zipping"); + this.selfPromotion = config.getBoolean("self-promotion"); + final String startTime = config.getString("start-time"); + final List intervalsStr = config.getStringList("delete-schedule.intervals"); + final List frequenciesStr = config.getStringList("delete-schedule.interval-frequencies"); + final String backupPrefix = config.getString("backup-prefix", ""); + + if (this.disableZipping) { + this.backupFileManager = new CopyBackup(this.backupFile, backupPrefix, this.dateFormat, this.getLogger()); } else { - backupFileManager = new ZipBackup(backupFile, dateFormat, getLogger()); + this.backupFileManager = new ZipBackup(this.backupFile, backupPrefix, this.dateFormat, this.getLogger()); } - this.deleteSchedule = new DeleteSchedule(intervalsStr, frequenciesStr, backupFileManager, getLogger()); - Collection folders = foldersForBackup(); - Collection worlds = worldsForBackup(); - if (worlds.size() < backupWorlds.size()) { - getLogger().warning("Not all listed worlds are recognized."); + this.deleteSchedule = new DeleteSchedule(intervalsStr, frequenciesStr, this.backupFileManager, this.getLogger()); + final Collection folders = this.foldersForBackup(); + final Collection worlds = this.worldsForBackup(); + if (worlds.size() < this.backupWorlds.size()) { + this.getLogger().warning("Not all listed worlds are recognized."); } - if (folders.size() < additionalFolders.size()) { - getLogger().warning("Not all listed folders are recognized."); + if (folders.size() < this.additionalFolders.size()) { + this.getLogger().warning("Not all listed folders are recognized."); } - getLogger().info("Worlds " + worlds + " scheduled for backup."); + this.getLogger().info("Worlds " + worlds.stream().map(World::getName).collect(Collectors.toList()) + " scheduled for backup."); if (!folders.isEmpty()) { - getLogger().info("Folders " + folders + " scheduled for backup."); + this.getLogger().info("Folders " + folders + " scheduled for backup."); } if (startTime != null) { try { - Date parsedTime = new SimpleDateFormat("HH:mm").parse(startTime); - startHour = hoursOf(parsedTime); - } catch (ParseException ignored) { - getLogger().warning("Can't parse time " + startTime); + final Date parsedTime = new SimpleDateFormat("HH:mm").parse(startTime); + this.startHour = this.hoursOf(parsedTime); + } catch (final ParseException ignored) { + this.getLogger().warning("Can't parse time " + startTime); } } } @@ -156,71 +158,60 @@ public void loadConfiguration() { public synchronized void doBackup() { // Begin backup of worlds // Broadcast the backup initialization if enabled - if (broadcast) { - getServer().getScheduler().runTask(this, new Runnable(){ - @Override - public void run() { - getServer().broadcastMessage(ChatColor.BLUE + message + " " + customMessage); - }}); + if (this.broadcast) { + this.getServer().getScheduler().runTask(this, () -> SimpleBackup.this.getServer().broadcastMessage(ChatColor.BLUE + SimpleBackup.this.message + " " + SimpleBackup.this.customMessage)); } // Loop through all the specified worlds and save them - List foldersToBackup = new ArrayList(); - for (final World world : worldsForBackup()) { + final List foldersToBackup = new ArrayList<>(); + for (final World world : this.worldsForBackup()) { world.setAutoSave(false); try { - getServer().getScheduler().callSyncMethod(this, new Callable() { - @Override - public Object call() throws Exception { - world.save(); - return null; - } - }).get(); + this.getServer().getScheduler().callSyncMethod(this, () -> { + world.save(); + return null; + }).get(); foldersToBackup.add(world.getWorldFolder()); - } catch (Exception e) { - getLogger().log(Level.WARNING, e.getMessage(), e); + } catch (final Exception e) { + this.getLogger().log(Level.WARNING, e.getMessage(), e); } } // additional folders, e.g. "plugins/" - foldersToBackup.addAll(foldersForBackup()); + foldersToBackup.addAll(this.foldersForBackup()); // zip/copy world folders String backupFile = null; try { - backupFile = backupFileManager.createBackup(foldersToBackup); - } catch (IOException e) { - getLogger().log(Level.WARNING, e.getMessage(), e); + backupFile = this.backupFileManager.createBackup(foldersToBackup); + } catch (final IOException e) { + this.getLogger().log(Level.WARNING, e.getMessage(), e); } // re-enable auto-save - for (World world : worldsForBackup()) { + for (final World world : this.worldsForBackup()) { world.setAutoSave(true); } // delete old backups try { - deleteSchedule.deleteOldBackups(); - } catch (IOException e) { - getLogger().log(Level.WARNING, e.getMessage(), e); + this.deleteSchedule.deleteOldBackups(); + } catch (final IOException e) { + this.getLogger().log(Level.WARNING, e.getMessage(), e); } // Broadcast the backup completion if enabled - if (broadcast) { - getServer().getScheduler().runTask(this, new Runnable(){ - @Override - public void run() { - getServer().broadcastMessage(ChatColor.BLUE + message + " " + customMessageEnd); - }}); + if (this.broadcast) { + this.getServer().getScheduler().runTask(this, () -> SimpleBackup.this.getServer().broadcastMessage(ChatColor.BLUE + SimpleBackup.this.message + " " + SimpleBackup.this.customMessageEnd)); } if(backupFile != null) { - loginListener.notifyBackupCreated(); - backupHooks.notifyBackupCreated(backupCommand, backupFile); + this.loginListener.notifyBackupCreated(); + this.backupHooks.notifyBackupCreated(this.backupCommand, backupFile); } } private Collection foldersForBackup() { - List result = new ArrayList(); - for (String additionalFolder : additionalFolders) { - File f = new File(".", additionalFolder); + final List result = new ArrayList<>(); + for (final String additionalFolder : this.additionalFolders) { + final File f = new File(".", additionalFolder); if (f.exists()) { result.add(f); } @@ -229,27 +220,33 @@ private Collection foldersForBackup() { } private Collection worldsForBackup() { - List worlds = new ArrayList(); - for (World world : getServer().getWorlds()) { - if (backupWorlds.isEmpty() || backupWorlds.contains(world.getName())) { + final List worlds = new ArrayList<>(); + for (final World world : this.getServer().getWorlds()) { + if (this.backupWorlds.isEmpty() || this.backupWorlds.contains(world.getName())) { worlds.add(world); } } return worlds; } - private double hoursOf(Date parsedTime) { - return parsedTime.getHours() + parsedTime.getMinutes() / 60. + parsedTime.getSeconds() / 3600.; + private double hoursOf(final Date parsedTime) { + final Calendar calendar = GregorianCalendar.getInstance(); + calendar.setTime(parsedTime); + final int hours = calendar.get(Calendar.HOUR_OF_DAY); + final int minutes = calendar.get(Calendar.MINUTE); + final int seconds = calendar.get(Calendar.SECOND); + + return hours + minutes / 60. + seconds / 3600.; } - private long syncStart(double startHour) { - double now = hoursOf(new Date()); + private long syncStart(final double startHour) { + final double now = this.hoursOf(new Date()); double diff = now - startHour; if (diff < 0) { diff += 24; } - double intervalPart = diff - Math.floor(diff / interval) * interval; - double remaining = interval - intervalPart; + final double intervalPart = diff - Math.floor(diff / this.interval) * this.interval; + final double remaining = this.interval - intervalPart; return (long) (remaining * 72000); } diff --git a/src/com/exolius/simplebackup/ZipBackup.java b/src/com/exolius/simplebackup/ZipBackup.java deleted file mode 100644 index 1ff07bc..0000000 --- a/src/com/exolius/simplebackup/ZipBackup.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.exolius.simplebackup; - -import java.io.*; -import java.net.URI; -import java.util.Date; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - -public class ZipBackup extends BackupFileManager { - - public ZipBackup(String backupFolder, String fileNameDateFormat, Logger logger) { - super(backupFolder, fileNameDateFormat, logger); - } - - @Override - public String createBackup(Iterable worldFolders) throws IOException { - if (!backupFolder.exists()) { - backupFolder.mkdirs(); - } - Date date = new Date(); - File backupFile = new File(backupFolder, getFileName(date)); - ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(backupFile)); - try { - for (File worldFolder : worldFolders) { - logger.info("Backing up " + worldFolder); - zipFiles(worldFolder.getParentFile().toURI(), worldFolder, zip); - } - } finally { - try { - zip.close(); - } catch (IOException e) { - logger.log(Level.FINE, e.getMessage(), e); - } - } - return backupFile.getAbsolutePath(); - } - - @Override - public void deleteBackup(Date date) { - File backupFile = new File(backupFolder, getFileName(date)); - logger.info("Deleting backup " + backupFile.getPath()); - backupFile.delete(); - } - - @Override - protected String getFileName(Date date) { - return formatDate(date) + ".zip"; - } - - private void zipFiles(URI root, File source, ZipOutputStream zip) throws IOException { - if (source.isDirectory()) { - for (String file : source.list()) { - zipFiles(root, new File(source, file), zip); - } - } else { - ZipEntry entry = new ZipEntry(root.relativize(source.toURI()).getPath()); - zip.putNextEntry(entry); - InputStream in = null; - try { - in = new FileInputStream(source); - byte[] buffer = new byte[4096]; - int bytesRead; - while ((bytesRead = in.read(buffer)) > 0) { - zip.write(buffer, 0, bytesRead); - } - } catch (IOException e) { - logger.warning("Unable to backup file: " + source.getAbsolutePath() + "(" + e.getMessage() + ")"); - } finally { - if (in != null) { - in.close(); - } - } - } - } -} diff --git a/src/com/exolius/simplebackup/manager/BackupFileManager.java b/src/com/exolius/simplebackup/manager/BackupFileManager.java new file mode 100644 index 0000000..7fe7332 --- /dev/null +++ b/src/com/exolius/simplebackup/manager/BackupFileManager.java @@ -0,0 +1,48 @@ +package com.exolius.simplebackup.manager; + +import java.io.File; +import java.text.ParsePosition; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.logging.Logger; + +import com.exolius.simplebackup.IBackupFileManager; + +public abstract class BackupFileManager implements IBackupFileManager { + + protected File backupFolder; + protected String backupPrefix; + protected SimpleDateFormat fileNameDateFormat; + protected Logger logger; + + protected BackupFileManager(final String backupFolder, final String backupPrefix, final String fileNameDateFormat, final Logger logger) { + this.backupFolder = new File(backupFolder); + this.backupPrefix = backupPrefix; + this.fileNameDateFormat = new SimpleDateFormat(fileNameDateFormat); + this.logger = logger; + } + + protected String formatDate(final Date date) { + return this.fileNameDateFormat.format(date); + } + + @Override + public SortedSet backupList() { + final File[] files = this.backupFolder.listFiles(); + if (files == null) { + return new TreeSet<>(); + } + final SortedSet backups = new TreeSet<>(); + for (final File file : files) { + final Date date = this.fileNameDateFormat.parse(file.getName(), new ParsePosition(0)); + if (date != null && file.getName().equals(this.getFileName(date))) { + backups.add(date); + } + } + return backups; + } + + protected abstract String getFileName(Date date); +} diff --git a/src/com/exolius/simplebackup/manager/CopyBackup.java b/src/com/exolius/simplebackup/manager/CopyBackup.java new file mode 100644 index 0000000..56c9457 --- /dev/null +++ b/src/com/exolius/simplebackup/manager/CopyBackup.java @@ -0,0 +1,47 @@ +package com.exolius.simplebackup.manager; + +import java.io.File; +import java.io.IOException; +import java.util.Date; +import java.util.logging.Logger; + +import com.exolius.simplebackup.util.FileUtils; + +public class CopyBackup extends BackupFileManager { + + public CopyBackup(final String backupFolder, final String backupPrefix, final String fileNameDateFormat, final Logger logger) { + super(backupFolder, backupPrefix, fileNameDateFormat, logger); + } + + @Override + public String createBackup(final Iterable worldFolders) throws IOException { + final Date date = new Date(); + final File destination = new File(this.backupFolder, this.getFileName(date)); + for (final File worldFolder : worldFolders) { + this.logger.info("Backing up " + worldFolder); + FileUtils.copyFiles(worldFolder, new File(destination, worldFolder.getName()), this.logger); + } + return destination.getAbsolutePath(); + } + + @Override + public void deleteBackup(final Date date) throws IOException { + final File backupFile = new File(this.backupFolder, this.getFileName(date)); + this.logger.info("Deleting backup " + backupFile.getPath()); + this.deleteFile(backupFile); + } + + @Override + protected String getFileName(final Date date) { + return this.formatDate(date); + } + + void deleteFile(final File f) throws IOException { + if (f.isDirectory()) { + for (final File c : f.listFiles()) { + this.deleteFile(c); + } + } + f.delete(); + } +} diff --git a/src/com/exolius/simplebackup/manager/ZipBackup.java b/src/com/exolius/simplebackup/manager/ZipBackup.java new file mode 100644 index 0000000..136831a --- /dev/null +++ b/src/com/exolius/simplebackup/manager/ZipBackup.java @@ -0,0 +1,81 @@ +package com.exolius.simplebackup.manager; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.util.Date; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +public class ZipBackup extends BackupFileManager { + + public ZipBackup(final String backupFolder, final String backupPrefix, final String fileNameDateFormat, final Logger logger) { + super(backupFolder, backupPrefix, fileNameDateFormat, logger); + } + + @Override + public String createBackup(final Iterable worldFolders) throws IOException { + if (!this.backupFolder.exists()) { + this.backupFolder.mkdirs(); + } + final Date date = new Date(); + final File backupFile = new File(this.backupFolder, this.getFileName(date)); + final ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(backupFile)); + try { + for (final File worldFolder : worldFolders) { + this.logger.info("Backing up " + worldFolder); + this.zipFiles(worldFolder.getParentFile().toURI(), worldFolder, zip); + } + } finally { + try { + zip.close(); + } catch (final IOException e) { + this.logger.log(Level.FINE, e.getMessage(), e); + } + } + return backupFile.getAbsolutePath(); + } + + @Override + public void deleteBackup(final Date date) { + final File backupFile = new File(this.backupFolder, this.getFileName(date)); + this.logger.info("Deleting backup " + backupFile.getPath()); + backupFile.delete(); + } + + @Override + protected String getFileName(final Date date) { + return this.backupPrefix + this.formatDate(date) + ".zip"; + } + + private void zipFiles(final URI root, final File source, final ZipOutputStream zip) throws IOException { + if (source.isDirectory()) { + for (final String file : source.list()) { + this.zipFiles(root, new File(source, file), zip); + } + } else { + final ZipEntry entry = new ZipEntry(root.relativize(source.toURI()).getPath()); + zip.putNextEntry(entry); + InputStream in = null; + try { + in = new FileInputStream(source); + final byte[] buffer = new byte[4096]; + int bytesRead; + while ((bytesRead = in.read(buffer)) > 0) { + zip.write(buffer, 0, bytesRead); + } + } catch (final IOException e) { + this.logger.warning("Unable to backup file: " + source.getAbsolutePath() + "(" + e.getMessage() + ")"); + } finally { + if (in != null) { + in.close(); + } + } + } + } +} diff --git a/src/com/exolius/simplebackup/DeleteSchedule.java b/src/com/exolius/simplebackup/util/DeleteSchedule.java similarity index 95% rename from src/com/exolius/simplebackup/DeleteSchedule.java rename to src/com/exolius/simplebackup/util/DeleteSchedule.java index f178daa..9037851 100644 --- a/src/com/exolius/simplebackup/DeleteSchedule.java +++ b/src/com/exolius/simplebackup/util/DeleteSchedule.java @@ -1,13 +1,19 @@ -package com.exolius.simplebackup; +package com.exolius.simplebackup.util; -import java.io.File; import java.io.IOException; -import java.text.*; -import java.util.*; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; +import com.exolius.simplebackup.IBackupFileManager; + public class DeleteSchedule { private List intervals; diff --git a/src/com/exolius/simplebackup/FileUtils.java b/src/com/exolius/simplebackup/util/FileUtils.java similarity index 98% rename from src/com/exolius/simplebackup/FileUtils.java rename to src/com/exolius/simplebackup/util/FileUtils.java index 2e857a1..bcd45a3 100644 --- a/src/com/exolius/simplebackup/FileUtils.java +++ b/src/com/exolius/simplebackup/util/FileUtils.java @@ -1,4 +1,4 @@ -package com.exolius.simplebackup; +package com.exolius.simplebackup.util; import java.io.File; import java.io.FileInputStream; diff --git a/src/config.yml b/src/config.yml index bd323ad..9c9a594 100644 --- a/src/config.yml +++ b/src/config.yml @@ -1,28 +1,30 @@ +# The time of day to make backups (makes sense with daily backups) +start-time: '03:00' + # Interval between map saves in hours, 0.25 is 15 minutes, 1.0 is 1 hour and so on. (1 hour is default). -# backup-interval-hours: 1.0 -# # +backup-interval-hours: 1.0 + # List of worlds to backup, leave it empty to backup all worlds -# backup-worlds: -# # +backup-worlds: [] + # List of additional folders to backup (relative paths only). The 'plugins' folder can contain open or locked files! # Depending on what plugins you have installed, it may not be a good idea to try to backup that folder. # Usually plugins that write a large amounts of data frequently (like some loggers) are risky. -# backup-folders: -# - plugins -# # +backup-folders: + # The folder where backups are stored. Can be absolute path or relative to the working directory. -# backup-file: backups/ -# # +backup-file: backups/ + # The backup file name. See Java's SimpleDateFormat for formatting help. -# backup-date-format: yyyy-MM-dd-HH-mm-ss -# # +backup-date-format: yyyy-MM-dd-HH-mm-ss + # Should a backup be created if no one was online since the last backup? -# backup-empty-server: false -# # +backup-empty-server: false + # If zipping is disabled, the world files will be copied to a folder. # If zipping is enabled, the world files will be compressed in a zip file. -# disable-zipping: false -# # +disable-zipping: false + # Backup delete schedule # For each interval a desired backup frequency is specified, for example: # delete-schedule: @@ -40,47 +42,33 @@ # for backups older than 6 months + 4 weeks + 3 days, do not keep any; # Supported symbols are ('h' = hour, 'd' = day, 'w' = week, 'm' = month, 'y' = year). # Fractional numbers are not supported. -# # +delete-schedule: + intervals: + - 1d + - 3d + - 4w + - 30w + interval-frequencies: + - 4h + - 1d + - 5d + - 30d + # true if a message should be broadcast when backup starts or ends -# broadcast-message: true -# # +broadcast-message: true + # Message tag shown in the chat when the server is backing up. # Example: if the message was set to '[Bukkit is awesome]' you # would see "[Bukkit is awesome] Starting Backup" when the # plugin backs up -# backup-message: '[SimpleBackup]' -# # -# The 'backup starting' message that is broadcast when backup starts -# custom-backup-message: Backup starting -# # -# The 'backup completed' message that is broadcast when backup ends -# custom-backup-message-end: Backup completed -# # -# The time of day to make backups (makes sense with daily backups) -# start-time: '03:00' -# # +backup-message: '[Backup]' -backup-interval-hours: 1.0 -backup-worlds: -backup-folders: -backup-file: backups/ -backup-date-format: yyyy-MM-dd-HH-mm-ss -backup-empty-server: false -disable-zipping: false -delete-schedule: - intervals: - - 1d - - 3d - - 4w - - 30w - interval-frequencies: - - 4h - - 1d - - 5d - - 30d - -broadcast-message: true -backup-message: '[SimpleBackup]' +# The 'backup starting' message that is broadcast when backup starts custom-backup-message: Backup starting + +# The 'backup completed' message that is broadcast when backup ends custom-backup-message-end: Backup completed backup-completed-hook: '' + +# Prefix added to backup zip files +backup-prefix: '' \ No newline at end of file diff --git a/src/plugin.yml b/src/plugin.yml index 471b31e..f25f623 100644 --- a/src/plugin.yml +++ b/src/plugin.yml @@ -1,6 +1,9 @@ -name: SimpleBackup +name: SimpleBackupReloaded main: com.exolius.simplebackup.SimpleBackup version: ${project.version} +description: Updated version of the original SimpleBackup plugin by Exolius +author: Derkades +authors: [Exolius] commands: sbackup: