[Pythonmac-SIG] ZipFile revision....

Schollnick, Benjamin Benjamin.Schollnick at xerox.com
Wed Apr 27 16:58:26 CEST 2005


Folks,

	There's been a lot of talk lately about changes to the ZipFile 
module...  Along with people stating that there are few "real life"
applications for it....

	Here's a small "gift"...

	A "Quick" Backup utility for your files....

	Example:

c:\develope\backup\backup.py --source c:\install_software 	--target
c:\backups\ 	 --label installers
c:\develope\backup\backup.py --source c:\develope 		--target
c:\backups\ 	 --label development -z .pyc
c:\develope\backup\backup.py --source "C:\Program Files\Microsoft SQL
Server\MSSQL\Data"  --target c:\backups\	--label sql

	It's evolved a bit, but still could use some work....  It's
currently only tested in a windows
environment...  So don't expect Mac OS X resource forks to be
preserved.....  But it creates and verifies 1Gb+ zip files....

	If you wish to use this to help benchmark, test, etc, any
changes to the ZipFile module
please feel free to...

		- Benjamin


"""Backup Creator Utility

This utility will backup the tree of files that you indicate, into a
archive
of your choice.

"""
#

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
__version__ = '0.95'    # Human Readable Version number
version_info = (0,9,5)  # Easier format version data for comparisons
                        # i.e. if version_info > (1,2,5)
                        #
                        #   if __version__ > '1.00' is a little more
contrived.
                        
__author__  = 'Benjamin A. Schollnick'
__date__    = '2004-12-28'  # yyyy-mm-dd
__email__   = 'Benjamin.Schollnick at xerox.com'
__module_name__ = "Archive Backup Tool"
__short_cright__= ""

import  bas_init
import os
import os.path
import sys
import time
import zipfile


#######################################################################
class   zip_file_engine:
    """The archive backup tool uses pregenerated classes to allow
    multiple styles of archives to be created.

    This is the wrapper around the Python ZIPFILE module.
    """
    def     __init__       ( self ):
        """
        Inputs  --
                    None
                                    
        Outputs --
                    None
        """
        self.Backup_File        = None
        self.Backup_Open        = False
        self.Backup_ReadOnly    = None
        self.Backup_FileName    = None

    def     close_Backup (self ):
        """This will close the current Archive file, and reset the
        internal structures to a clean state.

        Inputs  --
                    None
                                    
        Outputs --
                    None
        """
        if self.Backup_Open <> False:
            self.Backup_File.close ()

        self.Backup_File        = None            
        self.Backup_Open        = False
        self.Backup_ReadOnly    = None
        self.Backup_FileName    = None
        
    def     open_Backup (   self,
                            readonly = False,
                            filename = r"./temp.zip"):
        """This will open a archive file.  Currently appending is not
        formally supported...  The Read Only / Read/Write status is set
        via the readonly flag.

        Inputs  --

            Readonly:
                    True  = Read/Write
                    False = Read Only

            Filename contains the full file/pathname of the zip file.
                                    
        Outputs --
                    None
        """
        if self.Backup_Open == True:
            self.close_Backup ()

        self.Backup_Filename = filename
        if readonly == False:
            self.Backup_File        = zipfile.ZipFile ( filename, "r",
zipfile.ZIP_DEFLATED )
            self.Backup_Open        = True
            self.Backup_ReadOnly    = True
            self.Backup_FileName    = filename
        else:
            self.Backup_File        = zipfile.ZipFile ( filename, "w",
zipfile.ZIP_DEFLATED )
            self.Backup_Open        = True
            self.Backup_ReadOnly    = False
            self.Backup_FileName    = filename

    def     Verify_ZipFile ( self, FileName ):
            """Will create a temporary Zip File object, and verify the
Zip file
            at <filename> location.

            Inputs  -
                        FileName - The filename of the ZIP file to
verify.

            Outputs -
                        True  - File Intact CRCs match

                        Anything else, File Corrupted.  String Contains
the 1st corrupted file.
            """
            temporary_Backup_File = zip_file_engine ( )
            temporary_Backup_File.open_Backup ( False, FileName)
            test_results = temporary_Backup_File.Backup_File.testzip ()
            temporary_Backup_File.close_Backup()
            return test_results        

    def     Verify_Backup (self, FileName ):
            """ Generic Wrapper around the Verify_ZipFile object.
            """
            return self.Verify_ZipFile ( FileName )
            
    def     add_file_to_Backup ( self, filename, archived_filename):
            """Add a file to the writable Zip file.

                inputs -
                
                    filename = Filename of the file to be added
    
                    archived_filename = the Filename stored in the
archive.


                Outputs -

                    None    - Zip file is in Read Only Mode

                    True    - File has been added to the Zip File.
                    
                      -1    - Or the Zipfile engine is not initialized.
            """
            if self.Backup_ReadOnly:
                #   Archive is read only!
                return None
            elif self.Backup_ReadOnly == False:
                #   Archive is Read Write Mode
                if self.Backup_File <> None:
                    #   Zip File Engine is initialized
                    self.Backup_File.write (filename, archived_filename)
                    #   Return Success
                    return True
                else:
                    #   Zip File Engine is *NOT* initialized.
                    return -1


        

