CedarBackup3.actions.rebuild — Cedar Backup v3 documentation

# Source code for CedarBackup3.actions.rebuild

    # -*- coding: iso-8859-1 -*-
    # vim: set ft=python ts=3 sw=3 expandtab:
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    #
    #              C E D A R
    #          S O L U T I O N S       "Software done right."
    #           S O F T W A R E
    #
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    #
    # Copyright (c) 2004-2007,2010,2015 Kenneth J. Pronovici.
    # All rights reserved.
    #
    # This program is free software; you can redistribute it and/or
    # modify it under the terms of the GNU General Public License,
    # Version 2, as published by the Free Software Foundation.
    #
    # 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.
    #
    # Copies of the GNU General Public License are available from
    # the Free Software Foundation website, http://www.gnu.org/.
    #
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
    #
    # Author   : Kenneth J. Pronovici <pronovic@ieee.org>
    # Language : Python 3 (>= 3.4)
    # Project  : Cedar Backup, release 3
    # Purpose  : Implements the standard 'rebuild' action.
    #
    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

    ########################################################################
    # Module documentation
    ########################################################################

    """
    Implements the standard 'rebuild' action.
    :author: Kenneth J. Pronovici <pronovic@ieee.org>
    """

    ########################################################################
    # Imported modules
    ########################################################################

    # System modules
    import sys
    import os
    import logging
    import datetime

    # Cedar Backup modules
    from CedarBackup3.util import deriveDayOfWeek
    from CedarBackup3.actions.util import checkMediaState
    from CedarBackup3.actions.constants import DIR_TIME_FORMAT, STAGE_INDICATOR
    from CedarBackup3.actions.store import writeImage, writeStoreIndicator, consistencyCheck

    ########################################################################
    # Module-wide constants and variables
    ########################################################################

    logger = logging.getLogger("CedarBackup3.log.actions.rebuild")

    ########################################################################
    # Public functions
    ########################################################################

    ############################
    # executeRebuild() function
    ############################

    # pylint: disable=W0613
    def executeRebuild(configPath, options, config):
       """
       Executes the rebuild backup action.

       This function exists mainly to recreate a disc that has been "trashed" due
       to media or hardware problems.  Note that the "stage complete" indicator
       isn't checked for this action.

       Note that the rebuild action and the store action are very similar.  The
       main difference is that while store only stores a single day's staging
       directory, the rebuild action operates on multiple staging directories.

       Args:
          configPath (String representing a path on disk): Path to configuration file on disk
          options (Options object): Program command-line options
          config (Config object): Program configuration
       Raises:
          ValueError: Under many generic error conditions
          IOError: If there are problems reading or writing files
       """
       logger.debug("Executing the 'rebuild' action.")
       if sys.platform == "darwin":
          logger.warning("Warning: the rebuild action is not fully supported on Mac OS X.")
          logger.warning("See the Cedar Backup software manual for further information.")
       if config.options is None or config.store is None:
          raise ValueError("Rebuild configuration is not properly filled in.")
       if config.store.checkMedia:
          checkMediaState(config.store)  # raises exception if media is not initialized
       stagingDirs = _findRebuildDirs(config)
       writeImage(config, True, stagingDirs)
       if config.store.checkData:
          if sys.platform == "darwin":
             logger.warning("Warning: consistency check cannot be run successfully on Mac OS X.")
             logger.warning("See the Cedar Backup software manual for further information.")
          else:
             logger.debug("Running consistency check of media.")
             consistencyCheck(config, stagingDirs)
       writeStoreIndicator(config, stagingDirs)
       logger.info("Executed the 'rebuild' action successfully.")

    ########################################################################
    # Private utility functions
    ########################################################################

    ##############################
    # _findRebuildDirs() function
    ##############################

    def _findRebuildDirs(config):
       """
       Finds the set of directories to be included in a disc rebuild.

       A the rebuild action is supposed to recreate the "last week's" disc.  This
       won't always be possible if some of the staging directories are missing.
       However, the general procedure is to look back into the past no further than
       the previous "starting day of week", and then work forward from there trying
       to find all of the staging directories between then and now that still exist
       and have a stage indicator.

       Args:
          config: Config object

       Returns:
           Correct staging dir, as a dict mapping directory to date suffix
       Raises:
          IOError: If we do not find at least one staging directory
       """
       stagingDirs = {}
       start = deriveDayOfWeek(config.options.startingDay)
       today = datetime.date.today()
       if today.weekday() >= start:
          days = today.weekday() - start + 1
       else:
          days = 7 - (start - today.weekday()) + 1
       for i in range (0, days):
          currentDay = today - datetime.timedelta(days=i)
          dateSuffix = currentDay.strftime(DIR_TIME_FORMAT)
          stageDir = os.path.join(config.store.sourceDir, dateSuffix)
          indicator = os.path.join(stageDir, STAGE_INDICATOR)
          if os.path.isdir(stageDir) and os.path.exists(indicator):
             logger.info("Rebuild process will include stage directory [%s]", stageDir)
             stagingDirs[stageDir] = dateSuffix
       if len(stagingDirs) == 0:
          raise IOError("Unable to find any staging directories for rebuild process.")
       return stagingDirs