diff --git a/Build.py b/Build.py index 81b879b..1428000 100755 --- a/Build.py +++ b/Build.py @@ -126,6 +126,7 @@ class Analysis(Target): self.scripts = TOC() self.pure = TOC() self.binaries = TOC() + self.zipfiles = TOC() self.__postinit__() def check_guts(self, last_build): outnm = os.path.basename(self.out) @@ -164,6 +165,7 @@ class Analysis(Target): elif mtime(fnm[:-1]) > last_build: print "building because %s changed" % fnm[:-1] return True + # todo: add zipfiles for (nm, fnm, typ) in binaries: if mtime(fnm) > last_build: print "building because %s changed" % fnm @@ -207,6 +209,7 @@ class Analysis(Target): # Fills pure, binaries and rthookcs lists to TOC pure = [] # pure python modules binaries = [] # binaries to bundle + zipfiles = [] # zipfiles to bundle rthooks = [] # rthooks if needed for modnm, mod in analyzer.modules.items(): # FIXME: why can we have a mod == None here? @@ -220,6 +223,9 @@ class Analysis(Target): fnm = mod.__file__ if isinstance(mod, mf.ExtensionModule): binaries.append((mod.__name__, fnm, 'EXTENSION')) + elif isinstance(mod, mf.PkgInZipModule): + zipfiles.append((os.path.basename(str(mod.owner)), + str(mod.owner), 'ZIPFILE')) elif modnm == '__main__': pass else: @@ -230,10 +236,12 @@ class Analysis(Target): self.scripts = TOC(scripts) self.pure = TOC(pure) self.binaries = TOC(binaries) + self.zipfiles = TOC(zipfiles) try: # read .toc oldstuff = eval(open(self.out, 'r').read()) except: oldstuff = None + # todo: add zipfiles if oldstuff != (self.inputs, self.pathex, self.hookspath, self.excludes, scripts, pure, binaries): outf = open(self.out, 'w') pprint.pprint( @@ -412,6 +420,7 @@ class PKG(Target): 'PKG' : 'a', 'DATA': 'x', 'BINARY': 'b', + 'ZIPFILE': 'Z', 'EXECUTABLE': 'b'} def __init__(self, toc, name=None, cdict=None, exclude_binaries=0, strip_binaries=0, upx_binaries=0): @@ -607,7 +616,7 @@ class EXE(Target): exe = exe + '_d' return exe def assemble(self): - print "building EXE", os.path.basename(self.out) + print "building EXE from", os.path.basename(self.out) trash = [] outf = open(self.name, 'wb') exe = self._bootloader_postfix('support/loader/run') diff --git a/archive.py b/archive.py index 2570a95..0e7b7fd 100644 --- a/archive.py +++ b/archive.py @@ -71,6 +71,8 @@ else: if "-vi" in sys.argv[1:]: _verbose = 1 +class ArchiveReadError(RuntimeError): pass + class Archive: """ A base class for a repository of python code objects. The extract method is used by imputil.ArchiveImporter @@ -106,10 +108,10 @@ class Archive: """ 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" \ + raise ArchiveReadError, "%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) + raise ArchiveReadError, "%s has version mismatch to dll" % (self.path) self.lib.read(4) def loadtoc(self): @@ -372,7 +374,8 @@ class PYZOwner(iu.Owner): def __init__(self, path): try: self.pyz = ZlibArchive(path) - except IOError, e: + self.pyz.checkmagic() + except (IOError, ArchiveReadError), e: raise iu.OwnerError(e) iu.Owner.__init__(self, path) def getmod(self, nm, newmod=imp.new_module): diff --git a/iu.py b/iu.py index b8ed788..a1a1cd2 100644 --- a/iu.py +++ b/iu.py @@ -33,6 +33,12 @@ try: except AttributeError: py_version = (1,5) +try: + # zipimport is supported starting with Python 2.3 + import zipimport +except ImportError: + zipimport = None + #=======================Owners==========================# # An Owner does imports from a particular piece of turf # That is, there's an Owner for each thing on sys.path @@ -118,10 +124,28 @@ class DirOwner(Owner): mod.__co__ = co return mod -_globalownertypes = [ +ZipOwner = None +if zipimport: + class ZipOwner(Owner): + def __init__(self, path): + try: + self.__zip = zipimport.zipimporter(path) + except zipimport.ZipImportError, e: + raise OwnerError('%s: %s' % (e.message, path)) + Owner.__init__(self, path) + + def getmod(self, nm, newmod=imp.new_module): + try: + return self.__zip.load_module(nm) + except zipimport.ZipImportError: + return None + +# _mountzlib.py will insert archive.PYZOwner in front later +_globalownertypes = filter(None, [ + ZipOwner, DirOwner, Owner, -] +]) #===================Import Directors====================================# # ImportDirectors live on the metapath @@ -428,7 +452,7 @@ class ImportManager: self.setThreaded() else: sys.modules[fqname] = None - #print "..found %s" % mod + #print "..found %s" % mod, 'when looking for', fqname return mod def reloadHook(self, mod): fqnm = mod.__name__ diff --git a/mf.py b/mf.py index 20ca1a4..4154655 100644 --- a/mf.py +++ b/mf.py @@ -15,6 +15,11 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import sys, string, os, imp, marshal, dircache +try: + # zipimport is supported starting with Python 2.3 + import zipimport +except ImportError: + zipimport = None #=======================Owners==========================# # An Owner does imports from a particular piece of turf @@ -137,11 +142,27 @@ class PYZOwner(Owner): return PkgInPYZModule(nm, co, self) return PyModule(nm, self.path, co) -_globalownertypes = [ +ZipOwner = None +if zipimport: + class ZipOwner(Owner): + def __init__(self, path): + print 'ZipOwner', path + self.__zip = zipimport.zipimporter(path) + Owner.__init__(self, path) + + def getmod(self, nm): + try: + co = self.__zip.get_code(nm) + return PkgInZipModule(nm, co, self) + except zipimport.ZipImportError: + return None + +_globalownertypes = filter(None, [ DirOwner, + ZipOwner, PYZOwner, Owner, -] +]) #===================Import Directors====================================# # ImportDirectors live on the metapath @@ -217,7 +238,8 @@ class RegistryImportDirector(ImportDirector): stuff = open(fnm, 'rb').read() co = loadco(stuff[8:]) return PyModule(nm, fnm, co) - return None + return None + class PathImportDirector(ImportDirector): def __init__(self, pathlist=None, importers=None, ownertypes=None): if pathlist is None: @@ -596,6 +618,17 @@ class PkgInPYZModule(PyModule): mod = self.owner.getmod(self.__name__ + '.' + nm) return mod +class PkgInZipModule(PyModule): + typ = 'ZIPFILE' + def __init__(self, nm, co, pyzowner): + PyModule.__init__(self, nm, co.co_filename, co) + self._ispkg = 0 + self.__path__ = [ str(pyzowner) ] + self.owner = pyzowner + def doimport(self, nm): + mod = self.owner.getmod(self.__name__ + '.' + nm) + return mod + #======================== Utility ================================# # Scan the code object for imports, __all__ and wierd stuff diff --git a/source/common/launch.c b/source/common/launch.c index e159b0c..cf12f54 100644 --- a/source/common/launch.c +++ b/source/common/launch.c @@ -694,6 +694,28 @@ int installZlib(TOC *ptoc) return 0; } +/* Add a zipfile to sys.path from a toc entry + * Return non zero on failure + */ +int installZipfile(TOC *ptoc) +{ + int rc; + char *tmpl = "sys.path.append(r\"%s" SEP "%s\")\n"; + char *cmd = (char *) malloc(strlen(tmpl) + strlen(f_workpath) + + strlen(ptoc->name)+ 10); + sprintf(cmd, tmpl, f_workpath, ptoc->name); + /*VS(cmd);*/ + rc = PI_PyRun_SimpleString(cmd); + if (rc != 0) + { + FATALERROR("Error in command: %s\n", cmd); + free(cmd); + return -1; + } + + free(cmd); + return 0; +} /* * Install zlibs @@ -704,14 +726,21 @@ int installZlibs() TOC * ptoc; VS("Installing import hooks\n"); - /* Iterate through toc looking for zlibs (type 'z') */ + /* Iterate through toc looking for zlibs (type 'z') or + * zipfiles (type 'Z') + */ ptoc = f_tocbuff; while (ptoc < f_tocend) { - if (ptoc->typcd == 'z') + if (ptoc->typcd == 'z') { VS("%s\n", ptoc->name); installZlib(ptoc); } + else if (ptoc->typcd == 'Z') + { + VS("zipfile: %s\n", ptoc->name); + installZipfile(ptoc); + } ptoc = incrementTocPtr(ptoc); } @@ -855,7 +884,8 @@ int extract2fs(TOC *ptoc) return 0; } /* - * extract all binaries (type 'b') to the filesystem + * extract all binaries (type 'b') and zipfiles (type 'Z') + * to the filesystem */ int extractBinaries(char **workpath) { @@ -863,7 +893,7 @@ int extractBinaries(char **workpath) workpath[0] = '\0'; VS("Extracting binaries\n"); while (ptoc < f_tocend) { - if (ptoc->typcd == 'b') + if (ptoc->typcd == 'b' || ptoc->typcd == 'Z') if (extract2fs(ptoc)) return -1; ptoc = incrementTocPtr(ptoc);