00001
00002
00003
00004
00005
00006 import os, sys, zipfile, logging, stat, time
00007 from StringIO import StringIO
00008
00009
00010 sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.pardir, "cmt", "fragments"))
00011 print sys.path[0]
00012 import locker
00013
00014
00015 class ZipdirError(RuntimeError):
00016 pass
00017
00018
00019
00020
00021
00022
00023
00024
00025 def _zipChanges(directory, infolist):
00026
00027 infos = {}
00028 for i in infolist:
00029 fn = i.filename
00030 if fn.endswith(".pyc"):
00031 fn = fn[:-1]
00032 infos[fn] = i.date_time
00033
00034
00035 added = []
00036 modified = []
00037 untouched = []
00038 removed = []
00039 all_files = set()
00040
00041 log = logging.getLogger("zipdir")
00042 dirlen = len(directory) + 1
00043 for root, dirs, files in os.walk(directory):
00044 arcdir = root[dirlen:]
00045 for f in files:
00046 ext = os.path.splitext(f)[1]
00047 if ext == ".py":
00048 filename = os.path.join(arcdir, f)
00049 all_files.add(filename)
00050 if filename not in infos:
00051 action = "A"
00052 added.append(filename)
00053 else:
00054 filetime = time.localtime(os.stat(os.path.join(directory,filename))[stat.ST_MTIME])[:6]
00055 if filetime > infos[filename]:
00056 action = "M"
00057 modified.append(filename)
00058 else:
00059 action = "U"
00060 untouched.append(filename)
00061 log.info(" %s -> %s", action, filename)
00062 elif ext not in [".pyc", ".pyo", ".stamp"]:
00063 raise ZipdirError("Cannot add '%s' to the zip file, only '.py' are allowed." % os.path.join(arcdir, f))
00064
00065 for filename in infos:
00066 if filename not in all_files:
00067 removed.append(filename)
00068 log.info(" %s -> %s", "R", filename)
00069 return (added, modified, untouched, removed)
00070
00071
00072 def zipdir(directory, no_pyc = False):
00073 log = logging.getLogger("zipdir")
00074 if not os.path.isdir(directory):
00075 raise OSError(20, "Not a directory", directory)
00076 msg = "Zipping directory '%s'"
00077 if no_pyc:
00078 msg += " (without pre-compilation)"
00079 log.info(msg, directory)
00080 filename = os.path.realpath(directory + ".zip")
00081
00082
00083 if os.path.exists(filename):
00084 zipFile = open(filename, "r+b")
00085 else:
00086
00087
00088
00089 zipFile = open(filename, "ab")
00090
00091 locker.lock(zipFile)
00092 try:
00093 if zipfile.is_zipfile(filename):
00094 infolist = zipfile.ZipFile(filename).infolist()
00095 else:
00096 infolist = []
00097 (added, modified, untouched, removed) = _zipChanges(directory, infolist)
00098 if added or modified or removed:
00099 tempBuf = StringIO()
00100 z = zipfile.PyZipFile(tempBuf, "w", zipfile.ZIP_DEFLATED)
00101 for f in added + modified + untouched:
00102 if no_pyc:
00103 z.write(os.path.join(directory, f), f)
00104 else:
00105 z.writepy(os.path.join(directory, f), os.path.dirname(f))
00106 z.close()
00107 zipFile.seek(0)
00108 zipFile.write(tempBuf.getvalue())
00109 zipFile.truncate()
00110 log.info("File '%s' closed", filename)
00111 else:
00112 log.info("Nothing to do on '%s'", filename)
00113 finally:
00114 locker.unlock(zipFile)
00115 zipFile.close()
00116
00117
00118
00119 def main(argv = None):
00120 from optparse import OptionParser
00121 parser = OptionParser(usage = "%prog [options] directory1 [directory2 ...]")
00122 parser.add_option("--no-pyc", action = "store_true",
00123 help = "copy the .py files without pre-compiling them")
00124 parser.add_option("--quiet", action = "store_true",
00125 help = "do not print info messages")
00126
00127 if argv is None:
00128 argv = sys.argv
00129 opts, args = parser.parse_args(argv[1:])
00130
00131 if not args:
00132 parser.error("Specify at least one directory to zip")
00133
00134
00135 level = logging.INFO
00136 if opts.quiet:
00137 level = logging.WARNING
00138 logging.basicConfig(level = level)
00139
00140 if "GAUDI_BUILD_LOCK" in os.environ:
00141 scopedLock = locker.LockFile(os.environ["GAUDI_BUILD_LOCK"], temporary = True)
00142
00143 for d in args:
00144 zipdir(d, opts.no_pyc)
00145
00146 if __name__ == '__main__':
00147 main()