All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
ZipPythonDir Namespace Reference

Classes

class  ZipdirError
 Class for generic exception coming from the zipdir() function. More...
 

Functions

def _zipChanges
 Collect the changes to be applied to the zip file. More...
 
def checkEncoding
 
def zipdir
 Make a zip file out of a directory containing python modules. More...
 
def main
 Main function of the script. More...
 

Function Documentation

def ZipPythonDir._zipChanges (   directory,
  infolist 
)
private

Collect the changes to be applied to the zip file.

Parameters
directorydirectory to be packed in the zip file
infolistlist of ZipInfo objects already contained in the zip archive
Returns
: tuple of (added, modified, untouched, removed) entries in the directory with respect to the zip file

Definition at line 30 of file ZipPythonDir.py.

30 
31 def _zipChanges(directory, infolist):
32  # gets the dates of the files in the zip archive
33  infos = {}
34  for i in infolist:
35  fn = i.filename
36  if fn.endswith(".pyc"):
37  fn = fn[:-1]
38  infos[fn] = i.date_time
39 
40  # gets the changes
41  added = []
42  modified = []
43  untouched = []
44  removed = []
45  all_files = set()
46 
47  log = logging.getLogger("zipdir")
48  dirlen = len(directory) + 1
49  for root, dirs, files in os.walk(directory):
50  if "lib-dynload" in dirs:
51  # exclude the directory containing binary modules
52  dirs.remove("lib-dynload")
53  arcdir = root[dirlen:]
54  for f in files:
55  ext = os.path.splitext(f)[1]
56  if ext == ".py": # extensions that can enter the zip file
57  filename = os.path.join(arcdir, f)
58  all_files.add(filename)
59  if filename not in infos:
60  action = "A"
61  added.append(filename)
62  else:
63  filetime = time.localtime(os.stat(os.path.join(directory,filename))[stat.ST_MTIME])[:6]
64  if filetime > infos[filename]:
65  action = "M"
66  modified.append(filename)
67  else:
68  action = "U"
69  untouched.append(filename)
70  if action in ['U']:
71  log.debug(" %s -> %s", action, filename)
72  else:
73  log.info(" %s -> %s", action, filename)
74  # cases that can be ignored
75  elif (ext not in [".pyc", ".pyo", ".stamp", ".cmtref", ".confdb"]
76  and not f.startswith('.__afs')):
77  raise ZipdirError("Cannot add '%s' to the zip file, only '.py' are allowed." % os.path.join(arcdir, f))
78  # check for removed files
79  for filename in infos:
80  if filename not in all_files:
81  removed.append(filename)
82  log.info(" %s -> %s", "R", filename)
83  return (added, modified, untouched, removed)
def _zipChanges
Collect the changes to be applied to the zip file.
Definition: ZipPythonDir.py:30
Class for generic exception coming from the zipdir() function.
Definition: ZipPythonDir.py:20
def ZipPythonDir.checkEncoding (   fileObj)
Check that a file honors the declared encoding (default ASCII for Python 2
and UTF-8 for Python 3).

Raises a UnicodeDecodeError in case of decoding problems and LookupError if
the specified codec does not exists.

See http://www.python.org/dev/peps/pep-0263/

Definition at line 84 of file ZipPythonDir.py.

84 
85 def checkEncoding(fileObj):
86  '''
87  Check that a file honors the declared encoding (default ASCII for Python 2
88  and UTF-8 for Python 3).
89 
90  Raises a UnicodeDecodeError in case of decoding problems and LookupError if
91  the specified codec does not exists.
92 
93  See http://www.python.org/dev/peps/pep-0263/
94  '''
95  from itertools import islice
96 
97  # default encoding
98  if sys.version_info[0] <= 2:
99  enc = 'ascii'
100  else:
101  enc = 'utf-8'
102 
103  # find the encoding of the file, if specified (in the first two lines)
104  enc_exp = re.compile(r"coding[:=]\s*([-\w.]+)")
105  for l in islice(fileObj, 2):
106  m = enc_exp.search(l)
107  if m:
108  enc = m.group(1)
109  break
110 
111  if hasattr(fileObj, 'name'):
112  logging.getLogger('checkEncoding').debug('checking encoding %s on %s',
113  enc, fileObj.name)
114  else:
115  logging.getLogger('checkEncoding').debug('checking encoding %s on file object',
116  enc)
117  # try to read the file with the declared encoding
118  fileObj.seek(0)
119  codecs.getreader(enc)(fileObj).read()
120 
def ZipPythonDir.main (   argv = None)

