--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/srcanamdw/codescanner/pyinstaller/archive.py Thu Feb 18 12:29:02 2010 +0530
@@ -0,0 +1,413 @@
+# Copyright (C) 2005, Giovanni Bajo
+# Based on previous work under copyright (c) 2002 McMillan Enterprises, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# In addition to the permissions in the GNU General Public License, the
+# authors give you unlimited permission to link or embed the compiled
+# version of this file into combinations with other programs, and to
+# distribute those combinations without any restriction coming from the
+# use of this file. (The General Public License restrictions do apply in
+# other respects; for example, they cover modification of the file, and
+# distribution when not linked into a combine executable.)
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+# subclasses may not need marshal or struct, but since they're
+# builtin, importing is safe.
+#
+# While an Archive is really an abstraction for any "filesystem
+# within a file", it is tuned for use with imputil.FuncImporter.
+# This assumes it contains python code objects, indexed by the
+# the internal name (ie, no '.py').
+# See carchive.py for a more general archive (contains anything)
+# that can be understood by a C program.
+
+_verbose = 0
+_listdir = None
+_environ = None
+
+# **NOTE** This module is used during bootstrap. Import *ONLY* builtin modules.
+import marshal
+import struct
+import imp
+import sys
+
+_c_suffixes = filter(lambda x: x[2] == imp.C_EXTENSION, imp.get_suffixes())
+
+for nm in ('nt', 'posix', 'dos', 'os2', 'mac'):
+ if nm in sys.builtin_module_names:
+ mod = __import__(nm)
+ _listdir = mod.listdir
+ _environ = mod.environ
+ break
+
+if hasattr(sys, 'version_info'):
+ versuffix = '%d%d'%(sys.version_info[0],sys.version_info[1])
+else:
+ vers = sys.version
+ dot1 = dot2 = 0
+ for i in range(len(vers)):
+ if vers[i] == '.':
+ if dot1:
+ dot2 = i
+ break
+ else:
+ dot1 = i
+ else:
+ dot2 = len(vers)
+ versuffix = '%s%s' % (vers[:dot1], vers[dot1+1:dot2])
+
+if "-vi" in sys.argv[1:]:
+ _verbose = 1
+
+class Archive:
+ """ A base class for a repository of python code objects.
+ The extract method is used by imputil.ArchiveImporter
+ to get code objects by name (fully qualified name), so
+ an enduser "import a.b" would become
+ extract('a.__init__')
+ extract('a.b')
+ """
+ MAGIC = 'PYL\0'
+ HDRLEN = 12 # default is MAGIC followed by python's magic, int pos of toc
+ TOCPOS = 8
+ TRLLEN = 0 # default - no trailer
+ TOCTMPLT = {} #
+ os = None
+ _bincache = None
+ def __init__(self, path=None, start=0):
+ "Initialize an Archive. If path is omitted, it will be an empty Archive."
+ self.toc = None
+ self.path = path
+ self.start = start
+ import imp
+ self.pymagic = imp.get_magic()
+ if path is not None:
+ self.lib = open(self.path, 'rb')
+ self.checkmagic()
+ self.loadtoc()
+
+ ####### Sub-methods of __init__ - override as needed #############
+ def checkmagic(self):
+ """ Overridable.
+ Check to see if the file object self.lib actually has a file
+ we understand.
+ """
+ self.lib.seek(self.start) #default - magic is at start of file
+ if self.lib.read(len(self.MAGIC)) != self.MAGIC:
+ raise RuntimeError, "%s is not a valid %s archive file" \
+ % (self.path, self.__class__.__name__)
+ if self.lib.read(len(self.pymagic)) != self.pymagic:
+ raise RuntimeError, "%s has version mismatch to dll" % (self.path)
+ self.lib.read(4)
+
+ def loadtoc(self):
+ """ Overridable.
+ Default: After magic comes an int (4 byte native) giving the
+ position of the TOC within self.lib.
+ Default: The TOC is a marshal-able string.
+ """
+ self.lib.seek(self.start + self.TOCPOS)
+ (offset,) = struct.unpack('=i', self.lib.read(4))
+ self.lib.seek(self.start + offset)
+ self.toc = marshal.load(self.lib)
+
+ ######## This is what is called by FuncImporter #######
+ ## Since an Archive is flat, we ignore parent and modname.
+ #XXX obsolete - imputil only code
+ ## def get_code(self, parent, modname, fqname):
+ #### if _verbose:
+ #### print "I: get_code(%s, %s, %s, %s)" % (self, parent, modname, fqname)
+ ## iname = fqname
+ ## if parent:
+ ## iname = '%s.%s' % (parent.__dict__.get('__iname__', parent.__name__), modname)
+ #### if _verbose:
+ #### print "I: get_code: iname is %s" % iname
+ ## rslt = self.extract(iname) # None if not found, (ispkg, code) otherwise
+ #### if _verbose:
+ #### print 'I: get_code: rslt', rslt
+ ## if rslt is None:
+ #### if _verbose:
+ #### print 'I: get_code: importer', getattr(parent, "__importer__", None),'self',self
+ ## # check the cache if there is no parent or self is the parents importer
+ ## if parent is None or getattr(parent, "__importer__", None) is self:
+ #### if _verbose:
+ #### print 'I: get_code: cached 1',iname
+ ## file, desc = Archive._bincache.get(iname, (None, None))
+ #### if _verbose:
+ #### print 'I: get_code: file',file,'desc',desc
+ ## if file:
+ ## try:
+ ## fp = open(file, desc[1])
+ ## except IOError:
+ ## pass
+ ## else:
+ ## module = imp.load_module(fqname, fp, file, desc)
+ ## if _verbose:
+ ## print "I: import %s found %s" % (fqname, file)
+ ## return 0, module, {'__file__':file}
+ ## if _verbose:
+ ## print "I: import %s failed" % fqname
+ ##
+ ## return None
+ ##
+ ## ispkg, code = rslt
+ ## values = {'__file__' : code.co_filename, '__iname__' : iname}
+ ## if ispkg:
+ ## values['__path__'] = [fqname]
+ ## if _verbose:
+ ## print "I: import %s found %s" % (fqname, iname)
+ ## return ispkg, code, values
+
+ ####### Core method - Override as needed #########
+ def extract(self, name):
+ """ Get the object corresponding to name, or None.
+ For use with imputil ArchiveImporter, object is a python code object.
+ 'name' is the name as specified in an 'import name'.
+ 'import a.b' will become:
+ extract('a') (return None because 'a' is not a code object)
+ extract('a.__init__') (return a code object)
+ extract('a.b') (return a code object)
+ Default implementation:
+ self.toc is a dict
+ self.toc[name] is pos
+ self.lib has the code object marshal-ed at pos
+ """
+ ispkg, pos = self.toc.get(name, (0,None))
+ if pos is None:
+ return None
+ self.lib.seek(self.start + pos)
+ return ispkg, marshal.load(self.lib)
+
+ ########################################################################
+ # Informational methods
+
+ def contents(self):
+ """Return a list of the contents
+ Default implementation assumes self.toc is a dict like object.
+ Not required by ArchiveImporter.
+ """
+ return self.toc.keys()
+
+ ########################################################################
+ # Building
+
+ ####### Top level method - shouldn't need overriding #######
+ def build(self, path, lTOC):
+ """Create an archive file of name 'path'.
+ lTOC is a 'logical TOC' - a list of (name, path, ...)
+ where name is the internal name, eg 'a'
+ and path is a file to get the object from, eg './a.pyc'.
+ """
+ self.path = path
+ self.lib = open(path, 'wb')
+ #reserve space for the header
+ if self.HDRLEN:
+ self.lib.write('\0'*self.HDRLEN)
+
+ #create an empty toc
+
+ if type(self.TOCTMPLT) == type({}):
+ self.toc = {}
+ else: # assume callable
+ self.toc = self.TOCTMPLT()
+
+ for tocentry in lTOC:
+ self.add(tocentry) # the guts of the archive
+
+ tocpos = self.lib.tell()
+ self.save_toc(tocpos)
+ if self.TRLLEN:
+ self.save_trailer(tocpos)
+ if self.HDRLEN:
+ self.update_headers(tocpos)
+ self.lib.close()
+
+
+ ####### manages keeping the internal TOC and the guts in sync #######
+ def add(self, entry):
+ """Override this to influence the mechanics of the Archive.
+ Assumes entry is a seq beginning with (nm, pth, ...) where
+ nm is the key by which we'll be asked for the object.
+ pth is the name of where we find the object. Overrides of
+ get_obj_from can make use of further elements in entry.
+ """
+ if self.os is None:
+ import os
+ self.os = os
+ nm = entry[0]
+ pth = entry[1]
+ pynm, ext = self.os.path.splitext(self.os.path.basename(pth))
+ ispkg = pynm == '__init__'
+ assert ext in ('.pyc', '.pyo')
+ self.toc[nm] = (ispkg, self.lib.tell())
+ f = open(entry[1], 'rb')
+ f.seek(8) #skip magic and timestamp
+ self.lib.write(f.read())
+
+ def save_toc(self, tocpos):
+ """Default - toc is a dict
+ Gets marshaled to self.lib
+ """
+ marshal.dump(self.toc, self.lib)
+
+ def save_trailer(self, tocpos):
+ """Default - not used"""
+ pass
+
+ def update_headers(self, tocpos):
+ """Default - MAGIC + Python's magic + tocpos"""
+ self.lib.seek(self.start)
+ self.lib.write(self.MAGIC)
+ self.lib.write(self.pymagic)
+ self.lib.write(struct.pack('=i', tocpos))
+
+class DummyZlib:
+ def decompress(self, data):
+ return data
+ def compress(self, data, lvl):
+ return data
+
+import iu
+##############################################################
+#
+# ZlibArchive - an archive with compressed entries
+#
+class ZlibArchive(Archive):
+ MAGIC = 'PYZ\0'
+ TOCPOS = 8
+ HDRLEN = 16
+ TRLLEN = 0
+ TOCTMPLT = {}
+ LEVEL = 9
+
+ def __init__(self, path=None, offset=None, level=9):
+ if path is None:
+ offset = 0
+ elif offset is None:
+ for i in range(len(path)-1, -1, -1):
+ if path[i] == '?':
+ offset = int(path[i+1:])
+ path = path[:i]
+ break
+ else:
+ offset = 0
+ self.LEVEL = level
+ Archive.__init__(self, path, offset)
+ # dynamic import so not imported if not needed
+ global zlib
+ if self.LEVEL:
+ try:
+ import zlib
+ except ImportError:
+ zlib = DummyZlib()
+ else:
+ zlib = DummyZlib()
+
+
+ def extract(self, name):
+ (ispkg, pos, lngth) = self.toc.get(name, (0, None, 0))
+ if pos is None:
+ return None
+ self.lib.seek(self.start + pos)
+ try:
+ co = marshal.loads(zlib.decompress(self.lib.read(lngth)))
+ except EOFError:
+ raise ImportError, "PYZ entry '%s' failed to unmarshal" % name
+ return ispkg, co
+
+ def add(self, entry):
+ if self.os is None:
+ import os
+ self.os = os
+ nm = entry[0]
+ pth = entry[1]
+ base, ext = self.os.path.splitext(self.os.path.basename(pth))
+ ispkg = base == '__init__'
+ try:
+ txt = open(pth[:-1], 'r').read()+'\n'
+ except (IOError, OSError):
+ try:
+ f = open(pth, 'rb')
+ f.seek(8) #skip magic and timestamp
+ bytecode = f.read()
+ marshal.loads(bytecode).co_filename # to make sure it's valid
+ obj = zlib.compress(bytecode, self.LEVEL)
+ except (IOError, ValueError, EOFError, AttributeError):
+ raise ValueError("bad bytecode in %s and no source" % pth)
+ else:
+ txt = iu._string_replace(txt, '\r\n', '\n')
+ try:
+ co = compile(txt, "%s/%s" % (self.path, nm), 'exec')
+ except SyntaxError, e:
+ print "Syntax error in", pth[:-1]
+ print e.args
+ raise
+ obj = zlib.compress(marshal.dumps(co), self.LEVEL)
+ self.toc[nm] = (ispkg, self.lib.tell(), len(obj))
+ self.lib.write(obj)
+ def update_headers(self, tocpos):
+ """add level"""
+ Archive.update_headers(self, tocpos)
+ self.lib.write(struct.pack('!i', self.LEVEL))
+ def checkmagic(self):
+ Archive.checkmagic(self)
+ self.LEVEL = struct.unpack('!i', self.lib.read(4))[0]
+
+class PYZOwner(iu.Owner):
+ def __init__(self, path):
+ self.pyz = ZlibArchive(path)
+ iu.Owner.__init__(self, path)
+ def getmod(self, nm, newmod=imp.new_module):
+ rslt = self.pyz.extract(nm)
+ if rslt is None:
+ return None
+ ispkg, co = rslt
+ mod = newmod(nm)
+ try:
+ mod.__file__ = co.co_filename
+ except AttributeError:
+ raise ImportError, "PYZ entry '%s' (%s) is not a valid code object" % (nm, repr(co))
+ if ispkg:
+ if _environ.has_key('_MEIPASS2'):
+ localpath = _environ['_MEIPASS2'][:-1]
+ else:
+ localpath = iu._os_path_dirname(self.path)
+ mod.__path__ = [self.path, localpath, iu._os_path_dirname(mod.__file__)]
+ #print "PYZOwner setting %s's __path__: %s" % (nm, mod.__path__)
+ importer = iu.PathImportDirector(mod.__path__,
+ {self.path:PkgInPYZImporter(nm, self),
+ localpath:ExtInPkgImporter(localpath, nm)},
+ [iu.DirOwner])
+ mod.__importsub__ = importer.getmod
+ mod.__co__ = co
+ return mod
+
+class PkgInPYZImporter:
+ def __init__(self, name, owner):
+ self.name = name
+ self.owner = owner
+ def getmod(self, nm):
+ #print "PkgInPYZImporter.getmod %s -> %s" % (nm, self.name+'.'+nm)
+ return self.owner.getmod(self.name+'.'+nm)
+class ExtInPkgImporter(iu.DirOwner):
+ def __init__(self, path, prefix):
+ iu.DirOwner.__init__(self, path)
+ self.prefix = prefix
+ def getmod(self, nm):
+ return iu.DirOwner.getmod(self, self.prefix+'.'+nm)
+
+ #XXX this should also get moved out
+ ##iu._globalownertypes.insert(0, PYZOwner)
+ ##iu.ImportManager().install()