Gaudi Framework, version v22r0

Home   Generated: 9 Feb 2011

ZipPythonDir.py

Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 ## file ZipPythonDir.py
00004 #  Script to generate a zip file that can replace a directory in the python path.
00005 
00006 import os, sys, zipfile, logging, stat, time
00007 from StringIO import StringIO
00008 
00009 # Add to the path the entry needed to import the locker module.
00010 import locker
00011 
00012 ## Class for generic exception coming from the zipdir() function
00013 class ZipdirError(RuntimeError):
00014     pass
00015 
00016 ## Collect the changes to be applied to the zip file.
00017 #
00018 #  @param directory: directory to be packed in the zip file
00019 #  @param infolist: list of ZipInfo objects already contained in the zip archive
00020 #
00021 #  @return: tuple of (added, modified, untouched, removed) entries in the directory with respect to the zip file
00022 #
00023 def _zipChanges(directory, infolist):
00024     # gets the dates of the files in the zip archive
00025     infos = {}
00026     for i in infolist:
00027         fn = i.filename
00028         if fn.endswith(".pyc"):
00029             fn = fn[:-1]
00030         infos[fn] = i.date_time
00031 
00032     # gets the changes
00033     added = []
00034     modified = []
00035     untouched = []
00036     removed = []
00037     all_files = set()
00038 
00039     log = logging.getLogger("zipdir")
00040     dirlen = len(directory) + 1
00041     for root, dirs, files in os.walk(directory):
00042         if "lib-dynload" in dirs:
00043             # exclude the directory containing binary modules
00044             dirs.remove("lib-dynload")
00045         arcdir = root[dirlen:]
00046         for f in files:
00047             ext = os.path.splitext(f)[1]
00048             if ext == ".py": # extensions that can enter the zip file
00049                 filename = os.path.join(arcdir, f)
00050                 all_files.add(filename)
00051                 if filename not in infos:
00052                     action = "A"
00053                     added.append(filename)
00054                 else:
00055                     filetime = time.localtime(os.stat(os.path.join(directory,filename))[stat.ST_MTIME])[:6]
00056                     if filetime > infos[filename]:
00057                         action = "M"
00058                         modified.append(filename)
00059                     else:
00060                         action = "U"
00061                         untouched.append(filename)
00062                 if action in ['U']:
00063                     log.debug(" %s -> %s", action, filename)
00064                 else:
00065                     log.info(" %s -> %s", action, filename)
00066             elif ext not in [".pyc", ".pyo", ".stamp", ".cmtref"]: # extensions that can be ignored
00067                 raise ZipdirError("Cannot add '%s' to the zip file, only '.py' are allowed." % os.path.join(arcdir, f))
00068     # check for removed files
00069     for filename in infos:
00070         if filename not in all_files:
00071             removed.append(filename)
00072             log.info(" %s -> %s", "R", filename)
00073     return (added, modified, untouched, removed)
00074 
00075 ## Make a zip file out of a directory containing python modules
00076 def zipdir(directory, no_pyc = False):
00077     log = logging.getLogger("zipdir")
00078     if not os.path.isdir(directory):
00079         raise OSError(20, "Not a directory", directory)
00080     msg = "Zipping directory '%s'"
00081     if no_pyc:
00082         msg += " (without pre-compilation)"
00083     log.info(msg, directory)
00084     filename = os.path.realpath(directory + ".zip")
00085 
00086     # Open the file in read an update mode
00087     if os.path.exists(filename):
00088         zipFile = open(filename, "r+b")
00089     else:
00090         # If the file does not exist, we need to create it.
00091         # "append mode" ensures that, in case of two processes trying to
00092         # create the file, they do not truncate each other file
00093         zipFile = open(filename, "ab")
00094 
00095     locker.lock(zipFile)
00096     try:
00097         if zipfile.is_zipfile(filename):
00098             infolist = zipfile.ZipFile(filename).infolist()
00099         else:
00100             infolist = []
00101         (added, modified, untouched, removed) = _zipChanges(directory, infolist)
00102         if added or modified or removed:
00103             tempBuf = StringIO()
00104             z = zipfile.PyZipFile(tempBuf, "w", zipfile.ZIP_DEFLATED)
00105             for f in added + modified + untouched:
00106                 src = os.path.join(directory, f)
00107                 if no_pyc:
00108                     log.debug("adding '%s'", f)
00109                     z.write(src, f)
00110                 else:
00111                     # Remove the .pyc file to always force a re-compilation
00112                     if os.path.exists(src + 'c'):
00113                         log.debug("removing old .pyc for '%s'", f)
00114                         os.remove(src + 'c')
00115                     log.debug("adding '%s'", f)
00116                     z.writepy(src, os.path.dirname(f))
00117             z.close()
00118             zipFile.seek(0)
00119             zipFile.write(tempBuf.getvalue())
00120             zipFile.truncate()
00121             log.info("File '%s' closed", filename)
00122         else:
00123             log.info("Nothing to do on '%s'", filename)
00124     finally:
00125         locker.unlock(zipFile)
00126         zipFile.close()
00127 
00128 ## Main function of the script.
00129 #  Parse arguments and call zipdir() for each directory passed as argument
00130 def main(argv = None):
00131     from optparse import OptionParser
00132     parser = OptionParser(usage = "%prog [options] directory1 [directory2 ...]")
00133     parser.add_option("--no-pyc", action = "store_true",
00134                       help = "copy the .py files without pre-compiling them")
00135     parser.add_option("--quiet", action = "store_true",
00136                       help = "do not print info messages")
00137     parser.add_option("--debug", action = "store_true",
00138                       help = "print debug messages (has priority over --quiet)")
00139 
00140     if argv is None:
00141         argv = sys.argv
00142     opts, args = parser.parse_args(argv[1:])
00143 
00144     if not args:
00145         parser.error("Specify at least one directory to zip")
00146 
00147     # Initialize the logging module
00148     level = logging.INFO
00149     if opts.quiet:
00150         level = logging.WARNING
00151     if opts.debug:
00152         level = logging.DEBUG
00153     logging.basicConfig(level = level)
00154 
00155     if "GAUDI_BUILD_LOCK" in os.environ:
00156         _scopedLock = locker.LockFile(os.environ["GAUDI_BUILD_LOCK"], temporary =  True)
00157     # zip all the directories passed as arguments
00158     for d in args:
00159         zipdir(d, opts.no_pyc)
00160 
00161 if __name__ == '__main__':
00162     main()
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines

Generated at Wed Feb 9 16:24:58 2011 for Gaudi Framework, version v22r0 by Doxygen version 1.6.2 written by Dimitri van Heesch, © 1997-2004