From 1f43ab9b03178a3eb3a00f509338dc1bd40808a1 Mon Sep 17 00:00:00 2001 From: Philip Thiem Date: Sat, 2 Feb 2013 18:26:56 -0600 Subject: This changes distribute to use zipfile for obtaining a manifest of zip files instead of zipimpot._zip_directory_cache. As I don't see any place that the cache is being clear, should in effect remove the zipimport private variable dependency --HG-- branch : distribute extra : rebase_source : 275dd3d5a2f55dba541f7f12a1bf8ee7c3465825 --- pkg_resources.py | 48 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 11 deletions(-) (limited to 'pkg_resources.py') diff --git a/pkg_resources.py b/pkg_resources.py index f8de449e..e1bf9ee0 100644 --- a/pkg_resources.py +++ b/pkg_resources.py @@ -13,7 +13,8 @@ The package resource API is designed to work with normal filesystem packages, method. """ -import sys, os, zipimport, time, re, imp, types +import sys, os, zipimport, time, re, imp, types +import zipfile from urlparse import urlparse, urlunparse try: @@ -1348,7 +1349,33 @@ class EmptyProvider(NullProvider): empty_provider = EmptyProvider() - +def build_zipmanifest(path): + """ + This builds a similar dictionary to the zipimport directory + caches. However instead of tuples, ZipInfo objects are stored. + + The translation of the tuple is as follows: + * [0] - zipinfo.filename on stock pythons this needs "/" --> os.sep + on pypy it is the same (one reason why distribute did work + in some cases on pypy and win32). + * [1] - zipinfo.compress_type + * [2] - zipinfo.compress_size + * [3] - zipinfo.file_size + * [4] - len(utf-8 encoding of filename) if zipinfo & 0x800 + len(ascii encoding of filename) otherwise + * [5] - (zipinfo.date_time[0] - 1980) << 9 | + zipinfo.date_time[1] << 5 | zipinfo.date_time[2] + * [6] - (zipinfo.date_time[3] - 1980) << 11 | + zipinfo.date_time[4] << 5 | (zipinfo.date_time[5] // 2) + * [7] - zipinfo.CRC + """ + zipinfo = dict() + with zipfile.ZipFile(path) as zfile: + for zitem in zfile.namelist(): + zpath = zitem.replace('/', os.sep) + zipinfo[zpath] = zfile.getinfo(zitem) + assert zipinfo[zpath] is not None + return zipinfo class ZipProvider(EggProvider): @@ -1358,7 +1385,7 @@ class ZipProvider(EggProvider): def __init__(self, module): EggProvider.__init__(self,module) - self.zipinfo = zipimport._zip_directory_cache[self.loader.archive] + self.zipinfo = build_zipmanifest(self.load.archive) self.zip_pre = self.loader.archive+os.sep def _zipinfo_name(self, fspath): @@ -1393,12 +1420,10 @@ class ZipProvider(EggProvider): return self._extract_resource(manager, zip_path) @staticmethod - def _get_date_and_size(zip_stat): - t,d,size = zip_stat[5], zip_stat[6], zip_stat[3] - date_time = ( - (d>>9)+1980, (d>>5)&0xF, d&0x1F, # ymd - (t&0xFFFF)>>11, (t>>5)&0x3F, (t&0x1F) * 2, 0, 0, -1 # hms, etc. - ) + def _get_date_and_size(zip_stat): + size = zip_stat.file_size + date_time = zip_stat.date_time + (0, 0, -1) #ymdhms+wday, yday, dst + #1980 offset already done timestamp = time.mktime(date_time) return timestamp, size @@ -1411,7 +1436,7 @@ class ZipProvider(EggProvider): ) return os.path.dirname(last) # return the extracted directory name - timestamp, size = self._get_date_and_size(self.zipinfo[zip_path]) + timestamp, size = self._get_date_and_size(self.zipinfo[zip_path]) if not WRITE_SUPPORT: raise IOError('"os.rename" and "os.unlink" are not supported ' @@ -1610,7 +1635,7 @@ class EggMetadata(ZipProvider): def __init__(self, importer): """Create a metadata provider from a zipimporter""" - self.zipinfo = zipimport._zip_directory_cache[importer.archive] + self.zipinfo = build_zipmanifest(importer.archive) self.zip_pre = importer.archive+os.sep self.loader = importer if importer.prefix: @@ -2841,3 +2866,4 @@ run_main = run_script # backward compatibility add_activation_listener(lambda dist: dist.activate()) working_set.entries=[]; map(working_set.add_entry,sys.path) # match order + -- cgit v1.2.3