########################################################################
#
No_Archive = 1
ZIP  = 2
        
class   backup_system:
    """Main Class for the Backup Engine.

    Inputs  -
                default_source  = The pathname for the source files.
                default_target  = The pathname for the archive to be
written to.
                default_tag     = the prepended text tag for the archive
file.

    Outputs -

            None
            
    """
    def     __init__ (  self,
                        default_source  = None,
                        default_target  = None,
                        default_exclude = "",
                        default_extensions = "",
                        default_tag     = None,
                        prepend         = False,
                        quiet           = False):
        """The initialization routines for the Backup Engine.

        Inputs  -
                    default_source  = The pathname for the source files.
                    default_target  = The pathname for the archive to be
written to.
                    default_exclude = 
                    default_tag     = the text tag for the archive file.
                    prepend         = Deterimines the placement of the
default tag.

                                        True - The tag is prepended to
the filename
                                        False - The Tag is appended to
the filename.

                                        The default is to append the
default_tag.  (False)

                    quiet           = Forcibly prevent any output from
the directory walk.

        Outputs -

                None;  Internal Values are initialized for the core
engine.
                
        """
        
        self.directory_to_backup        = default_source
        self.backup_storage_location    = default_target
        self.base_filename              = default_tag
        self.archive_filename           = None
        self.force_quiet                = quiet
#        self.exlude_files_dir           = default_exlude

        self.exclude_files_dir           =
default_exclude.upper().strip().split(",")
        self.exclude_exts                =
default_extensions.upper().strip().split(",")
        
        if default_tag == None:
            self.archive_filename_template  = "%m_%d_%Y__%H_%M_%S"
        else:
            if (prepend==True):
                self.archive_filename_template  = self.base_filename +
"_%m_%d_%Y__%H_%M_%S"
            elif (prepend==None) or (prepend==False):
                self.archive_filename_template  = "%m_%d_%Y__%H_%M_%S_"
+ self.base_filename

                
        self.archive_filename_extension = ".zip"
        self.archive_engine_to_use      = None
        

    def     create_archive_filename  ( self ):
        """This sets the archive filename in the object.

        This is set, to prevent timing issues internally.

        Inputs -

                None

        Outputs -

                None;  Internally creates the archives filename from the
backup_storage_location,
                and the archive_filename_template.
        """
        self.archive_filename = self.backup_storage_location + os.sep +
time.strftime (self.archive_filename_template, time.localtime() ) +
self.archive_filename_extension


    def     Verify_Backup ( self ):
        """ Wrapper around the archive_engines verify routines.

        This will automatically start the verification process, and
        return the results.

        Inputs -

                    None

        Outputs -

                    True  - File Intact CRCs match

                    Anything else, File Corrupted.  String Contains
details from the
                    archiver engine.
                    
        """
        return self.archive_engine_to_use.Verify_Backup (
self.archive_filename )
    

    def     start_archive_engine ( self, Backup_Type):
        """ Initializae the derived archive_engine, depending on the
Backup_Type.

        Inputs -
                Backup_Type
                    1  - None
                    2  - Zip

        Outputs -

                None
                
        """
        if Backup_Type == 2:
            self.archive_engine_to_use = zip_file_engine ()

        self.create_archive_filename ()
        self.archive_engine_to_use.open_Backup (   readonly = True,
filename = self.archive_filename )

    def     close_archive_file ( self ):
        """Stop and Close the Archive File.

        This does terminate the Archive Engine.
        But does not terminate the Backup_Engine.

        Inputs -
                    None

        Outputs -
                    None; Internally resets the archive engine to a
closed state.
                    
        """
        self.archive_engine_to_use.close_Backup ()

    def     walk_directory_tree ( self, notify_directory = None,
notify_file = None ):
        """Walk the source directory tree, and add each file/directory
into the archive file.

        Inputs -

            notify_directory    (Pointer)   - see below
            notify_file         (Pointer)   - see below

        Outputs -

            None


        If you wish to have a console output for the walk function, you
can
        have that via the notify_directory and notify_file functions....

        Create two stubs and pass them to the walk routine.  The
routines only have
        a single input, either a directory name, or a filename,
depending on the
        function.

            def     notify_dir ( directory_name ):
                print
                print "Processing Directory - %s " % directory_name


            def     notify_file ( file_name ):
                print "\t\tFile - %s " % file_name
        
        Backup_Engine.walk_directory_tree ( notify_directory =
notify_dir, notify_file = notify_file )
        """
        selfexclude = os.path.normpath(self.archive_filename)

        if self.force_quiet:
            notify_directory    = None
            notify_file         = None
            
        for root, dirs, files in os.walk( self.directory_to_backup ):
            if notify_directory <> None:
                notify_directory ( root )
            for file in files:
                if notify_file <> None:
                    notify_file ( file )
                #
                #   Add the file to the backup zip file.

