[Python-Dev] 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 Python-Dev
mailing list