Main function of the script.

Parse arguments and call zipdir() for each directory passed as argument

Definition at line 182 of file ZipPythonDir.py.

183 def main(argv = None):
184  from optparse import OptionParser
185  parser = OptionParser(usage = "%prog [options] directory1 [directory2 ...]")
186  parser.add_option("--no-pyc", action = "store_true",
187  help = "copy the .py files without pre-compiling them")
188  parser.add_option("--quiet", action = "store_true",
189  help = "do not print info messages")
190  parser.add_option("--debug", action = "store_true",
191  help = "print debug messages (has priority over --quiet)")
192 
193  if argv is None:
194  argv = sys.argv
195  opts, args = parser.parse_args(argv[1:])
196 
197  if not args:
198  parser.error("Specify at least one directory to zip")
199 
200  # Initialize the logging module
201  level = logging.INFO
202  if opts.quiet:
203  level = logging.WARNING
204  if opts.debug:
205  level = logging.DEBUG
206  logging.basicConfig(level = level)
207 
208  if "GAUDI_BUILD_LOCK" in os.environ:
209  _scopedLock = locker.LockFile(os.environ["GAUDI_BUILD_LOCK"], temporary = True)
210  # zip all the directories passed as arguments
211  for d in args:
212  zipdir(d, opts.no_pyc)
def main
Main function of the script.
def zipdir
Make a zip file out of a directory containing python modules.
Lock a file.
Definition: locker.py:63
def ZipPythonDir.zipdir (   directory,
  no_pyc = False 
)

Make a zip file out of a directory containing python modules.

Definition at line 122 of file ZipPythonDir.py.

123 def zipdir(directory, no_pyc = False):
124  log = logging.getLogger("zipdir")
125  if not os.path.isdir(directory):
126  raise OSError(20, "Not a directory", directory)
127  msg = "Zipping directory '%s'"
128  if no_pyc:
129  msg += " (without pre-compilation)"
130  log.info(msg, directory)
131  filename = os.path.realpath(directory + ".zip")
132 
133  # Open the file in read an update mode
134  if os.path.exists(filename):
135  zipFile = open(filename, "r+b")
136  else:
137  # If the file does not exist, we need to create it.
138  # "append mode" ensures that, in case of two processes trying to
139  # create the file, they do not truncate each other file
140  zipFile = open(filename, "ab")
141 
142  locker.lock(zipFile)
143  try:
144  if zipfile.is_zipfile(filename):
145  infolist = zipfile.ZipFile(filename).infolist()
146  else:
147  infolist = []
148  (added, modified, untouched, removed) = _zipChanges(directory, infolist)
149  if added or modified or removed:
150  tempBuf = StringIO()
151  z = zipfile.PyZipFile(tempBuf, "w", zipfile.ZIP_DEFLATED)
152  for f in added + modified + untouched:
153  src = os.path.join(directory, f)
154  checkEncoding(open(src, 'rb'))
155  if no_pyc:
156  log.debug("adding '%s'", f)
157  z.write(src, f)
158  else:
159  # Remove the .pyc file to always force a re-compilation
160  if os.path.exists(src + 'c'):
161  log.debug("removing old .pyc for '%s'", f)
162  os.remove(src + 'c')
163  log.debug("adding '%s'", f)
164  z.writepy(src, os.path.dirname(f))
165  z.close()
166  zipFile.seek(0)
167  zipFile.write(tempBuf.getvalue())
168  zipFile.truncate()
169  log.info("File '%s' closed", filename)
170  else:
171  log.info("Nothing to do on '%s'", filename)
172  except UnicodeDecodeError, x:
173  log.error("Wrong encoding in file '%s':", src)
174  log.error(" %s", x)
175  log.error("Probably you forgot the line '# -*- coding: utf-8 -*-'")
176  sys.exit(1)
177  finally:
178  locker.unlock(zipFile)
179  zipFile.close()
def _zipChanges
Collect the changes to be applied to the zip file.
Definition: ZipPythonDir.py:30
def lock
Definition: locker.py:16
def zipdir
Make a zip file out of a directory containing python modules.
def unlock
Definition: locker.py:34