diff --git a/.gitignore b/.gitignore index 5fd2a421..c7f73196 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ -/target +/target /.settings /.classpath /.project -/work +/work + +# Intellij files +.idea/ diff --git a/src/main/java/org/jvnet/hudson/plugins/thinbackup/ThinBackupPeriodicWork.java b/src/main/java/org/jvnet/hudson/plugins/thinbackup/ThinBackupPeriodicWork.java index 8a2e036c..aaf6c23b 100644 --- a/src/main/java/org/jvnet/hudson/plugins/thinbackup/ThinBackupPeriodicWork.java +++ b/src/main/java/org/jvnet/hudson/plugins/thinbackup/ThinBackupPeriodicWork.java @@ -97,7 +97,7 @@ protected void backupNow(final BackupType type) { backupPath); LOGGER.log(Level.SEVERE, msg, e); } finally { - if (!inQuietModeBeforeBackup) + if (!inQuietModeBeforeBackup || Utils.isQuiteDownOngoingButNeedsToCancel(plugin.isWaitForIdle(), hudson)) hudson.doCancelQuietDown(); else LOGGER.info("Backup process finsihed, but still in quiet mode as before. The quiet mode needs to be cancled manually, because it is not sure who is putting jenkins/hudson into quiet mode."); diff --git a/src/main/java/org/jvnet/hudson/plugins/thinbackup/ThinBackupPluginImpl.java b/src/main/java/org/jvnet/hudson/plugins/thinbackup/ThinBackupPluginImpl.java index d70f912c..3191e5b8 100644 --- a/src/main/java/org/jvnet/hudson/plugins/thinbackup/ThinBackupPluginImpl.java +++ b/src/main/java/org/jvnet/hudson/plugins/thinbackup/ThinBackupPluginImpl.java @@ -27,6 +27,7 @@ import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; +import jenkins.model.Jenkins; import org.apache.commons.lang.StringUtils; import org.jvnet.hudson.plugins.thinbackup.utils.EnvironmentVariableNotDefinedException; import org.jvnet.hudson.plugins.thinbackup.utils.Utils; @@ -36,6 +37,8 @@ import antlr.ANTLRException; +import static org.jvnet.hudson.plugins.thinbackup.utils.Utils.isQuiteDownOngoingButNeedsToCancel; + public class ThinBackupPluginImpl extends Plugin { private static final int VERY_HIGH_TIMEOUT = 12 * 60; @@ -250,6 +253,11 @@ public String getBackupAdditionalFilesRegex() { } public void setWaitForIdle(boolean waitForIdle) { + Jenkins jenkinsInstance = Jenkins.getInstance(); + + if (isQuiteDownOngoingButNeedsToCancel(waitForIdle, jenkinsInstance)) + jenkinsInstance.doCancelQuietDown(); + this.waitForIdle = waitForIdle; } diff --git a/src/main/java/org/jvnet/hudson/plugins/thinbackup/utils/Utils.java b/src/main/java/org/jvnet/hudson/plugins/thinbackup/utils/Utils.java index ef1bc3a5..60a327bc 100644 --- a/src/main/java/org/jvnet/hudson/plugins/thinbackup/utils/Utils.java +++ b/src/main/java/org/jvnet/hudson/plugins/thinbackup/utils/Utils.java @@ -1,475 +1,472 @@ /** - * Copyright (C) 2011 Matthias Steinkogler, Thomas Fürer - * - * 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 3 of 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; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 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. If not, see http://www.gnu.org/licenses. + * Copyright (C) 2011 Matthias Steinkogler, Thomas Fürer + *

