Gaudi Framework, version v23r5

Home   Generated: Wed Nov 28 2012
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
ZipPythonDir.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 ## file ZipPythonDir.py
4 # Script to generate a zip file that can replace a directory in the python path.
5 
6 import os, sys, zipfile, logging, stat, time
7 from StringIO import StringIO
8 
9 # Add to the path the entry needed to import the locker module.
10 import locker
11 
12 ## Class for generic exception coming from the zipdir() function
13 class ZipdirError(RuntimeError):
14  pass
15 
16 ## Collect the changes to be applied to the zip file.
17 #
18 # @param directory: directory to be packed in the zip file
19 # @param infolist: list of ZipInfo objects already contained in the zip archive
20 #
21 # @return: tuple of (added, modified, untouched, removed) entries in the directory with respect to the zip file
22 #
23 def _zipChanges(directory, infolist):
24  # gets the dates of the files in the zip archive
25  infos = {}
26  for i in infolist:
27  fn = i.filename
28  if fn.endswith(".pyc"):
29  fn = fn[:-1]
30  infos[fn] = i.date_time
31 
32  # gets the changes
33  added = []
34  modified = []
35  untouched = []
36  removed = []
37  all_files = set()
38 
39  log = logging.getLogger("zipdir")
40  dirlen = len(directory) + 1
41  for root, dirs, files in os.walk(directory):
42  if "lib-dynload" in dirs:
43  # exclude the directory containing binary modules
44  dirs.remove("lib-dynload")
45  arcdir = root[dirlen:]
46  for f in files:
47  ext = os.path.splitext(f)[1]
48  if ext == ".py": # extensions that can enter the zip file
49  filename = os.path.join(arcdir, f)
50  all_files.add(filename)
51  if filename not in infos:
52  action = "A"
53  added.append(filename)
54  else:
55  filetime = time.localtime(os.stat(os.path.join(directory,filename))[stat.ST_MTIME])[:6]
56  if filetime > infos[filename]:
57  action = "M"
58  modified.append(filename)
59  else:
60  action = "U"
61  untouched.append(filename)
62  if action in ['U']:
63  log.debug(" %s -> %s", action, filename)
64  else:
65  log.info(" %s -> %s", action, filename)
66  elif ext not in [".pyc", ".pyo", ".stamp", ".cmtref"]: # extensions that can be ignored
67  raise ZipdirError("Cannot add '%s' to the zip file, only '.py' are allowed." % os.path.join(arcdir, f))
68  # check for removed files
69  for filename in infos:
70  if filename not in all_files:
71  removed.append(filename)
72  log.info(" %s -> %s", "R", filename)
73  return (added, modified, untouched, removed)
74 
75 ## Make a zip file out of a directory containing python modules
76 def zipdir(directory, no_pyc = False):
77  log = logging.getLogger("zipdir")
78  if not os.path.isdir(directory):
79  raise OSError(20, "Not a directory", directory)
80  msg = "Zipping directory '%s'"
81  if no_pyc:
82  msg += " (without pre-compilation)"
83  log.info(msg, directory)
84  filename = os.path.realpath(directory + ".zip")
85 
86  # Open the file in read an update mode
87  if os.path.exists(filename):
88  zipFile = open(filename, "r+b")
89  else:
90  # If the file does not exist, we need to create it.
91  # "append mode" ensures that, in case of two processes trying to
92  # create the file, they do not truncate each other file
93  zipFile = open(filename, "ab")
94 
95  locker.lock(zipFile)
96  try:
97  if zipfile.is_zipfile(filename):
98  infolist = zipfile.ZipFile(filename).infolist()
99  else:
100  infolist = []
101  (added, modified, untouched, removed) = _zipChanges(directory, infolist)
102  if added or modified or removed:
103  tempBuf = StringIO()
104  z = zipfile.PyZipFile(tempBuf, "w", zipfile.ZIP_DEFLATED)
105  for f in added + modified + untouched:
106  src = os.path.join(directory, f)
107  if no_pyc:
108  log.debug("adding '%s'", f)
109  z.write(src, f)
110  else:
111  # Remove the .pyc file to always force a re-compilation
112  if os.path.exists(src + 'c'):
113  log.debug("removing old .pyc for '%s'", f)
114  os.remove(src + 'c')
115  log.debug("adding '%s'", f)
116  z.writepy(src, os.path.dirname(f))
117  z.close()
118  zipFile.seek(0)
119  zipFile.write(tempBuf.getvalue())
120  zipFile.truncate()
121  log.info("File '%s' closed", filename)
122  else:
123  log.info("Nothing to do on '%s'", filename)
124  finally:
125  locker.unlock(zipFile)
126  zipFile.close()
127 
128 ## Main function of the script.
129 # Parse arguments and call zipdir() for each directory passed as argument
130 def main(argv = None):
131  from optparse import OptionParser
132  parser = OptionParser(usage = "%prog [options] directory1 [directory2 ...]")
133  parser.add_option("--no-pyc", action = "store_true",
134  help = "copy the .py files without pre-compiling them")
135  parser.add_option("--quiet", action = "store_true",
136  help = "do not print info messages")
137  parser.add_option("--debug", action = "store_true",
138  help = "print debug messages (has priority over --quiet)")
139 
140  if argv is None:
141  argv = sys.argv
142  opts, args = parser.parse_args(argv[1:])
143 
144  if not args:
145  parser.error("Specify at least one directory to zip")
146 
147  # Initialize the logging module
148  level = logging.INFO
149  if opts.quiet:
150  level = logging.WARNING
151  if opts.debug:
152  level = logging.DEBUG
153  logging.basicConfig(level = level)
154 
155  if "GAUDI_BUILD_LOCK" in os.environ:
156  _scopedLock = locker.LockFile(os.environ["GAUDI_BUILD_LOCK"], temporary = True)
157  # zip all the directories passed as arguments
158  for d in args:
159  zipdir(d, opts.no_pyc)
160 
161 if __name__ == '__main__':
162  main()

Generated at Wed Nov 28 2012 12:17:17 for Gaudi Framework, version v23r5 by Doxygen version 1.8.2 written by Dimitri van Heesch, © 1997-2004