#                if os.path.normpath(file) <> selfexclude:
#                    self.archive_engine_to_use.add_file_to_Backup (
root + os.sep + file, root + os.sep + file)
#                else:
#                     print "Skipping, it is backup file - %s" % file
                exclude_file = False

                if os.path.normpath(file) == selfexclude:
                    exclude_file = True

                if file.strip().upper() in self.exclude_files_dir:
                    exclude_file = True

                if root <> '.':
                    root_segment = root.strip().upper().split(os.sep)
                    for x in root_segment:
                        if x in self.exclude_files_dir:
                            exclude_file = True

#self.exclude_exts
                for x in self.exclude_exts:
                    #print "X: ", x.strip(), " - ", os.path.splitext(
file )[1].upper().strip()
                    #print  x.strip() == os.path.splitext( file
)[1].upper().strip()
                    if x.strip() == os.path.splitext( file
)[1].upper().strip():
                        exclude_file = True

                if not exclude_file:
                    self.archive_engine_to_use.add_file_to_Backup ( root
+ os.sep + file, root + os.sep + file)
#                else:
#                     print "Skipping - %s" % file

                exclude_file = False
                
def     notify_dir ( directory_name ):
    print
    print "Processing Directory - %s " % directory_name

def     notify_file ( file_name ):
    print "\t\tFile - %s " % file_name
    
            
def     Backup_Directories_App ():
    """Example Application that will backup the Directories as stated in
the command line.

    Inputs -
                None

    Outputs -

                None;  FileSystem, Archive file.


    """    
    initialization_data  = bas_init.initialization_wrapper ()
    
    initialization_data.cmd_line_interface.add_option ("-s", "--source",
action="store", type="string", dest="source", help="Directory Tree to
Read From", default=".")
    initialization_data.cmd_line_interface.add_option ("-t", "--target",
action="store", type="string", dest="target", help="Directory to write
the backup to", default=".")
    initialization_data.cmd_line_interface.add_option ("-l", "--label",
action="store", type="string", dest="label", help="What to Label the
Backup File as", default="backup")
    initialization_data.cmd_line_interface.add_option ("-p", "--pre",
action="store_true", dest="prelabel", help="If used, the label is
prepended to the filename.  Otherwise it is appended.")
    initialization_data.cmd_line_interface.add_option ("-q", "--quiet",
action="store_true", dest="quiet", help="Force File & Directory printing
to be turned off.")
    initialization_data.cmd_line_interface.add_option ("-x",
"--exclude", action="store", type="string", dest="exclude", help="List
of files/directories to exclude", default="")
    initialization_data.cmd_line_interface.add_option ("-z",
"--extensions", action="store", type="string", dest="exclude_exts",
help="List of file extensions to exclude", default="")
    initialization_data.run_cmd_line_parse ( )

    print "Initialization Successful..."
    print

    Backup_Engine = backup_system (
initialization_data.cmd_line_options.source,
 
initialization_data.cmd_line_options.target,
 
initialization_data.cmd_line_options.exclude,
 
initialization_data.cmd_line_options.exclude_exts,
 
initialization_data.cmd_line_options.label,
 
initialization_data.cmd_line_options.prelabel,
 
initialization_data.cmd_line_options.quiet)
        
    Backup_Engine.start_archive_engine ( ZIP )


    print "Backup Archive - %s " % Backup_Engine.archive_filename
    
    Backup_Engine.walk_directory_tree ( notify_directory = notify_dir,
notify_file = notify_file )
    Backup_Engine.close_archive_file ()

    print "Verifying the Archive File...."
    if Backup_Engine.Verify_Backup ( ):
        print
        print "The Backup has failed!"
        print
        print "This file, %s, is bad." % test
    else:
        print
        print "The Backup has been verified!"
        print
        print "Backup is successful."
    print
    print "Backup Application has completed."

if __name__ == "__main__":      #   If run from the Command line
    Backup_Directories_App ()   #   run the unit test.
    
    


More information about the Pythonmac-SIG mailing list