+ * 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 3 of 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; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 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. If not, see http://www.gnu.org/licenses. */ package org.jvnet.hudson.plugins.thinbackup.utils; import hudson.model.Computer; import hudson.model.Hudson; +import jenkins.model.Jenkins; +import org.apache.commons.io.filefilter.DirectoryFileFilter; +import org.apache.commons.io.filefilter.FileFileFilter; +import org.apache.commons.io.filefilter.FileFilterUtils; +import org.apache.commons.io.filefilter.IOFileFilter; +import org.jvnet.hudson.plugins.thinbackup.ThinBackupPeriodicWork.BackupType; +import org.jvnet.hudson.plugins.thinbackup.backup.BackupSet; +import org.jvnet.hudson.plugins.thinbackup.backup.HudsonBackup; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; -import javax.servlet.ServletException; +public final class Utils { + public static final SimpleDateFormat DISPLAY_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm"); + public static final SimpleDateFormat DIRECTORY_NAME_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH-mm"); + public static final String THINBACKUP_TMP_DIR = System.getProperty("java.io.tmpdir") + File.separator + + "thinBackupTmpDir"; + public static final int FORCE_QUIETMODE_TIMEOUT_MINUTES = 120; + private static final int SLEEP_TIMEOUT = 500; + private static final Logger LOGGER = Logger.getLogger("hudson.plugins.thinbackup"); + private static final int QUIETMODE_MONITORING_SLEEP = 500; + private static final String DIRECTORY_NAME_DATE_EXTRACTION_REGEX = String.format("(%s|%s)-", BackupType.FULL, + BackupType.DIFF); + private static final String START_ENV_VAR_TOKEN = "${"; + private static final String END_ENV_VAR_TOKEN = "}"; + private static boolean PLUGIN_INITIATED_QUITE_MODE = false; + + private Utils() { + } -import org.apache.commons.io.filefilter.DirectoryFileFilter; -import org.apache.commons.io.filefilter.FileFileFilter; -import org.apache.commons.io.filefilter.FileFilterUtils; -import org.apache.commons.io.filefilter.IOFileFilter; -import org.jvnet.hudson.plugins.thinbackup.ThinBackupPeriodicWork.BackupType; -import org.jvnet.hudson.plugins.thinbackup.backup.BackupSet; -import org.jvnet.hudson.plugins.thinbackup.backup.HudsonBackup; + public static boolean isPluginInitiatedQuiteMode() { + return PLUGIN_INITIATED_QUITE_MODE; + } -public final class Utils { - private static final int SLEEP_TIMEOUT = 500; - - private static final Logger LOGGER = Logger.getLogger("hudson.plugins.thinbackup"); - - private static final int QUIETMODE_MONITORING_SLEEP = 500; - private static final String DIRECTORY_NAME_DATE_EXTRACTION_REGEX = String.format("(%s|%s)-", BackupType.FULL, - BackupType.DIFF); - private static final String START_ENV_VAR_TOKEN = "${"; - private static final String END_ENV_VAR_TOKEN = "}"; - - public static final SimpleDateFormat DISPLAY_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm"); - public static final SimpleDateFormat DIRECTORY_NAME_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH-mm"); - public static final String THINBACKUP_TMP_DIR = System.getProperty("java.io.tmpdir") + File.separator - + "thinBackupTmpDir"; - public static final int FORCE_QUIETMODE_TIMEOUT_MINUTES = 120; - - private Utils() {} - - /** - * Waits until all Hudson slaves are idle. - */ - public static void waitUntilIdle() { - Hudson hudson = Hudson.getInstance(); - final Computer computers[] = hudson.getComputers(); - - boolean running; - do { - running = false; - for (final Computer computer : computers) { - if (computer.countBusy() != 0) { - running = true; - break; - } - } - - try { - Thread.sleep(QUIETMODE_MONITORING_SLEEP); - } catch (final InterruptedException e) { - LOGGER.log(Level.WARNING, e.getMessage(), e); - } - } while (running); - } - - /** - * Waits until all executors are idle and switch jenkins to quiet mode. If it takes to long that all executors are - * idle because in the mean time other jobs are executed the timeout ensure that the quiet mode is forced. - * - * @param timeout - * specifies when a quiet mode is forced. 0 = no timeout. - * @param unit - * specifies the time unit for the value of timeout. - * @throws IOException ? - */ - public static void waitUntilIdleAndSwitchToQuietMode(int timeout, TimeUnit unit) throws IOException { - Hudson hudson = Hudson.getInstance(); - final Computer computers[] = hudson.getComputers(); - - boolean running; - long starttime = System.currentTimeMillis(); - do { - running = false; - for (final Computer computer : computers) { - if (computer.countBusy() != 0) { - running = true; - break; - } - } - - try { - TimeUnit.MILLISECONDS.sleep(QUIETMODE_MONITORING_SLEEP); - } catch (final InterruptedException e) { - LOGGER.log(Level.WARNING, e.getMessage(), e); - } - - if (!hudson.isQuietingDown() && starttime + unit.toMillis(timeout) < System.currentTimeMillis()) { - LOGGER.info("Force quiet mode for jenkins now and wait unilt all executors are idle."); - hudson.doQuietDown(); - } - } while (running); - } - - /** - * @param directory directory to get the date from - * @return the date component of a directory name formatted in the thinBackup standard - */ - public static Date getDateFromBackupDirectory(final File directory) { - return getDateFromBackupDirectoryName(directory.getName()); - } - - /** - * @param directoryName directory name to get the date from - * @return the date component of a directory name formatted in the thinBackup standard - */ - public static Date getDateFromBackupDirectoryName(final String directoryName) { - Date result = null; - - String dateOnly = ""; - try { - if (directoryName.startsWith(BackupType.FULL.toString()) || directoryName.startsWith(BackupType.DIFF.toString())) { - dateOnly = directoryName.replaceFirst(DIRECTORY_NAME_DATE_EXTRACTION_REGEX, ""); - if (!dateOnly.isEmpty()) { - result = DIRECTORY_NAME_DATE_FORMAT.parse(dateOnly); - } - } - } catch (final NumberFormatException nfe) { - LOGGER.log(Level.FINEST, "Unexplained NFE...", nfe); - } catch (final Exception e) { - LOGGER.log(Level.WARNING, String.format("Could not parse directory name '%s'.", directoryName)); + /** + * Waits until all Hudson slaves are idle. + */ + public static void waitUntilIdle() { + Hudson hudson = Hudson.getInstance(); + final Computer computers[] = hudson.getComputers(); + + boolean running; + do { + running = false; + for (final Computer computer : computers) { + if (computer.countBusy() != 0) { + running = true; + break; + } + } + + try { + Thread.sleep(QUIETMODE_MONITORING_SLEEP); + } catch (final InterruptedException e) { + LOGGER.log(Level.WARNING, e.getMessage(), e); + } + } while (running); } - return result; - } - - /** - * @param displayFormattedDate - * a String in the display format date - * @return the string formatted in the directory names' date format - * @throws ParseException if the beginning of the specified parameter cannot be parsed. - */ - public static String convertToDirectoryNameDateFormat(final String displayFormattedDate) throws ParseException { - final Date displayDate = DISPLAY_DATE_FORMAT.parse(displayFormattedDate); - return DIRECTORY_NAME_DATE_FORMAT.format(displayDate); - } - - /** - * @param parent root directory of all backups - * @param backupType type of backup - * @param date date of backup - * @return a reference to a file in the given parent directory with a name formatted like - * "<BACKUP_TYPE>-yyyy-MM-dd_HH-mm". - */ - public static File getFormattedDirectory(final File parent, final BackupType backupType, final Date date) { - final File formattedDirectory = new File(parent, String.format("%s-%s", backupType, - DIRECTORY_NAME_DATE_FORMAT.format(date))); - return formattedDirectory; - } - - /** - * @param parentDir root directory of all backups - * @param backupType type of backup - * @return an unordered list of backup directories of the given backup type. - */ - public static List getBackupTypeDirectories(final File parentDir, final BackupType backupType) { - IOFileFilter prefixFilter = FileFilterUtils.and( - FileFilterUtils.prefixFileFilter(backupType.toString()), - DirectoryFileFilter.DIRECTORY); - - final File[] existingDirs = parentDir.listFiles((FilenameFilter) prefixFilter); - if (existingDirs == null) { - return Collections.emptyList(); + /** + * Waits until all executors are idle and switch jenkins to quiet mode. If it takes to long that all executors are + * idle because in the mean time other jobs are executed the timeout ensure that the quiet mode is forced. + * + * @param timeout specifies when a quiet mode is forced. 0 = no timeout. + * @param unit specifies the time unit for the value of timeout. + * @throws IOException ? + */ + public static void waitUntilIdleAndSwitchToQuietMode(int timeout, TimeUnit unit) throws IOException { + Hudson hudson = Hudson.getInstance(); + final Computer computers[] = hudson.getComputers(); + + boolean running; + long starttime = System.currentTimeMillis(); + do { + running = false; + for (final Computer computer : computers) { + if (computer.countBusy() != 0) { + running = true; + break; + } + } + + try { + TimeUnit.MILLISECONDS.sleep(QUIETMODE_MONITORING_SLEEP); + } catch (final InterruptedException e) { + LOGGER.log(Level.WARNING, e.getMessage(), e); + } + + if (!hudson.isQuietingDown() && starttime + unit.toMillis(timeout) < System.currentTimeMillis()) { + LOGGER.info("Force quiet mode for jenkins now and wait until all executors are idle."); + hudson.doQuietDown(); + PLUGIN_INITIATED_QUITE_MODE = true; + } + } while (running); } - return Arrays.asList(existingDirs); - } - - /** - * @param parentDir root directory of all backups - * @return an unordered list of zipped backupsets in the given directory. - */ - public static List getBackupSetZipFiles(final File parentDir) { - IOFileFilter zipFileFilter = FileFilterUtils.and( - FileFilterUtils.prefixFileFilter(BackupSet.BACKUPSET_ZIPFILE_PREFIX), - FileFilterUtils.suffixFileFilter(HudsonBackup.ZIP_FILE_EXTENSION), - FileFileFilter.FILE); - - final File[] existingZips = parentDir.listFiles((FilenameFilter) zipFileFilter); - if (existingZips == null) { - return Collections.emptyList(); + /** + * @param directory directory to get the date from + * @return the date component of a directory name formatted in the thinBackup standard + */ + public static Date getDateFromBackupDirectory(final File directory) { + return getDateFromBackupDirectoryName(directory.getName()); } - return Arrays.asList(existingZips); - } + /** + * @param directoryName directory name to get the date from + * @return the date component of a directory name formatted in the thinBackup standard + */ + public static Date getDateFromBackupDirectoryName(final String directoryName) { + Date result = null; - /** - * @param diffBackup diff backup - * @return the full backup referenced by the given diff backup, or null if none can be found. - */ - public static File getReferencedFullBackup(final File diffBackup) { - if (diffBackup.getName().startsWith(BackupType.FULL.toString())) { - return diffBackup; + String dateOnly = ""; + try { + if (directoryName.startsWith(BackupType.FULL.toString()) || directoryName.startsWith(BackupType.DIFF.toString())) { + dateOnly = directoryName.replaceFirst(DIRECTORY_NAME_DATE_EXTRACTION_REGEX, ""); + if (!dateOnly.isEmpty()) { + result = DIRECTORY_NAME_DATE_FORMAT.parse(dateOnly); + } + } + } catch (final NumberFormatException nfe) { + LOGGER.log(Level.FINEST, "Unexplained NFE...", nfe); + } catch (final Exception e) { + LOGGER.log(Level.WARNING, String.format("Could not parse directory name '%s'.", directoryName)); + } + + return result; } - final Collection backups = getBackupTypeDirectories(diffBackup.getParentFile(), BackupType.FULL); + /** + * @param displayFormattedDate a String in the display format date + * @return the string formatted in the directory names' date format + * @throws ParseException if the beginning of the specified parameter cannot be parsed. + */ + public static String convertToDirectoryNameDateFormat(final String displayFormattedDate) throws ParseException { + final Date displayDate = DISPLAY_DATE_FORMAT.parse(displayFormattedDate); + return DIRECTORY_NAME_DATE_FORMAT.format(displayDate); + } - if (backups.isEmpty()) { - return null; + /** + * @param parent root directory of all backups + * @param backupType type of backup + * @param date date of backup + * @return a reference to a file in the given parent directory with a name formatted like + * "<BACKUP_TYPE>-yyyy-MM-dd_HH-mm". + */ + public static File getFormattedDirectory(final File parent, final BackupType backupType, final Date date) { + final File formattedDirectory = new File(parent, String.format("%s-%s", backupType, + DIRECTORY_NAME_DATE_FORMAT.format(date))); + return formattedDirectory; } - File referencedFullBackup = null; - - final Date curBackupDate = getDateFromBackupDirectory(diffBackup); - if (curBackupDate != null) { - Date closestPreviousBackupDate = new Date(0); - for (final File fullBackupDir : backups) { - final Date tmpBackupDate = getDateFromBackupDirectory(fullBackupDir); - if ((tmpBackupDate != null) - && (tmpBackupDate.after(closestPreviousBackupDate) && (tmpBackupDate.getTime() <= curBackupDate.getTime()))) { - closestPreviousBackupDate = tmpBackupDate; - referencedFullBackup = fullBackupDir; + /** + * @param parentDir root directory of all backups + * @param backupType type of backup + * @return an unordered list of backup directories of the given backup type. + */ + public static List getBackupTypeDirectories(final File parentDir, final BackupType backupType) { + IOFileFilter prefixFilter = FileFilterUtils.and( + FileFilterUtils.prefixFileFilter(backupType.toString()), + DirectoryFileFilter.DIRECTORY); + + final File[] existingDirs = parentDir.listFiles((FilenameFilter) prefixFilter); + if (existingDirs == null) { + return Collections.emptyList(); } - } + + return Arrays.asList(existingDirs); } - return referencedFullBackup; - } - - /** - * @param fullBackup fill backup - * @return a list of all diff backups which reference the given full backup. - */ - public static List getReferencingDiffBackups(final File fullBackup) { - final List diffBackups = new ArrayList(); - if (fullBackup.getName().startsWith(BackupType.DIFF.toString())) { - return diffBackups; + /** + * @param parentDir root directory of all backups + * @return an unordered list of zipped backupsets in the given directory. + */ + public static List getBackupSetZipFiles(final File parentDir) { + IOFileFilter zipFileFilter = FileFilterUtils.and( + FileFilterUtils.prefixFileFilter(BackupSet.BACKUPSET_ZIPFILE_PREFIX), + FileFilterUtils.suffixFileFilter(HudsonBackup.ZIP_FILE_EXTENSION), + FileFileFilter.FILE); + + final File[] existingZips = parentDir.listFiles((FilenameFilter) zipFileFilter); + if (existingZips == null) { + return Collections.emptyList(); + } + + return Arrays.asList(existingZips); } - final Collection allDiffBackups = getBackupTypeDirectories(fullBackup.getParentFile(), BackupType.DIFF); + /** + * @param diffBackup diff backup + * @return the full backup referenced by the given diff backup, or null if none can be found. + */ + public static File getReferencedFullBackup(final File diffBackup) { + if (diffBackup.getName().startsWith(BackupType.FULL.toString())) { + return diffBackup; + } + + final Collection backups = getBackupTypeDirectories(diffBackup.getParentFile(), BackupType.FULL); - for (final File diffBackup : allDiffBackups) { - final File tmpFullBackup = getReferencedFullBackup(diffBackup); - if ((tmpFullBackup != null) && (tmpFullBackup.getAbsolutePath().equals(fullBackup.getAbsolutePath()))) { - diffBackups.add(diffBackup); - } + if (backups.isEmpty()) { + return null; + } + + File referencedFullBackup = null; + + final Date curBackupDate = getDateFromBackupDirectory(diffBackup); + if (curBackupDate != null) { + Date closestPreviousBackupDate = new Date(0); + for (final File fullBackupDir : backups) { + final Date tmpBackupDate = getDateFromBackupDirectory(fullBackupDir); + if ((tmpBackupDate != null) + && (tmpBackupDate.after(closestPreviousBackupDate) && (tmpBackupDate.getTime() <= curBackupDate.getTime()))) { + closestPreviousBackupDate = tmpBackupDate; + referencedFullBackup = fullBackupDir; + } + } + } + + return referencedFullBackup; } - return diffBackups; - } - - /** - * @param directory root directory of all backups - * @return a list of backups in the given directory (both FULL and DIFF), displayed as the respective backup date, - * from both directories and ZIP files, ordered descending by the date encoded in the backups' name. - */ - public static List getBackupsAsDates(final File directory) { - final List backupDates = new ArrayList(); - - final List backupSets = getValidBackupSets(directory); - for (final BackupSet backupSet : backupSets) { - final String fullName = backupSet.getFullBackupName(); - try { - final Date tmp = getDateFromBackupDirectoryName(fullName); - if (tmp != null) { - backupDates.add(DISPLAY_DATE_FORMAT.format(tmp)); - } else { - throw new ParseException("", 0); + /** + * @param fullBackup fill backup + * @return a list of all diff backups which reference the given full backup. + */ + public static List getReferencingDiffBackups(final File fullBackup) { + final List diffBackups = new ArrayList(); + if (fullBackup.getName().startsWith(BackupType.DIFF.toString())) { + return diffBackups; } - } catch (final ParseException e) { - LOGGER.warning(String.format( - "Cannot parse directory name '%s' , therefore it will not show up in the list of available backups.", - fullName)); - } - for (final String diffName : backupSet.getDiffBackupsNames()) { - try { - final Date tmp = getDateFromBackupDirectoryName(diffName); - if (tmp != null) { - backupDates.add(DISPLAY_DATE_FORMAT.format(tmp)); - } else { - throw new ParseException("", 0); - } - } catch (final ParseException e) { - LOGGER.warning(String.format( - "Cannot parse directory name '%s' , therefore it will not show up in the list of available backups.", - diffName)); + final Collection allDiffBackups = getBackupTypeDirectories(fullBackup.getParentFile(), BackupType.DIFF); + + for (final File diffBackup : allDiffBackups) { + final File tmpFullBackup = getReferencedFullBackup(diffBackup); + if ((tmpFullBackup != null) && (tmpFullBackup.getAbsolutePath().equals(fullBackup.getAbsolutePath()))) { + diffBackups.add(diffBackup); + } } - } + + return diffBackups; } - Collections.sort(backupDates); - Collections.reverse(backupDates); - - return backupDates; - } - - /** - * @param directory root directory of all backups - * @return a list of valid (@see BackupSet#isValid) backup sets that exists as directories (not as ZIP files) in the - * given directory, ordered ascending by the backup date of the BackupSets' full backup. - */ - public static List getValidBackupSetsFromDirectories(final File directory) { - final Collection backups = Utils.getBackupTypeDirectories(directory, BackupType.FULL); - - final List validSets = new ArrayList(); - for (final File backup : backups) { - final BackupSet set = new BackupSet(backup); - if (set.isValid()) { - validSets.add(set); - } + /** + * @param directory root directory of all backups + * @return a list of backups in the given directory (both FULL and DIFF), displayed as the respective backup date, + * from both directories and ZIP files, ordered descending by the date encoded in the backups' name. + */ + public static List getBackupsAsDates(final File directory) { + final List backupDates = new ArrayList(); + + final List backupSets = getValidBackupSets(directory); + for (final BackupSet backupSet : backupSets) { + final String fullName = backupSet.getFullBackupName(); + try { + final Date tmp = getDateFromBackupDirectoryName(fullName); + if (tmp != null) { + backupDates.add(DISPLAY_DATE_FORMAT.format(tmp)); + } else { + throw new ParseException("", 0); + } + } catch (final ParseException e) { + LOGGER.warning(String.format( + "Cannot parse directory name '%s' , therefore it will not show up in the list of available backups.", + fullName)); + } + + for (final String diffName : backupSet.getDiffBackupsNames()) { + try { + final Date tmp = getDateFromBackupDirectoryName(diffName); + if (tmp != null) { + backupDates.add(DISPLAY_DATE_FORMAT.format(tmp)); + } else { + throw new ParseException("", 0); + } + } catch (final ParseException e) { + LOGGER.warning(String.format( + "Cannot parse directory name '%s' , therefore it will not show up in the list of available backups.", + diffName)); + } + } + } + + Collections.sort(backupDates); + Collections.reverse(backupDates); + + return backupDates; } - Collections.sort(validSets); - - return validSets; - } - - /** - * @param directory root directory of all backups - * @return a list of valid (@see BackupSet#isValid) backup sets that exists as ZIP files (not as directories) in the - * given directory, ordered ascending by the backup date of the BackupSets' full backup. - */ - public static List getValidBackupSetsFromZips(final File directory) { - final Collection backups = Utils.getBackupSetZipFiles(directory); - - final List validSets = new ArrayList(); - for (final File backup : backups) { - final BackupSet set = new BackupSet(backup); - if (set.isValid()) { - validSets.add(set); - } + + /** + * @param directory root directory of all backups + * @return a list of valid (@see BackupSet#isValid) backup sets that exists as directories (not as ZIP files) in the + * given directory, ordered ascending by the backup date of the BackupSets' full backup. + */ + public static List getValidBackupSetsFromDirectories(final File directory) { + final Collection backups = Utils.getBackupTypeDirectories(directory, BackupType.FULL); + + final List validSets = new ArrayList(); + for (final File backup : backups) { + final BackupSet set = new BackupSet(backup); + if (set.isValid()) { + validSets.add(set); + } + } + Collections.sort(validSets); + + return validSets; } - Collections.sort(validSets); - - return validSets; - } - - /** - * @param directory root directory of all backups - * @return a list of valid (@see BackupSet#isValid) backup sets in the given directory, ordered ascending by the - * backup date of the BackupSets' full backup. - */ - public static List getValidBackupSets(final File directory) { - final List validSets = new ArrayList(); - - validSets.addAll(getValidBackupSetsFromDirectories(directory)); - validSets.addAll(getValidBackupSetsFromZips(directory)); - Collections.sort(validSets); - - return validSets; - } - - /** - * Moves all backup sets (that are not already zipped) other than the one containing currentBackup to ZIP files - * located in backupRoot. - * - * @param backupRoot root directory of all backups - * @param currentBackup - * specified which backup should be omitted from being moved. If null, all backups are moved to ZIP files. - */ - public static void moveOldBackupsToZipFile(final File backupRoot, final File currentBackup) { - LOGGER.fine("Moving old backups to zip files..."); - - final List validBackupSets = Utils.getValidBackupSetsFromDirectories(backupRoot); - int numberOfZippedBackupSets = 0; - int numberOfMovedBackupSets = 0; - for (final BackupSet backupSet : validBackupSets) { - if ((!backupSet.containsDirectory(currentBackup)) && (!backupSet.isInZipFile())) { - final File zippedBackupSet = backupSet.zipTo(backupRoot); - ++numberOfZippedBackupSets; - if (zippedBackupSet != null) { - LOGGER.fine(String.format("Successfully zipped backup set %s to '%s'.", backupSet, - zippedBackupSet.getAbsolutePath())); - try { - backupSet.delete(); - LOGGER.fine(String.format("Deleted backup set %s after zipping it.", backupSet)); - ++numberOfMovedBackupSets; - } catch (final IOException ioe) { - LOGGER.log(Level.WARNING, String.format("Could not delete backup set %s.", backupSet)); - } + + /** + * @param directory root directory of all backups + * @return a list of valid (@see BackupSet#isValid) backup sets that exists as ZIP files (not as directories) in the + * given directory, ordered ascending by the backup date of the BackupSets' full backup. + */ + public static List getValidBackupSetsFromZips(final File directory) { + final Collection backups = Utils.getBackupSetZipFiles(directory); + + final List validSets = new ArrayList(); + for (final File backup : backups) { + final BackupSet set = new BackupSet(backup); + if (set.isValid()) { + validSets.add(set); + } } - } + Collections.sort(validSets); + + return validSets; } - if (numberOfMovedBackupSets == numberOfZippedBackupSets) { - LOGGER.info(String.format("DONE moving %d backup set(s) to ZIP files.", numberOfMovedBackupSets)); - } else { - LOGGER - .info(String - .format( - "DONE zipping %d backup set(s). %d of those could be moved to ZIP files, the rest remain as files/directories as well.", - numberOfZippedBackupSets, numberOfMovedBackupSets)); + /** + * @param directory root directory of all backups + * @return a list of valid (@see BackupSet#isValid) backup sets in the given directory, ordered ascending by the + * backup date of the BackupSets' full backup. + */ + public static List getValidBackupSets(final File directory) { + final List validSets = new ArrayList(); + + validSets.addAll(getValidBackupSetsFromDirectories(directory)); + validSets.addAll(getValidBackupSetsFromZips(directory)); + Collections.sort(validSets); + + return validSets; } - } - - public static String expandEnvironmentVariables(final String path) throws EnvironmentVariableNotDefinedException { - return internalExpandEnvironmentVariables(path, System.getenv()); - } - - // For unit testing purposes only. Use @link {expandEnvironmentVariables}. - protected static String internalExpandEnvironmentVariables(final String path, - final Map environmentVariables) throws EnvironmentVariableNotDefinedException { - - String tmpPath = path; - final StringBuilder newPath = new StringBuilder(); - boolean done = false; - while (!done) { - if (tmpPath.contains(START_ENV_VAR_TOKEN)) { - final int startIdx = tmpPath.indexOf(START_ENV_VAR_TOKEN); - final int endIdx = tmpPath.indexOf(END_ENV_VAR_TOKEN, startIdx + START_ENV_VAR_TOKEN.length()); - - if (endIdx != -1) { - final String envVar = tmpPath.substring(startIdx + START_ENV_VAR_TOKEN.length(), endIdx); - final String envVarValue = environmentVariables.get(envVar); - if (envVarValue == null) { - final String message = String - .format( - "Environment variable '%s' was specified in path '%s', but it is not defined in the system's environment variables.", - envVar, path); - throw new EnvironmentVariableNotDefinedException(message); - } - newPath.append(tmpPath.substring(0, startIdx)); - newPath.append(envVarValue); - tmpPath = tmpPath.substring(endIdx + END_ENV_VAR_TOKEN.length()); - } else { - newPath.append(tmpPath); - done = true; + + /** + * Moves all backup sets (that are not already zipped) other than the one containing currentBackup to ZIP files + * located in backupRoot. + * + * @param backupRoot root directory of all backups + * @param currentBackup specified which backup should be omitted from being moved. If null, all backups are moved to ZIP files. + */ + public static void moveOldBackupsToZipFile(final File backupRoot, final File currentBackup) { + LOGGER.fine("Moving old backups to zip files..."); + + final List validBackupSets = Utils.getValidBackupSetsFromDirectories(backupRoot); + int numberOfZippedBackupSets = 0; + int numberOfMovedBackupSets = 0; + for (final BackupSet backupSet : validBackupSets) { + if ((!backupSet.containsDirectory(currentBackup)) && (!backupSet.isInZipFile())) { + final File zippedBackupSet = backupSet.zipTo(backupRoot); + ++numberOfZippedBackupSets; + if (zippedBackupSet != null) { + LOGGER.fine(String.format("Successfully zipped backup set %s to '%s'.", backupSet, + zippedBackupSet.getAbsolutePath())); + try { + backupSet.delete(); + LOGGER.fine(String.format("Deleted backup set %s after zipping it.", backupSet)); + ++numberOfMovedBackupSets; + } catch (final IOException ioe) { + LOGGER.log(Level.WARNING, String.format("Could not delete backup set %s.", backupSet)); + } + } + } } - if (tmpPath.isEmpty()) { - done = true; + + if (numberOfMovedBackupSets == numberOfZippedBackupSets) { + LOGGER.info(String.format("DONE moving %d backup set(s) to ZIP files.", numberOfMovedBackupSets)); + } else { + LOGGER + .info(String + .format( + "DONE zipping %d backup set(s). %d of those could be moved to ZIP files, the rest remain as files/directories as well.", + numberOfZippedBackupSets, numberOfMovedBackupSets)); } - } else { - newPath.append(tmpPath); - done = true; - } } - return newPath.toString(); - } + public static String expandEnvironmentVariables(final String path) throws EnvironmentVariableNotDefinedException { + return internalExpandEnvironmentVariables(path, System.getenv()); + } + + // For unit testing purposes only. Use @link {expandEnvironmentVariables}. + protected static String internalExpandEnvironmentVariables(final String path, + final Map environmentVariables) throws EnvironmentVariableNotDefinedException { + + String tmpPath = path; + final StringBuilder newPath = new StringBuilder(); + boolean done = false; + while (!done) { + if (tmpPath.contains(START_ENV_VAR_TOKEN)) { + final int startIdx = tmpPath.indexOf(START_ENV_VAR_TOKEN); + final int endIdx = tmpPath.indexOf(END_ENV_VAR_TOKEN, startIdx + START_ENV_VAR_TOKEN.length()); + + if (endIdx != -1) { + final String envVar = tmpPath.substring(startIdx + START_ENV_VAR_TOKEN.length(), endIdx); + final String envVarValue = environmentVariables.get(envVar); + if (envVarValue == null) { + final String message = String + .format( + "Environment variable '%s' was specified in path '%s', but it is not defined in the system's environment variables.", + envVar, path); + throw new EnvironmentVariableNotDefinedException(message); + } + newPath.append(tmpPath.substring(0, startIdx)); + newPath.append(envVarValue); + tmpPath = tmpPath.substring(endIdx + END_ENV_VAR_TOKEN.length()); + } else { + newPath.append(tmpPath); + done = true; + } + if (tmpPath.isEmpty()) { + done = true; + } + } else { + newPath.append(tmpPath); + done = true; + } + } - public static void waitUntilFileCanBeRead(File f) { - while (!f.canRead()) { - try { - Thread.sleep(SLEEP_TIMEOUT); - } catch (InterruptedException e) { - // nothing to do - } + return newPath.toString(); + } + + public static void waitUntilFileCanBeRead(File f) { + while (!f.canRead()) { + try { + Thread.sleep(SLEEP_TIMEOUT); + } catch (InterruptedException e) { + // nothing to do + } + } + } + public static boolean isQuiteDownOngoingButNeedsToCancel(final boolean waitForIdle, final Jenkins jenkinsInstance) { + if (jenkinsInstance != null) + return !waitForIdle && jenkinsInstance.isQuietingDown() && Utils.isPluginInitiatedQuiteMode(); + return false; } - } }