Browse Source

*** empty log message ***

Joe Shochet 25 years ago
parent
commit
ec3ac7ffad

+ 6 - 6
direct/src/directnotify/DirectNotify.py

@@ -47,20 +47,20 @@ class DirectNotify:
         """
         """
         Check to see if this category has a dconfig variable
         Check to see if this category has a dconfig variable
         to set the notify severity and then set that level. You cannot
         to set the notify severity and then set that level. You cannot
-        set these until base.config is set.
+        set these until config is set.
         """
         """
 
 
-        # We cannot check dconfig variables until base.config has been
-        # set. Once base.config is set in ShowBase.py, it tries to set
-        # all the levels again in case some were created before base.config
+        # We cannot check dconfig variables until config has been
+        # set. Once config is set in ShowBase.py, it tries to set
+        # all the levels again in case some were created before config
         # was created.
         # was created.
         try:
         try:
-            base.config
+            config
         except:
         except:
             return 0
             return 0
         
         
         dconfigParam = ("notify-level-" + categoryName)
         dconfigParam = ("notify-level-" + categoryName)
-        level = base.config.GetString(dconfigParam, "")
+        level = config.GetString(dconfigParam, "")
         if level:
         if level:
             print ("Setting DirectNotify category: " + dconfigParam +
             print ("Setting DirectNotify category: " + dconfigParam +
                    " to severity: " + level)
                    " to severity: " + level)

+ 3 - 3
direct/src/directscripts/python-mode.el

@@ -1281,7 +1281,7 @@ filter."
 			       (concat
 			       (concat
 				(mapconcat 'identity py-which-args " ") " ")
 				(mapconcat 'identity py-which-args " ") " ")
 			       ))))
 			       ))))
-    (switch-to-buffer-other-window
+    (switch-to-buffer ;; -other-window
      (apply 'make-comint py-which-bufname py-which-shell nil args))
      (apply 'make-comint py-which-bufname py-which-shell nil args))
     (make-local-variable 'comint-prompt-regexp)
     (make-local-variable 'comint-prompt-regexp)
     (setq comint-prompt-regexp "^>>> \\|^[.][.][.] \\|^(pdb) ")
     (setq comint-prompt-regexp "^>>> \\|^[.][.][.] \\|^(pdb) ")
@@ -1308,7 +1308,7 @@ filter."
 			       (concat
 			       (concat
 				(mapconcat 'identity py-which-args " ") " ")
 				(mapconcat 'identity py-which-args " ") " ")
 			       ))))
 			       ))))
-    (switch-to-buffer-other-window
+    (switch-to-buffer ;; -other-window
      (apply 'make-comint py-which-bufname pyd-which-shell nil args))
      (apply 'make-comint py-which-bufname pyd-which-shell nil args))
     (make-local-variable 'comint-prompt-regexp)
     (make-local-variable 'comint-prompt-regexp)
     (setq comint-prompt-regexp "^>>> \\|^[.][.][.] \\|^(pdb) ")
     (setq comint-prompt-regexp "^>>> \\|^[.][.][.] \\|^(pdb) ")
@@ -1337,7 +1337,7 @@ filter."
 			       (concat
 			       (concat
 				(mapconcat 'identity py-which-args " ") " ")
 				(mapconcat 'identity py-which-args " ") " ")
 			       ))))
 			       ))))
-    (switch-to-buffer-other-window
+    (switch-to-buffer ;; -other-window
      (apply 'make-comint py-which-bufname ppy-which-shell nil args))
      (apply 'make-comint py-which-bufname ppy-which-shell nil args))
     (make-local-variable 'comint-prompt-regexp)
     (make-local-variable 'comint-prompt-regexp)
     (setq comint-prompt-regexp "^>>> \\|^[.][.][.] \\|^(pdb) ")
     (setq comint-prompt-regexp "^>>> \\|^[.][.][.] \\|^(pdb) ")

+ 9 - 0
direct/src/distributed/DistributedObject.py

@@ -1,9 +1,11 @@
 """DistributedObject module: contains the DistributedObject class"""
 """DistributedObject module: contains the DistributedObject class"""
 
 
 from PandaObject import *
 from PandaObject import *
+from DirectNotifyGlobal import *
 
 
 class DistributedObject(PandaObject):
 class DistributedObject(PandaObject):
     """Distributed Object class:"""
     """Distributed Object class:"""
+    notify = directNotify.newCategory("DistributedObject")
     def __init__(self, cr):
     def __init__(self, cr):
         try:
         try:
             self.DistributedObject_initialized
             self.DistributedObject_initialized
@@ -33,6 +35,13 @@ class DistributedObject(PandaObject):
             self.deleteImminent = 0
             self.deleteImminent = 0
         return None
         return None
 
 
+    def __del__(self):
+        """
+        For debugging purposes, this just prints out what got deleted
+        """
+        DistributedObject.notify.debug("Destructing: " + self.__class__.__name__ +
+                                       " id: " + str(self.doId))
+
     def setNeverDisable(self, bool):
     def setNeverDisable(self, bool):
         assert((bool == 1) or (bool == 0))
         assert((bool == 1) or (bool == 0))
         self.neverDisable = bool
         self.neverDisable = bool

+ 2 - 2
direct/src/leveleditor/LevelEditor.py

@@ -15,8 +15,8 @@ if sys.argv[1:]:
 # If you do not run from the command line, we just load all of them
 # If you do not run from the command line, we just load all of them
 # or you can hack this up for your own purposes.
 # or you can hack this up for your own purposes.
 else:
 else:
-    # hoods = ['TT', 'DD', 'BR', 'DG', 'DL', 'MM']
-    hoods = ['BR' ]
+    hoods = ['TT', 'DD', 'BR', 'DG', 'DL', 'MM']
+    # hoods = ['DL' ]
 
 
 print "Loading LevelEditor for hoods: ", hoods
 print "Loading LevelEditor for hoods: ", hoods
 
 

+ 503 - 0
direct/src/pyinst/Builder.py

@@ -0,0 +1,503 @@
+import string
+import pprint
+import sys
+import os
+import ConfigParser
+import pprint
+import shutil
+import tempfile
+import ltoc
+import tocfilter
+import resource
+import archive
+import archivebuilder
+import carchive
+
+logfile = None
+autopath = []
+built = {}
+copyFile = None
+
+class Target:
+    def __init__(self, cfg, sectnm, cnvrts):
+        self.children = []
+        self._dependencies = ltoc.lTOC() # the stuff an outer package will need to use me
+        self.cfg = cfg
+        self.__name__ = 'joe'
+        for optnm in cfg.options(sectnm):
+            cnvrt = cnvrts.get(optnm, 'getstringlist')
+            if cnvrt:
+                f = getattr(self, cnvrt, None)
+                if f:
+                    self.__dict__[optnm] = f(cfg.get(sectnm, optnm))
+        if not hasattr(self, 'name'):
+            self.name = self.__name__
+        print "Initializing", self.__name__
+        self.pathprefix = autopath + self.pathprefix
+        self.pathprefix.append(os.path.join(pyinsthome, 'support'))
+        for z in self.zlib:
+            if z in self.cfg.sections():
+                self.children.append(z)
+            else:
+                raise ValueError, "%s - zlib '%s' does not refer to a sections" \
+                      % (self.name, z)
+        for i in range(len(self.misc)):
+            x = self.misc[i]
+            if x in self.cfg.sections():
+                if self.cfg.get(x, "type") == 'PYZ':
+                    self.zlib.append(x)
+                    self.misc[i] = None
+                self.children.append(x)
+        self.misc = filter(None, self.misc)
+        self.edit()
+        self.toc = ltoc.lTOC()
+        for thingie in self.excludes:
+            try:
+                fltr = tocfilter.makefilter(thingie, self.pathprefix)
+            except ValueError:
+                print "Warning: '%s' not found - no filter created" % thingie
+            else:
+                self.toc.addFilter(fltr)
+        if self.exstdlib:
+            self.toc.addFilter(tocfilter.StdLibFilter())
+        if self.extypes:
+            self.toc.addFilter(tocfilter.ExtFilter(self.extypes))
+        if self.expatterns:
+            self.toc.addFilter(tocfilter.PatternFilter(self.expatterns))
+        
+        ##------utilities------##                   
+    def dump(self):
+        logfile.write("---- %s: %s -----\n" % (self.__class__.__name__, self.name))
+        pprint.pprint(self.__dict__, logfile)
+    def getstringlist(self, opt):
+        tmp = string.split(opt, ',')
+        return filter(None, map(string.strip, tmp))
+    def getstring(self, opt):
+        return opt
+    def getbool(self, opt):
+        if opt in ('0','f','F','n','N'):
+            return 0
+        return 1
+        ##-----framework-----##
+    def build(self):
+        print "Gathering components of %s" % self.name
+        self.gather()
+        logfile.write("Final Table of Contents for %s:\n" % self.name)
+        pprint.pprint(self.toc.toList(), logfile)
+        print "Creating %s" % self.name
+        self.assemble()
+        ##-----overrideables-----##
+    def edit(self):
+        pass
+    def gather(self):
+        pass
+    def assemble(self):
+        pass
+        
+class PYZTarget(Target):
+    def __init__(self, cfg, sectnm, cnvrts):
+        Target.__init__(self, cfg, sectnm, cnvrts)
+        # to use a PYZTarget, you'll need imputil and archive 
+        archivebuilder.GetCompiled([os.path.join(pyinsthome, 'support', 'imputil.py')])
+        imputil = resource.makeresource('imputil.py', [os.path.join(pyinsthome, 'support')])
+        self._dependencies.append(imputil)
+        archivebuilder.GetCompiled([os.path.join(pyinsthome, 'support', 'archive_rt.py')])
+        archmodule = resource.makeresource('archive_rt.py', [os.path.join(pyinsthome, 'support')]) 
+        self._dependencies.merge(archmodule.dependencies())
+        self._dependencies.append(archmodule)
+        self.toc.addFilter(archmodule)
+        self.toc.addFilter(imputil)
+        for mod in archmodule.modules:
+            self.toc.addFilter(mod)
+    def edit(self):
+        if self.extypes:
+            print "PYZ target %s ignoring extypes = %s" % (self.__name__, self.extypes)
+            
+    def gather(self):
+        for script in self.dependencies:
+            rsrc = resource.makeresource(script, self.pathprefix)
+            if not isinstance(rsrc, resource.scriptresource):
+                print "Bug alert - Made %s from %s!" % (rsrc, script)
+            self.toc.merge(rsrc.modules)
+        logfile.write("lTOC after expanding 'depends':\n")
+        pprint.pprint(self.toc.toList(), logfile)
+        for thingie in self.includes + self.directories + self.packages:
+            rsrc = resource.makeresource(thingie, self.pathprefix)
+##            if not isinstance(rsrc, resource.pythonresource):
+##                print "PYZ target %s ignoring include %s" % (self.name, thingie)
+##            else:
+            self.toc.merge(rsrc.contents())
+        logfile.write("lTOC after includes, dir, pkgs:\n")
+        pprint.pprint(self.toc.toList(), logfile)
+        self.toc.addFilter(tocfilter.ExtFilter(['.py', '.pyc', '.pyo'], 1))
+        logfile.write("Applying the following filters:\n")
+        pprint.pprint(self.toc.filters, logfile)
+        self.toc.filter()
+        
+    def assemble(self):
+        contents = self.toc.toList()
+        if contents:
+            lib = archive.ZlibArchive()
+            lib.build(self.name, archivebuilder.GetCompiled(self.toc.toList()))
+        
+class CollectTarget(Target):
+    def __init__(self, cfg, sectnm, cnvrts):
+        Target.__init__(self, cfg, sectnm, cnvrts)
+        
+    _rsrcdict = {'COLLECT': resource.dirresource, 'PYZ': resource.zlibresource, 'CARCHIVE': resource.archiveresource}
+
+    def gather(self):
+        if self.support:
+            # the bare minimum
+            self.toc.merge([resource.makeresource('python20.dll')])
+            self.toc.merge([resource.makeresource('exceptions.pyc').asBinary()])
+        # zlib, bindepends, misc, trees, destdir
+        for i in range(len(self.zlib)):
+            # z refers to the section name
+            z = self.zlib[i]
+            nm = self.cfg.get(z, 'name')
+            try:
+                self.toc.merge([resource.makeresource(nm, ['.'])])
+            except ValueError:
+                # zlibs aren't written if they turn out to be empty
+                self.zlib[i] = None
+        self.zlib = filter(None, self.zlib)
+        if self.zlib:
+            target = built.get(self.zlib[0], None)
+            if target:
+                self.toc.merge(target._dependencies)
+        for script in self.bindepends:
+            rsrc = resource.makeresource(script, self.pathprefix)
+            self.toc.merge(rsrc.binaries)
+        logfile.write('ltoc after bindepends:\n')
+        pprint.pprint(self.toc.toList(), logfile)
+        for thingie in self.misc:
+            if thingie in self.cfg.sections():
+                name = self.cfg.get(thingie, "name")
+                typ = self.cfg.get(thingie, "type")
+                klass = self._rsrcdict.get(typ, resource.dataresource)
+                rsrc = apply(klass, (name, name))
+                #now make sure we have the stuff the resource requires
+                target = built.get(thingie, None)
+                if target:
+                    self.toc.merge(target._dependencies)
+            else:
+                rsrc = resource.makeresource(thingie, self.pathprefix)
+            self.toc.merge(rsrc.contents())
+        logfile.write('ltoc after misc:\n')
+        pprint.pprint(self.toc.toList(), logfile)
+        for script in self.script:
+            if string.find(script, '.') == -1:
+                script = script + '.py'
+            rsrc = resource.makeresource(script, self.pathprefix)
+            if rsrc.typ == 'm':
+                rsrc.typ = 's'
+            self.toc.merge([rsrc])
+        logfile.write('ltoc after scripts:\n')
+        pprint.pprint(self.toc.toList(), logfile)
+        for tree in self.trees:
+            try:
+                rsrc = resource.treeresource('.', tree)
+            except ValueError:
+                print "tree %s not found" % tree
+            else:
+                self.toc.merge(rsrc.contents())
+        logfile.write('ltoc after trees:\n')
+        pprint.pprint(self.toc.toList(), logfile)
+        self.toc.addFilter(tocfilter.TypeFilter(['d'])) 
+        logfile.write("Applying the following filters:\n")
+        pprint.pprint(self.toc.filters, logfile)
+        self.toc.filter() 
+        #don't dupe stuff in a zlib that's part of this target
+        if self.zlib:
+           ztoc = ltoc.lTOC()
+           for zlibnm in self.zlib:
+               target = built.get(zlibnm, None)
+               if target:
+                   ztoc.merge(target.toc)
+           for i in range(len(self.toc)-1, -1, -1):
+               rsrc = self.toc[i]
+               if isinstance(rsrc, resource.moduleresource) and rsrc in ztoc:
+                   del self.toc[i]
+        
+    def assemble(self):
+        if os.path.exists(self.name):
+            if os.path.isdir(self.name):
+                for fnm in os.listdir(self.name):
+                    try:
+                        os.remove(os.path.join(self.name, fnm))
+                    except:
+                        print "Could not delete file %s" % os.path.join(self.name, fnm)
+        else:
+            os.makedirs(self.name)
+        mysite = []
+        for nm, path, typ in self.toc.toList():
+            shutil.copy2(path, self.name)
+            if typ == 'z':
+                mysite.append('imputil.FuncImporter(archive.ZlibArchive("%s",0).get_code).install()' % nm)
+        if mysite:
+            mysite.insert(0, 'import archive, imputil')
+            open(os.path.join(self.name, 'site.py'),'w').write(string.join(mysite, '\n'))
+            
+            
+class ArchiveTarget(CollectTarget):
+    usefullname = 1
+    def __init__(self, cfg, sectnm, cnvrts):
+        CollectTarget.__init__(self, cfg, sectnm, cnvrts)  
+        archivebuilder.GetCompiled([os.path.join(pyinsthome, 'support', 'carchive_rt.py')])
+        carchmodule = resource.makeresource('carchive_rt.py', [os.path.join(pyinsthome, 'support')])
+        self._dependencies.merge(carchmodule.dependencies())
+        self._dependencies.append(carchmodule)
+
+    def edit(self):
+        if self.destdir:
+            print "Warning 'destdir = %s' ignored for %s" % (self.destdir, self.name)
+            
+    def gather(self):
+        CollectTarget.gather(self)
+    
+    _cdict = {'s':2,'m':1,'b':1,'x':1,'a':0,'z':0, 'p':1}
+    
+    def assemble(self, pkgnm=None):
+        if pkgnm is None:
+            pkgnm = self.name
+        arch = carchive.CArchive()
+        toc = []
+        pytoc = []
+        for nm, path, typ in self.toc.toList():
+            compress = self._cdict[typ]
+            if typ == 'b' or (self.usefullname and typ in 'ms'):
+                nm = os.path.basename(path)
+            if typ == 'm':
+                pytoc.append((nm, path, compress, typ))
+            else:
+                toc.append((nm, path, compress, typ))
+        toc = toc + archivebuilder.GetCompiled(pytoc)
+        arch.build(pkgnm, toc)
+        return arch
+        
+class FullExeTarget(ArchiveTarget):
+    usefullname = 0
+    def __init__(self, cfg, sectnm, cnvrts):
+        ArchiveTarget.__init__(self, cfg, sectnm, cnvrts)
+
+    def gather(self):
+        for script in self.script:
+            #print "FullExeTarget.gather: script is", `script`
+            rsrc = resource.makeresource(script, self.pathprefix)
+            rsrc = resource.scriptresource(rsrc.name, rsrc.path)
+            #print " resource is", `rsrc`
+            self.toc.merge(rsrc.binaries)
+        ArchiveTarget.gather(self)        
+        if not self.zlib:
+            self.toc.merge(rsrc.modules)
+        self._dependencies = ltoc.lTOC()
+        
+    _cdict = {'s':2,'m':0,'b':1,'x':0,'a':0,'z':0}
+    _edict = { (1,1):'Runw_d.exe', (1,0):'Runw.exe', (0,1):'Run_d.exe', (0,0):'Run.exe'}
+
+    def assemble(self):
+        pkgname = tempfile.mktemp()
+        arch = ArchiveTarget.assemble(self, pkgname)
+        exe = self._edict[(self.userunw, self.debug)]
+        exe = os.path.normpath(os.path.join(pyinsthome, 'support', exe))
+##        copyFile([exe, pkgname], self.name)
+##        os.remove(pkgname)
+        # Thomas Heller's icon code
+        # my version
+        if self.icon:
+            myexe = tempfile.mktemp()
+            copyFile (exe, myexe)
+            try:
+                from icon import CopyIcons
+                CopyIcons(myexe, self.icon)
+            except ImportError:
+                print "win32api is required for updating icons"
+                print "You should have win32api.pyd and PyWinTypes20.dll"
+                print "in the installation directory."
+                print "Please copy them to Python's DLLS subdirectory"
+                print "(or install Mark Hammond's Win32 extensions)."
+##        iconfile = None
+##        for name in self.cfg.sections():
+##            if self.cfg.get (name, "type") == "STANDALONE":
+##                try:
+##                    iconfile = self.cfg.get (name, "iconfile")
+##                except:
+##                    pass
+##        if iconfile:
+##            from icon import CopyIcons
+##            CopyIcons (myexe, iconfile)
+            copyFile ([myexe, pkgname], self.name)
+            os.remove(myexe)
+        else:
+            copyFile([exe, pkgname], self.name)
+        #os.remove(pkgname)
+        
+class ExeTarget(FullExeTarget):
+    def __init__(self, cfg, sectnm, cnvrts):
+        FullExeTarget.__init__(self, cfg, sectnm, cnvrts)
+        
+    def edit(self):
+        if not self.script:
+            raise ValueError, "EXE target %s requires 'script= <script>'" % self.__name__
+
+    def gather(self):
+        FullExeTarget.gather(self)
+        for i in range(len(self.toc)-1, -1, -1):
+            rsrc = self.toc[i]
+            if rsrc.typ == 'b':
+                self._dependencies.append(rsrc)
+                del self.toc[i]
+
+installpreamble = """\
+import sys, os
+import installutils
+import carchive_rt
+idir = installutils.getinstalldir()
+me = sys.argv[0]
+if me[:-4] != '.exe':
+    me = me + '.exe'
+this = carchive_rt.CArchive(sys.argv[0])
+here = sys.path[0]
+"""
+mvfile = "installutils.copyFile(os.path.join(here, '%s'), os.path.join(idir, '%s'))\n"
+extractfile = "open(os.path.join(idir, '%s'), 'wb').write(this.extract('%s')[1])\n"
+sitepreamble = """\
+import archive_rt
+import imputil
+import sys
+"""
+importzlib = "imputil.FuncImporter(archive_rt.ZlibArchive(sys.path[0]+'/%s').get_code).install()\n"
+
+class InstallTarget(FullExeTarget):
+    def __init__(self, cfg, sectnm, cnvrts):
+        FullExeTarget.__init__(self, cfg, sectnm, cnvrts)
+
+    def edit(self):
+        if not self.script:
+            open('gen_install.py', 'w').write(installpreamble)
+            self.script = ['gen_install.py']
+
+    def gather(self):
+        FullExeTarget.gather(self)
+        if self.script[0] == 'gen_install.py':
+            f = open(self.script[0], 'a')
+            for rsrc in self.toc:
+                if isinstance(rsrc, resource.binaryresource):
+                    nm = os.path.basename(rsrc.path)
+                    f.write(mvfile % (nm, nm))
+                elif isinstance(rsrc, resource.pythonresource):
+                    pass
+                elif isinstance(rsrc, resource.zlibresource):
+                    pass
+                else:
+                    f.write(extractfile % (rsrc.name, rsrc.name))
+                    if isinstance(rsrc, resource.archiveresource):
+                        #did it come with an install script?
+                        target = built.get(rsrc.name, None)
+                        if target:
+                           if hasattr(target, "installscript"):
+                               for script in target.installscript:
+                                   s = resource.makeresource(script, self.pathprefix)
+                                   txt = open(s.path, 'r').read()
+                                   f.write(txt)
+            f.close()
+        
+dispatch = { 	
+                'PYZ': PYZTarget,
+                'CARCHIVE': ArchiveTarget,
+                'COLLECT': CollectTarget,
+                'STANDALONE': ExeTarget,
+                'INSTALL' : InstallTarget,
+                'FULLEXE' : FullExeTarget,
+}
+
+        
+def makeTarget(cfg, section):
+    return dispatch[cfg.get(section, 'type')](cfg, section, optcnvrts)
+
+optdefaults = {	'type':'PYZ',
+		'script':'',		# INSTALL (opt) & STANDALONE (required)
+		'zlib':'',		# INSTALL, STANDALONE, COLLECT
+		'bindepends':'', 	# INSTALL, COLLECT
+		'misc':'',		# INSTALL. COLLECT
+		'includetk': '0',	# INSTALL, COLLECT
+        'userunw': '0',         # STANDALONE
+		'dependencies':'',	# PYZ
+		'directories':'',	# PYZ
+		'excludes':'',		# PYZ, INSTALL, COLLECT
+		'expatterns': '',
+                'exstdlib' : '0',
+                'extypes' : '',
+		'includes':'',		# PYZ 
+		'packages':'',		# PYZ
+                'destdir':'',		# COLLECT
+                'pathprefix' : '',
+                'trees' : '',
+                'debug' : '0',
+                'support' : '1', # include python20.dll & exceptons.pyc at a minimum
+                'icon': '',
+}   
+
+optcnvrts = {   'type':'',
+                'name' : 'getstring',       
+                'exstdlib': 'getbool', 
+                'console': 'getbool',
+                'analyze' : 'getbool', 
+                'debug' : 'getbool',
+                'includetk' : 'getbool',
+                'userunw': 'getbool',
+                'destdir': 'getstring',
+                'support': 'getbool',
+                '__name__': 'getstring',
+                'icon': 'getstring',
+}
+def main(opts, args):
+    global pyinsthome
+    global copyFile
+    pyinsthome = os.path.abspath(os.path.dirname(sys.argv[0]))
+    sys.path.insert(0, os.path.join(pyinsthome, 'support'))
+    import installutils
+    copyFile = installutils.copyFile
+    global logfile
+    logfile = open('Builder.log','w')
+    targets = []
+    xref = {}
+    cfg = ConfigParser.ConfigParser(optdefaults)
+    for arg in args:
+        dirnm = os.path.dirname(arg)
+        if dirnm == '':
+            dirnm = '.'
+        autopath.append(os.path.abspath(dirnm))
+    cfg.read(args)
+    for section in cfg.sections():
+        target = makeTarget(cfg, section)
+        targets.append(target)
+        xref[section] = target
+    while targets:
+        for i in range(len(targets)):
+            target = targets[i]
+            for child in target.children:
+                if xref[child] in targets:
+                    break
+            else:       #no break - ready to build
+                target.dump()
+                target.build()
+                built[target.__name__] = target
+                built[target.name] = target
+                targets[i] = None
+                break
+        else:       #no break - couldn't find anything to build
+            names = map(lambda x: getattr(x, 'name'), targets)
+            raise RuntimeError, "circular dependencies in %s" % `names`
+        targets = filter(None, targets)
+        
+def run(file):
+    main ([], file)
+    
+if __name__ == '__main__':
+    import getopt
+    (opts, args) = getopt.getopt(sys.argv[1:], 'dv')
+    print "opts:", opts
+    print "args:", args
+    main(opts, args)

+ 246 - 0
direct/src/pyinst/archive.py

@@ -0,0 +1,246 @@
+#
+# Gordon McMillan (as inspired and influenced by Greg Stein)
+#
+
+# 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.
+
+import marshal
+import struct
+
+class Archive:
+  """ A base class for a repository of python code objects.
+  
+      The get_code method is used by imputil.FuntionImporter
+      to get code objects by name.
+      Archives are flat namespaces, so conflict between module
+      names in different packages are possible. Use a different
+      Archive for each package.
+  """
+  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
+  def __init__(self, path=None, start=0):
+    """
+         Initialize an Archive. If path is omitted, it will be an empty Archive.
+         start is the seek position within path where the Archive starts."""
+    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):
+    """Verify version and validity of file.
+    
+        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)
+
+  def loadtoc(self):
+    """Load the table of contents.
+    
+        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.
+
+  def get_code(self, parent, modname, fqname):
+    """The import hook.
+    
+       Called by imputil.FunctionImporter.
+       Override extract to tune getting code from the Archive."""
+    rslt = self.extract(fqname) # None if not found, (ispkg, code) otherwise
+    if rslt is None:
+      return None
+    ispkg, code = rslt
+    if ispkg:
+      return ispkg, code, {'__path__' : []}
+    return rslt
+
+  ####### Core method - Override as needed  #########
+  def extract(self, name):
+    """ Get the object corresponding to name, or None.
+    
+        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.
+    """
+    return self.toc.keys()
+
+  ########################################################################
+  # Building
+  
+  ####### Top level method - shouldn't need overriding #######
+  def build(self, path, lTOC):
+    """Create an archive file of name PATH from LTOC.
+    
+       lTOC is a 'logical TOC' - a list of (name, path, ...)
+       where name is the internal (import) name, 
+       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):
+    """Add an entry to the archive.
+
+      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. 
+    """
+    if self.os is None:
+      import os
+      self.os = os
+    nm = entry[0]
+    pth = entry[1]
+    ispkg = self.os.path.splitext(self.os.path.basename(pth))[0] == '__init__'
+    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):
+    """Save the table of contents.
+
+       Default - toc is a dict
+       Gets marshaled to self.lib
+    """
+    marshal.dump(self.toc, self.lib)
+
+  def save_trailer(self, tocpos):
+    """Placeholder for Archives with trailers."""
+    pass
+
+  def update_headers(self, tocpos):
+    """Update any header data.
+    
+       Default header is  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))
+   
+##############################################################
+#
+# ZlibArchive - an archive with compressed entries
+#
+
+class ZlibArchive(Archive):
+  """A subclass of Archive that compresses entries with zlib
+     and uses a (marshalled) dict as a table of contents"""
+  MAGIC = 'PYZ\0'
+  TOCPOS = 8
+  HDRLEN = 12
+  TRLLEN = 0
+  TOCTMPLT = {}
+  LEVEL = 9
+
+  def __init__(self, path=None, offset=0):
+    Archive.__init__(self, path, offset)
+    # dynamic import so not imported if not needed
+    global zlib
+    import zlib
+   
+  def extract(self, name):
+    """Get the code object for NAME.
+    
+       Return None if name is not in the table of contents.
+       Otherwise, return a tuple (ispkg, code)"""
+    (ispkg, pos, lngth) = self.toc.get(name, (0, None, 0))
+    if pos is None:
+      return None
+    self.lib.seek(self.start + pos)
+    return ispkg, marshal.loads(zlib.decompress(self.lib.read(lngth)))
+
+  def add(self, entry):
+    """Add an entry.
+    
+       ENTRY is a sequence where entry[0] is name and entry[1] is full path name.
+       zlib compress the code object, and build a toc entry"""
+    if self.os is None:
+      import os
+      self.os = os
+    nm = entry[0]
+    pth = entry[1]
+    ispkg = self.os.path.splitext(self.os.path.basename(pth))[0] == '__init__'
+    f = open(pth, 'rb')
+    f.seek(8)	#skip magic and timestamp
+    obj = zlib.compress(f.read(), self.LEVEL)
+    self.toc[nm] = (ispkg, self.lib.tell(), len(obj))
+    self.lib.write(obj)
+ 

+ 81 - 0
direct/src/pyinst/archivebuilder.py

@@ -0,0 +1,81 @@
+# copyright 1999 McMillan Enterprises, Inc.
+# license: use as you please. No warranty.
+# Gordon McMillan [email protected]
+#
+# A collection of routines for building a logical Table Of Contents
+# that Archive (subclasses) use to build themselves.
+# A logical Table of Contents is a sequence, each element of which is
+# a sequence, with at least 2 entries - "name" and "path".
+
+import os
+
+import string
+
+import py_compile
+
+def GetCompiled(seq, lvl='c'):
+  """SEQ is a list of .py files, or a logical TOC.
+     Return as .pyc or .pyo files (LVL) after ensuring their existence"""
+  if len(seq) == 0:
+    return seq
+  rslt = []
+  isTOC = 0
+  if type(seq[0]) == type(()):
+    isTOC = 1
+  for py in seq:
+    if isTOC:
+      (nm, fnm), rest = py[:2], py[2:]
+    else:
+      fnm = py
+    fnm = os.path.splitext(fnm)[0] + '.py'
+    cmpl = 1
+    pyc = fnm + lvl
+    if os.path.exists(pyc):
+      pytm = long(os.stat(fnm)[8])
+      ctm = long(os.stat(pyc)[8])
+      if pytm < ctm:
+        cmpl = 0
+    if cmpl:
+      py_compile.compile(fnm, pyc)
+    if isTOC:
+      rslt.append((nm, pyc)+rest)
+    else:
+      rslt.append(pyc)
+  return rslt
+
+import modulefinder
+MF = modulefinder
+import sys
+
+def Dependencies(script):
+  """Get a logical TOC directly from the dependencies of a script.
+  
+     The returned TOC does NOT contain the script.
+     It does contain extension modules. Uses modulefinder."""
+  rslt = []
+  (dir, name) = os.path.split(script)
+  if dir:
+    ppath = [os.path.normpath(dir)] + sys.path
+  else:
+    ppath = sys.path[:]
+  mf = MF.ModuleFinder(ppath, 0)
+  try:
+    mf.run_script(script)
+  except IOError:
+    print " Script not found:", script
+    return []
+  del mf.modules['__main__']
+  for (k, v) in mf.modules.items():
+    if v.__file__ is None:
+      del mf.modules[k]  # a builtin
+  for (k, v) in mf.modules.items():
+    #ispkg = os.path.basename(v.__file__) == '__init__.py'
+    d = os.path.dirname(v.__file__)
+    if not d:
+      v.__file__ = os.path.join(os.getcwd(), v.__file__)
+    #if ispkg:
+    #    rslt.append(k+'.__init__', v.__file__)
+    #else:
+    rslt.append( (k, v.__file__) )
+  return rslt
+

+ 169 - 0
direct/src/pyinst/bindepend.py

@@ -0,0 +1,169 @@
+# copyright 1999 McMillan Enterprises, Inc.
+# license: use as you please. No warranty.
+#
+# use dumpbin.exe (if present) to find the binary
+# dependencies of an extension module.
+# if dumpbin not available, pick apart the PE hdr of the binary
+# while this appears to work well, it is complex and subject to
+# problems with changes to PE hdrs (ie, this works only on 32 bit Intel
+# Windows format binaries)
+#
+# Note also that you should check the results to make sure that the
+# dlls are redistributable. I've listed most of the common MS dlls
+# under "excludes" below; add to this list as necessary (or use the
+# "excludes" option in the INSTALL section of the config file).
+
+import os
+import time
+import string
+import sys
+import tempfile
+import finder
+
+seen = {}
+excludes = {'KERNEL32.DLL':1, 
+      'ADVAPI.DLL':1, 
+      'MSVCRT.DLL':1,
+      'ADVAPI32.DLL':1,
+      'COMCTL32.DLL':1,
+      'CRTDLL.DLL':1,
+      'GDI32.DLL':1,
+      'MFC42.DLL':1,
+      'NTDLL.DLL':1,
+      'OLE32.DLL':1,
+      'OLEAUT32.DLL':1,
+      'RPCRT4.DLL':1,
+      'SHELL32.DLL':1,
+      'USER32.DLL':1,
+      'WINSPOOL.DRV':1,
+      'WS2HELP.DLL':1,
+      'WS2_32.DLL':1,
+      'WSOCK32.DLL':1,
+      'WINMM.DLL':1,
+      'COMDLG32.DLL':1,
+      'ZLIB.DLL':1,
+      'ODBC32.DLL':1,
+      'VERSION.DLL':1}     
+
+def getfullnameof(mod, xtrapath = None):
+  """Return the full path name of MOD.
+  
+      MOD is the basename of a dll or pyd.
+      XTRAPATH is a path or list of paths to search first.
+      Return the full path name of MOD.
+      Will search the full Windows search path, as well as sys.path"""
+  epath = finder.getpath()
+  if mod[-4:] in ('.pyd', '.PYD'):
+    epath = epath + sys.path
+  if xtrapath is not None:
+    if type(xtrapath) == type(''):
+      epath.insert(0, xtrapath)
+    else:
+      epath = xtrapath + epath
+  for p in epath:
+    npth = os.path.join(p, mod)
+    if os.path.exists(npth):
+      return npth
+  return ''
+  
+def getImports1(pth):
+    """Find the binary dependencies of PTH.
+    
+        This implementation (not used right now) uses the MSVC utility dumpbin"""
+    rslt = []
+    tmpf = tempfile.mktemp()
+    os.system('dumpbin /IMPORTS "%s" >%s' %(pth, tmpf))
+    time.sleep(0.1)
+    txt = open(tmpf,'r').readlines()
+    os.remove(tmpf)
+    i = 0
+    while i < len(txt):
+        tokens = string.split(txt[i])
+        if len(tokens) == 1 and string.find(tokens[0], '.') > 0:
+            rslt.append(string.strip(tokens[0]))
+        i = i + 1
+    return rslt
+    
+def getImports2(pth):
+    """Find the binary dependencies of PTH.
+    
+        This implementation walks through the PE header"""
+    import struct
+    rslt = []
+    try:
+      f = open(pth, 'rb').read()
+      pehdrd = struct.unpack('l', f[60:64])[0]
+      magic = struct.unpack('l', f[pehdrd:pehdrd+4])[0]
+      numsecs = struct.unpack('h', f[pehdrd+6:pehdrd+8])[0]
+      numdirs = struct.unpack('l', f[pehdrd+116:pehdrd+120])[0]
+      idata = ''
+      if magic == 17744:
+          importsec, sz = struct.unpack('2l', f[pehdrd+128:pehdrd+136])
+          secttbl = pehdrd + 120 + 8*numdirs
+          secttblfmt = '8s7l2h'
+          seclist = []
+          for i in range(numsecs):
+              seclist.append(struct.unpack(secttblfmt, f[secttbl+i*40:secttbl+(i+1)*40]))
+              #nm, vsz, va, rsz, praw, preloc, plnnums, qrelocs, qlnnums, flags \
+              # = seclist[-1]
+          for i in range(len(seclist)-1):
+              if seclist[i][2] <= importsec < seclist[i+1][2]:
+                  break
+          vbase = seclist[i][2]
+          raw = seclist[i][4]
+          idatastart = raw + importsec - vbase
+          idata = f[idatastart:idatastart+seclist[i][1]]
+          i = 0
+          while 1:
+              vsa =  struct.unpack('5l', idata[i*20:i*20+20])[3]
+              if vsa == 0:
+                  break
+              sa = raw + vsa - vbase
+              end = string.find(f, '\000', sa)
+              rslt.append(f[sa:end])
+              i = i + 1
+    except IOError:
+      print "bindepend cannot analyze %s - file not found!"
+    except struct.error:
+      print "bindepend cannot analyze %s - error walking thru pehdr"
+    return rslt
+    
+def Dependencies(lTOC):
+  """Expand LTOC to include all the closure of binary dependencies.
+  
+     LTOC is a logical table of contents, ie, a seq of tuples (name, path).
+     Return LTOC expanded by all the binary dependencies of the entries
+     in LTOC, except those listed in the module global EXCLUDES"""
+  for (nm, pth) in lTOC:
+    fullnm = string.upper(os.path.basename(pth))
+    if seen.get(string.upper(nm),0):
+      continue
+    print "analyzing", nm
+    seen[string.upper(nm)] = 1
+    dlls = getImports(pth)
+    for lib in dlls:
+        print " found", lib
+        if excludes.get(string.upper(lib),0):
+          continue
+        if seen.get(string.upper(lib),0):
+          continue
+        npth = getfullnameof(lib)
+        if npth:
+          lTOC.append((lib, npth))
+        else:
+          print " lib not found:", lib, "dependency of", 
+  return lTOC
+  
+        
+##if getfullnameof('dumpbin.exe') == '':
+##    def getImports(pth):
+##        return getImports2(pth)
+##else:
+##    def getImports(pth):
+##        return getImports1(pth)
+        
+def getImports(pth):
+    """Forwards to either getImports1 or getImports2
+    """
+    return getImports2(pth)
+ 

+ 204 - 0
direct/src/pyinst/carchive.py

@@ -0,0 +1,204 @@
+# copyright 1999 McMillan Enterprises, Inc.
+# license: use as you please. No warranty.
+#
+# A subclass of Archive that can be understood
+# by a C program. See uplaunch.cpp for unpacking
+# from C.
+import archive
+import struct
+import zlib
+import strop
+
+class CTOC:
+  """A class encapsulating the table of contents of a CArchive.
+  
+     When written to disk, it is easily read from C."""
+  ENTRYSTRUCT = 'iiiibc' #(structlen, dpos, dlen, ulen, flag, typcd) followed by name
+  def __init__(self):
+    self.data = []
+  
+  def frombinary(self, s):
+    """Decode the binary string into an in memory list.
+    
+        S is a binary string."""
+    entrylen = struct.calcsize(self.ENTRYSTRUCT)
+    p = 0
+    while p<len(s):
+      (slen, dpos, dlen, ulen, flag, typcd) = struct.unpack(self.ENTRYSTRUCT, 
+                                                  s[p:p+entrylen]) 
+      nmlen = slen - entrylen 
+      p = p + entrylen
+      (nm,) = struct.unpack(`nmlen`+'s', s[p:p+nmlen])
+      p = p + nmlen 
+      self.data.append((dpos, dlen, ulen, flag, typcd, nm[:-1]))
+
+  def tobinary(self):
+    """Return self as a binary string."""
+    import string
+    entrylen = struct.calcsize(self.ENTRYSTRUCT)
+    rslt = []
+    for (dpos, dlen, ulen, flag, typcd, nm) in self.data:
+      nmlen = len(nm) + 1	# add 1 for a '\0'
+      rslt.append(struct.pack(self.ENTRYSTRUCT+`nmlen`+'s',
+        nmlen+entrylen, dpos, dlen, ulen, flag, typcd, nm+'\0'))
+    return string.join(rslt, '')
+
+  def add(self, dpos, dlen, ulen, flag, typcd, nm):
+    """Add an entry to the table of contents.
+    
+       DPOS is data position.
+       DLEN is data length.
+       ULEN is the uncompressed data len.
+       FLAG says if the data is compressed.
+       TYPCD is the "type" of the entry (used by the C code)
+       NM is the entry's name."""
+    self.data.append((dpos, dlen, ulen, flag, typcd, nm))
+
+  def get(self, ndx):
+    """return the toc entry (tuple) at index NDX"""
+    return self.data[ndx]
+
+  def __getitem__(self, ndx):
+    return self.data[ndx]
+
+  def find(self, name):
+    """Return the index of the toc entry with name NAME.
+    
+       Return -1 for failure."""
+    for i in range(len(self.data)):
+      if self.data[i][-1] == name:
+        return i
+    return -1
+
+class CArchive(archive.Archive):
+  """An Archive subclass that an hold arbitrary data.
+  
+     Easily handled from C or from Python."""
+  MAGIC = 'MEI\014\013\012\013\015'
+  HDRLEN = 0
+  TOCTMPLT = CTOC
+  TRLSTRUCT = '8siii'
+  TRLLEN = 20
+  LEVEL = 9
+  def __init__(self, path=None, start=0, len=0):
+    """Constructor.
+    
+       PATH is path name of file (create an empty CArchive if path is None).
+       START is the seekposition within PATH.
+       LEN is the length of the CArchive (if 0, then read till EOF). """
+    self.len = len
+    archive.Archive.__init__(self, path, start)
+
+  def checkmagic(self):
+    """Verify that self is a valid CArchive.
+    
+        Magic signature is at end of the archive."""
+    #magic is at EOF; if we're embedded, we need to figure where that is
+    if self.len:
+      self.lib.seek(self.start+self.len, 0)
+    else:
+      self.lib.seek(0, 2)
+    filelen = self.lib.tell()
+    if self.len:
+      self.lib.seek(self.start+self.len-self.TRLLEN, 0)
+    else:
+      self.lib.seek(-self.TRLLEN, 2)
+    (magic, totallen, tocpos, toclen) = struct.unpack(self.TRLSTRUCT, 
+						self.lib.read(self.TRLLEN))
+    if magic != self.MAGIC:
+      raise RuntimeError, "%s is not a valid %s archive file" \
+		% (self.path, self.__class__.__name__)
+    self.pkgstart = filelen - totallen
+    if self.len:
+      if totallen != self.len or self.pkgstart != self.start:
+        raise RuntimeError, "Problem with embedded archive in %s" % self.path
+    self.tocpos, self.toclen = tocpos, toclen
+
+  def loadtoc(self):
+    """Load the table of contents into memory."""
+    self.toc = self.TOCTMPLT()
+    self.lib.seek(self.pkgstart+self.tocpos)
+    tocstr = self.lib.read(self.toclen)
+    self.toc.frombinary(tocstr)
+
+  def extract(self, name):
+    """Get the contents of an entry.
+    
+       NAME is an entry name.
+       Return the tuple (ispkg, contents).
+       For non-Python resoures, ispkg is meaningless (and 0).
+       Used by the import mechanism."""
+    if type(name) == type(''):
+      ndx = self.toc.find(name)
+      if ndx == -1:
+        return None
+    else:
+      ndx = name
+    (dpos, dlen, ulen, flag, typcd, nm) = self.toc.get(ndx)
+    self.lib.seek(self.pkgstart+dpos)
+    rslt = self.lib.read(dlen)
+    if flag == 1:
+      rslt = zlib.decompress(rslt)
+    if typcd == 'M':
+      return (1, rslt)
+    return (0, rslt)
+
+  def contents(self):
+    """Return the names of the entries"""
+    rslt = []
+    for (dpos, dlen, ulen, flag, typcd, nm) in self.toc:
+      rslt.append(nm)
+    return rslt
+
+  def add(self, entry):
+    """Add an ENTRY to the CArchive.
+    
+       ENTRY must have:
+         entry[0] is name (under which it will be saved).
+         entry[1] is fullpathname of the file.
+         entry[2] is a flag for it's storage format (0==uncompressed,
+         1==compressed, 2==Python source format)
+         entry[3] is the entry's type code."""
+    (nm, pathnm, flag, typcd) = entry[:4]
+    if flag == 2:
+        s = open(pathnm, 'r').read()
+        s = s + '\n\0'
+    else:
+        s = open(pathnm, 'rb').read()
+    ulen = len(s)
+    if flag == 1:
+      s = zlib.compress(s, self.LEVEL)
+    dlen = len(s)
+    where = self.lib.tell()
+    if typcd == 'm':
+      if strop.find(pathnm, '.__init__.py') > -1:
+        typcd = 'M'
+    self.toc.add(where, dlen, ulen, flag, typcd, nm)
+    self.lib.write(s)
+
+  def save_toc(self, tocpos):
+    """Save the table of contents to disk."""
+    self.tocpos = tocpos
+    tocstr = self.toc.tobinary()
+    self.toclen = len(tocstr)
+    self.lib.write(tocstr)
+
+  def save_trailer(self, tocpos):
+    """Save the trailer to disk.
+    
+       CArchives can be opened from the end - the trailer points
+       back to the start. """
+    totallen = tocpos + self.toclen + self.TRLLEN
+    trl = struct.pack(self.TRLSTRUCT, self.MAGIC, totallen, 
+                      tocpos, self.toclen)
+    self.lib.write(trl)
+
+  def openEmbedded(self, name):
+    """Open a CArchive of name NAME embedded within this CArchive."""
+    ndx = self.toc.find(name)
+    if ndx == -1:
+      raise KeyError, "Member '%s' not found in %s" % (name, self.path)
+    (dpos, dlen, ulen, flag, typcd, nm) = self.toc.get(ndx)
+    if flag:
+      raise ValueError, "Cannot open compressed archive %s in place"
+    return CArchive(self.path, self.pkgstart+dpos, dlen)

+ 178 - 0
direct/src/pyinst/finder.py

@@ -0,0 +1,178 @@
+# copyright McMillan Enterprises, 1999
+import os, sys
+import string
+
+SCRIPT = 1
+GSCRIPT = 2
+MODULE = 3
+PACKAGE = 4
+PBINARY = 5
+BINARY = 6
+ZLIB = 7
+DIRECTORY = 8
+DATA = 9
+
+_bpath = None
+_ppath = None
+_pcache = {}
+
+def _locate(nm, xtrapath=None, base=None):
+    """Find a file / directory named NM in likely places.
+    
+       XTRAPATH is a list of paths to prepend to BASE.
+       If BASE is None, sys.path (as extended by packages) is used."""
+    ppath = base
+    if base is None:
+        ppath = _ppath
+    if xtrapath:
+        ppath = xtrapath + ppath
+    for pth in ppath:
+        fullnm = os.path.join(pth, nm)
+        #print " _locate trying", fullnm
+        if os.path.exists(fullnm):
+            break
+    else:
+        return ''
+    return fullnm
+
+def _locatepython(name, xtrapath=None):
+    """Locate a Python resource named NAME.
+    
+       All of the standard file extensions will be tried.
+       XTRAPATH is prepended to sys.path."""
+    for ext in ('.py', '.pyc', '.pyw', '.pyo', '.pyd', '.dll'):
+        fullnm = _locate(name+ext, xtrapath)
+        if fullnm:
+            break
+    else:
+        for ext in ('.pyd', '.dll'):
+            fullnm = _locate(name+ext, [], _bpath)
+            if fullnm:
+                break
+    return fullnm
+
+def ispackage(name):
+    """Determine if NAME is the name of a package."""
+    if os.path.exists(os.path.join(name, '__init__.py')):
+        return 1
+    if os.path.exists(os.path.join(name, '__init__.pyc')):
+        return 1
+    if os.path.exists(os.path.join(name, '__init__.pyo')):
+        return 1
+    return 0
+        
+def idtype(fullnm):
+    """Figure out what type of resource FULLNM refers to."""
+    if os.path.isdir(fullnm):
+        if ispackage(fullnm):
+            return PACKAGE
+        return DIRECTORY
+    ext = os.path.splitext(fullnm)[1]
+    if ext:
+        if ext == '.pyd':
+            return PBINARY
+        if ext == '.dll':
+            return BINARY
+        if ext in ('.pyc', '.pyo'):
+            return MODULE
+        if ext == '.py':
+            return SCRIPT
+        if ext == '.pyw':
+            return GSCRIPT
+        if ext == '.pyz':
+            return ZLIB
+    return DATA
+
+def identify(name, xtrapath=None):
+    """Find, and identify the type of NAME, using XTRAPATH as the
+       first place to look.
+
+       Return type, name and full path name.
+       NAME can be a logical or physical name. However, the logical
+       name of a Python module can easily conflict with the physical
+       name of something else, so beware."""
+    if os.path.exists(name):
+        fullnm = name
+    else:
+        if xtrapath is None:
+            xtra = []
+        elif _pcache.has_key(id(xtrapath)):
+            xtra = _pcache[id(xtrapath)]
+        else:
+            xtra = expand(xtrapath)
+            _pcache[id(xtrapath)] = xtra 
+        fullnm = _locate(name, xtra)
+        if not fullnm:
+            fullnm =  _locate(name, [], _bpath)
+            if not fullnm:
+                ext = os.path.splitext(name)[1]
+                if not ext:
+                    fullnm = _locatepython(name, xtra)
+                    if not fullnm:
+                        raise ValueError, "%s not found" % name
+                else:
+                    nm = name
+                    while string.count(nm, '.'):
+                        nm = string.replace(nm, '.', '/', 1)
+                        fullnm = _locatepython(nm, xtra)
+                        if fullnm:
+                            break
+                    else:
+                        raise ValueError, "%s not found" % name
+                    
+    typ = idtype(fullnm)
+    nm = name
+    if typ in (GSCRIPT, SCRIPT, MODULE, PACKAGE, PBINARY):
+        dir, nm = os.path.split(fullnm)
+        nm = os.path.splitext(nm)[0]
+    if typ == SCRIPT:
+        if os.path.exists(fullnm+'c') or os.path.exists(fullnm+'o'):
+            typ = MODULE
+    if typ in (MODULE, PACKAGE):
+        while idtype(dir) == PACKAGE:
+            dir, lnode = os.path.split(dir)
+            nm = lnode+'.'+nm
+    elif typ == BINARY:
+        nm = os.path.basename(fullnm)
+    return typ, nm, fullnm
+ 
+def expand(plist):
+    """ expand a list of paths (like sys.path) to include all the 
+        directories that qualify as packages """
+    pkgdirs = []
+    for pth in plist:
+        os.path.walk(pth, pkgfinder, pkgdirs)
+    return plist + pkgdirs
+
+def pkgfinder(pkgdirs, dir, fnms):
+    i = 0
+    while i < len(fnms):
+        fnm = os.path.join(dir, fnms[i])
+        if os.path.isdir(fnm):
+            if ispackage(fnm):
+                pkgdirs.append(fnm)
+                i = i + 1
+            else:
+                del fnms[i]
+        else:
+            i = i + 1
+
+if _bpath is None:
+    try:
+        import win32api
+    except ImportError:
+        print "Cannot determine your Windows or System directories"
+        print "Please add them to your PATH if .dlls are not found"
+        _bpath = []
+    else:
+        sysdir = win32api.GetSystemDirectory()
+        sysdir2 = os.path.join(sysdir, '../SYSTEM')
+        windir = win32api.GetWindowsDirectory()
+        _bpath = [sysdir, sysdir2, windir]
+    _bpath.extend(string.split(os.environ.get('PATH', ''), ';'))
+if _ppath is None:
+    _ppath = expand(sys.path)
+        
+def getpath():
+    """Return the path that Windows will search for dlls."""
+    return _bpath

+ 138 - 0
direct/src/pyinst/icon.py

@@ -0,0 +1,138 @@
+# This code is courtesy of Thomas Heller, who
+# has kindly donated it to this project.
+RT_ICON = 3
+RT_GROUP_ICON = 14
+LOAD_LIBRARY_AS_DATAFILE = 2
+
+import struct
+
+class Structure:
+    def __init__ (self):
+        size = self._sizeInBytes = struct.calcsize (self._format_)
+        self._fields_ = list (struct.unpack (self._format_, '\000' * size))
+        indexes = self._indexes_ = {}
+        for i in range (len (self._names_)):
+            indexes[self._names_[i]] = i
+    def dump (self):
+        print "DUMP of", self
+        for name in self._names_:
+            if name[0] != '_':
+                print "%20s = %s" % (name, getattr (self, name))
+        print
+    def __getattr__ (self, name):
+        if name in self._names_:
+            index = self._indexes_[name]
+            return self._fields_[index]
+        try:
+            return self.__dict__[name]
+        except KeyError:
+            raise AttributeError, name
+    def __setattr__ (self, name, value):
+        if name in self._names_:
+            index = self._indexes_[name]
+            self._fields_[index] = value
+        else:
+            self.__dict__[name] = value
+    def tostring (self):
+        return apply (struct.pack, [self._format_,] + self._fields_)
+    def fromfile (self, file):
+        data = file.read (self._sizeInBytes)
+        self._fields_ = list (struct.unpack (self._format_, data))
+
+class ICONDIRHEADER (Structure):
+    _names_ = "idReserved", "idType", "idCount"
+    _format_ = "hhh"
+
+class ICONDIRENTRY (Structure):
+    _names_ = "bWidth", "bHeight", "bColorCount", "bReserved", "wPlanes", "wBitCount", "dwBytesInRes", "dwImageOffset"
+    _format_ = "bbbbhhii"
+
+class GRPICONDIR (Structure):
+    _names_ = "idReserved", "idType", "idCount"
+    _format_ = "hhh"
+
+class GRPICONDIRENTRY (Structure):
+    _names_ = "bWidth", "bHeight", "bColorCount", "bReserved", "wPlanes", "wBitCount", "dwBytesInRes", "nID"
+    _format_ = "bbbbhhih"
+
+class IconFile:
+    def __init__ (self, path):
+        self.path = path
+        file = open (path, "rb")
+        self.entries = []
+        self.images = []
+        header = self.header = ICONDIRHEADER()
+        header.fromfile (file)
+        for i in range (header.idCount):
+            entry = ICONDIRENTRY()
+            entry.fromfile (file)
+            self.entries.append (entry)
+        for e in self.entries:
+            file.seek (e.dwImageOffset, 0)
+            self.images.append (file.read (e.dwBytesInRes))
+
+    def grp_icon_dir (self):
+        return self.header.tostring()
+
+    def grp_icondir_entries (self):
+        data = ""
+        i = 1
+        for entry in self.entries:
+            e = GRPICONDIRENTRY()
+            for n in e._names_[:-1]:
+                setattr(e, n, getattr (entry, n))
+            e.nID = i
+            i = i + 1
+            data = data + e.tostring()
+        return data
+            
+
+def CopyIcons_FromIco (dstpath, srcpath):
+    f = IconFile (srcpath)
+    print "Updating icons from", srcpath, "to", dstpath
+    import win32api #, win32con
+    hdst = win32api.BeginUpdateResource (dstpath, 0)
+    data = f.grp_icon_dir()
+    data = data + f.grp_icondir_entries()
+    win32api.UpdateResource (hdst, RT_GROUP_ICON, 1, data)
+    print "Writing RT_GROUP_ICON resource with %d bytes" % len (data)
+    i = 1
+    for data in f.images:
+        win32api.UpdateResource (hdst, RT_ICON, i, data)
+        print "Writing RT_ICON resource with %d bytes" % len (data)
+        i = i + 1
+    win32api.EndUpdateResource (hdst, 0)
+
+def CopyIcons (dstpath, srcpath):
+    import os.path, string
+    index = None
+    try:
+        srcpath, index = map (string.strip, string.split (srcpath, ','))
+        index = int (index)
+    except:
+        pass
+    print "PATH, INDEX", srcpath, index
+    srcext = os.path.splitext (srcpath)[1]
+    if string.lower (srcext) == '.ico':
+        return CopyIcons_FromIco (dstpath, srcpath)
+    if index is not None:
+        print "Updating icons from", srcpath, ", %d to" % index, dstpath
+    else:
+        print "Updating icons from", srcpath, "to", dstpath
+    import win32api #, win32con
+    hdst = win32api.BeginUpdateResource (dstpath, 0)
+    hsrc = win32api.LoadLibraryEx (srcpath, 0, LOAD_LIBRARY_AS_DATAFILE)
+    if index is None:
+        grpname = win32api.EnumResourceNames (hsrc, RT_GROUP_ICON)[0]
+    elif index >= 0:
+        grpname = win32api.EnumResourceNames (hsrc, RT_GROUP_ICON)[index]
+    else:
+        grpname = -index
+    data = win32api.LoadResource (hsrc, RT_GROUP_ICON, grpname)
+    win32api.UpdateResource (hdst, RT_GROUP_ICON, grpname, data)
+    for iconname in win32api.EnumResourceNames (hsrc, RT_ICON):
+        data = win32api.LoadResource (hsrc, RT_ICON, iconname)
+        win32api.UpdateResource (hdst, RT_ICON, iconname, data)
+    win32api.FreeLibrary (hsrc)
+    win32api.EndUpdateResource (hdst, 0)
+

+ 85 - 0
direct/src/pyinst/ltoc.py

@@ -0,0 +1,85 @@
+import os, sys, UserList
+from MEInc.Dist import finder, tocfilter, resource
+
+class lTOC(UserList.UserList):
+    """ A class for managing lists of resources.
+        Should be a UserList subclass. Doh. 
+        Like a list, but has merge(other) and filter() methods """
+    def __init__(self, reslist=None, filters=None):
+        UserList.UserList.__init__(self, reslist)
+        self.filters = []
+        if filters is not None:
+            self.filters = filters[:]
+    def prepend(self, res):
+        self.resources.insert(0, res)
+    def merge(self, other):
+        ' merge in another ltoc, discarding dups and preserving order '
+        tmp = {}
+        for res in self.data:
+            tmp[res.name] = 0
+        for res in other:
+            if tmp.get(res.name, 1):
+                self.data.append(res)
+                tmp[res.name] = 0
+    def filter(self):
+        ' invoke all filters '
+        for i in range(len(self.data)):
+            res = self.data[i]
+            if res:
+                for f in self.filters:
+                    if f.matches(res):
+                        self.data[i] = None
+                        break
+        self.data = filter(None, self.data)
+        return self
+    def unique(self):
+        ' remove all duplicate entries, preserving order '
+        new = self.__class__()
+        new.merge(self)
+        self.data = new.data
+    def toList(self):
+        ' return self as a list of (name, path, typ) '
+        tmp = []
+        for res in self.data:
+            tmp.append((res.name, res.path, res.typ))
+        return tmp
+    def addFilter(self, filter):
+        if type(filter) == type(''):
+            self.filters.append(finder.makeresource(filter).asFilter())
+        else:
+            if type(filter) == type(self):
+                if isinstance(filter, tocfilter._Filter):
+                    self.filters.append(filter)
+                elif isinstance(filter, resource.resource):
+                    self.filters.append(filter.asFilter())
+                else:
+                    raise ValueError, "can't make filter from %s", repr(filter)
+            else:
+                raise ValueError, "can't make filter from %s", repr(filter)
+        print " added filter", `self.filters[-1]`             
+            
+   
+if __name__ == '__main__':
+    sys.path.insert(0, '.')
+    import finder
+    import pprint
+    s = finder.scriptresource('finder.py', './finder.py')
+    ##    pyltoc = lTOC(s.modules)
+    ##    l1 = pyltoc.toList()
+    ##    print "Raw py ltoc:", pprint.pprint(l1)
+    ##    f1 = ModFilter(['dospath', 'macpath', 'posixpath'])
+    ##    l2 = lTOC(s.modules).filter(f1).toList()
+    ##    print "Filter out dospath, macpath, posixpath:", pprint.pprint(l2)
+    ##    f2 = DirFilter(['.'])
+    ##    l3 = lTOC(s.modules).filter(f2).toList()
+    ##    print "Filter out current dir:", pprint.pprint(l3)
+    ##    f3 = StdLibFilter()
+    ##    l4 = lTOC(s.modules).filter(f3).toList()
+    ##    print "Filter out stdlib:", pprint.pprint(l4)
+    ##    #print "Filter out current dir and stdlib:", lTOC(s.modules).filter(f2, f3).toList()
+    binltoc = lTOC(s.binaries)
+    print "Raw bin ltoc:", pprint.pprint(binltoc.toList())
+    binltoc.addFilter('c:/winnt/system32')
+    pprint.pprint(binltoc.filter().toList())
+    
+    

+ 42 - 0
direct/src/pyinst/mkarchive.py

@@ -0,0 +1,42 @@
+import MkWrap
+import imputil
+import strop
+import zlib
+import os
+import marshal
+    
+class MkImporter:
+    def __init__(self, db, viewnm='pylib'):
+        self.db = db
+        self.view = db.getas(viewnm+'[name:S,ispkg:I,code:M]') # an MkWrap view object
+    def setImportHooks(self):
+        imputil.FuncImporter(self.get_code).install()
+    def get_code(self, parent, modname, fqname):
+        if self.view is None:
+            return None
+        ndx = self.view.search(name=fqname)
+        if ndx < len(self.view):
+            row = self.view[ndx]
+            if row.name == fqname:
+                return (row.ispkg, marshal.loads(zlib.decompress(row.code)))
+        return None
+    def build(self, lTOC):
+        for entry in lTOC:
+            nm, fnm = entry[0], entry[1]
+            ispkg = os.path.splitext(os.path.basename(fnm))[0] == '__init__'
+            ndx = self.view.search(name=nm)
+            if ndx < len(self.view):
+                row = self.view[ndx]
+                if row.name != nm:
+                    self.view.insert(ndx, {})
+                    row = self.view[ndx]
+            else:
+                ndx = self.view.append({})
+                row = self.view[ndx]
+            row.name = nm
+            row.ispkg = ispkg
+            f = open(fnm, 'rb')
+            f.seek(8)
+            obj = zlib.compress(f.read(), 9)
+            row.code = obj
+        self.db.commit()

+ 436 - 0
direct/src/pyinst/modulefinder.py

@@ -0,0 +1,436 @@
+"""Find modules used by a script, using introspection."""
+
+import dis
+import imp
+import marshal
+import os
+import re
+import string
+import sys
+
+if sys.platform=="win32":
+    # On Windows, we can locate modules in the registry with
+    # the help of the win32api package.
+    try:
+        import win32api
+    except ImportError:
+        print "The win32api module is not available - modules listed"
+        print "in the registry will not be found."
+        win32api = None
+
+
+IMPORT_NAME = dis.opname.index('IMPORT_NAME')
+IMPORT_FROM = dis.opname.index('IMPORT_FROM')
+
+# Modulefinder does a good job at simulating Python's, but it can not
+# handle __path__ modifications packages make at runtime.  Therefore there
+# is a mechanism whereby you can register extra paths in this map for a
+# package, and it will be honoured.
+
+# Note this is a mapping is lists of paths.
+packagePathMap = {}
+
+# A Public interface
+def AddPackagePath(packagename, path):
+    paths = packagePathMap.get(packagename, [])
+    paths.append(path)
+    packagePathMap[packagename] = paths
+
+class Module:
+
+    def __init__(self, name, file=None, path=None):
+        self.__name__ = name
+        self.__file__ = file
+        self.__path__ = path
+        self.__code__ = None
+
+    def __repr__(self):
+        s = "Module(%s" % `self.__name__`
+        if self.__file__ is not None:
+            s = s + ", %s" % `self.__file__`
+        if self.__path__ is not None:
+            s = s + ", %s" % `self.__path__`
+        s = s + ")"
+        return s
+
+
+class ModuleFinder:
+
+    def __init__(self, path=None, debug=0, excludes = []):
+        if path is None:
+            path = sys.path
+        self.path = path
+        self.modules = {}
+        self.badmodules = {}
+        self.debug = debug
+        self.indent = 0
+        self.excludes = excludes
+
+    def msg(self, level, str, *args):
+        if level <= self.debug:
+            for i in range(self.indent):
+                print "   ",
+            print str,
+            for arg in args:
+                print repr(arg),
+            print
+
+    def msgin(self, *args):
+        level = args[0]
+        if level <= self.debug:
+            self.indent = self.indent + 1
+            apply(self.msg, args)
+
+    def msgout(self, *args):
+        level = args[0]
+        if level <= self.debug:
+            self.indent = self.indent - 1
+            apply(self.msg, args)
+
+    def run_script(self, pathname):
+        self.msg(2, "run_script", pathname)
+        fp = open(pathname)
+        stuff = ("", "r", imp.PY_SOURCE)
+        self.load_module('__main__', fp, pathname, stuff)
+
+    def load_file(self, pathname):
+        dir, name = os.path.split(pathname)
+        name, ext = os.path.splitext(name)
+        fp = open(pathname)
+        stuff = (ext, "r", imp.PY_SOURCE)
+        self.load_module(name, fp, pathname, stuff)
+
+    def import_hook(self, name, caller=None, fromlist=None):
+        self.msg(3, "import_hook", name, caller, fromlist)
+        parent = self.determine_parent(caller)
+        q, tail = self.find_head_package(parent, name)
+        m = self.load_tail(q, tail)
+        if not fromlist:
+            return q
+        if m.__path__:
+            self.ensure_fromlist(m, fromlist)
+
+    def determine_parent(self, caller):
+        self.msgin(4, "determine_parent", caller)
+        if not caller:
+            self.msgout(4, "determine_parent -> None")
+            return None
+        pname = caller.__name__
+        if caller.__path__:
+            parent = self.modules[pname]
+            assert caller is parent
+            self.msgout(4, "determine_parent ->", parent)
+            return parent
+        if '.' in pname:
+            i = string.rfind(pname, '.')
+            pname = pname[:i]
+            parent = self.modules[pname]
+            assert parent.__name__ == pname
+            self.msgout(4, "determine_parent ->", parent)
+            return parent
+        self.msgout(4, "determine_parent -> None")
+        return None
+
+    def find_head_package(self, parent, name):
+        self.msgin(4, "find_head_package", parent, name)
+        if '.' in name:
+            i = string.find(name, '.')
+            head = name[:i]
+            tail = name[i+1:]
+        else:
+            head = name
+            tail = ""
+        if parent:
+            qname = "%s.%s" % (parent.__name__, head)
+        else:
+            qname = head
+        q = self.import_module(head, qname, parent)
+        if q:
+            self.msgout(4, "find_head_package ->", (q, tail))
+            return q, tail
+        if parent:
+            qname = head
+            parent = None
+            q = self.import_module(head, qname, parent)
+            if q:
+                self.msgout(4, "find_head_package ->", (q, tail))
+                return q, tail
+        self.msgout(4, "raise ImportError: No module named", qname)
+        raise ImportError, "No module named " + qname
+
+    def load_tail(self, q, tail):
+        self.msgin(4, "load_tail", q, tail)
+        m = q
+        while tail:
+            i = string.find(tail, '.')
+            if i < 0: i = len(tail)
+            head, tail = tail[:i], tail[i+1:]
+            mname = "%s.%s" % (m.__name__, head)
+            m = self.import_module(head, mname, m)
+            if not m:
+                self.msgout(4, "raise ImportError: No module named", mname)
+                raise ImportError, "No module named " + mname
+        self.msgout(4, "load_tail ->", m)
+        return m
+
+    def ensure_fromlist(self, m, fromlist, recursive=0):
+        self.msg(4, "ensure_fromlist", m, fromlist, recursive)
+        for sub in fromlist:
+            if sub == "*":
+                if not recursive:
+                    all = self.find_all_submodules(m)
+                    if all:
+                        self.ensure_fromlist(m, all, 1)
+            elif not hasattr(m, sub):
+                subname = "%s.%s" % (m.__name__, sub)
+                submod = self.import_module(sub, subname, m)
+                if not submod:
+                    raise ImportError, "No module named " + subname
+
+    def find_all_submodules(self, m):
+        if not m.__path__:
+            return
+        modules = {}
+        suffixes = [".py", ".pyc", ".pyo"]
+        for dir in m.__path__:
+            try:
+                names = os.listdir(dir)
+            except os.error:
+                self.msg(2, "can't list directory", dir)
+                continue
+            for name in names:
+                mod = None
+                for suff in suffixes:
+                    n = len(suff)
+                    if name[-n:] == suff:
+                        mod = name[:-n]
+                        break
+                if mod and mod != "__init__":
+                    modules[mod] = mod
+        return modules.keys()
+
+    def import_module(self, partname, fqname, parent):
+        self.msgin(3, "import_module", partname, fqname, parent)
+        try:
+            m = self.modules[fqname]
+        except KeyError:
+            pass
+        else:
+            self.msgout(3, "import_module ->", m)
+            return m
+        if self.badmodules.has_key(fqname):
+            self.msgout(3, "import_module -> None")
+            self.badmodules[fqname][parent.__name__] = None
+            return None
+        try:
+            fp, pathname, stuff = self.find_module(partname,
+                                                   parent and parent.__path__)
+        except ImportError:
+            self.msgout(3, "import_module ->", None)
+            return None
+        try:
+            m = self.load_module(fqname, fp, pathname, stuff)
+        finally:
+            if fp: fp.close()
+        if parent:
+            setattr(parent, partname, m)
+        self.msgout(3, "import_module ->", m)
+        return m
+
+    def load_module(self, fqname, fp, pathname, (suffix, mode, type)):
+        self.msgin(2, "load_module", fqname, fp and "fp", pathname)
+        if type == imp.PKG_DIRECTORY:
+            m = self.load_package(fqname, pathname)
+            self.msgout(2, "load_module ->", m)
+            return m
+        if type == imp.PY_SOURCE:
+            co = compile(fp.read()+'\n', pathname, 'exec')
+        elif type == imp.PY_COMPILED:
+            if fp.read(4) != imp.get_magic():
+                self.msgout(2, "raise ImportError: Bad magic number", pathname)
+                raise ImportError, "Bad magic number in %s", pathname
+            fp.read(4)
+            co = marshal.load(fp)
+        else:
+            co = None
+        m = self.add_module(fqname)
+        m.__file__ = pathname
+        if co:
+            m.__code__ = co
+            self.scan_code(co, m)
+        self.msgout(2, "load_module ->", m)
+        return m
+
+    def scan_code(self, co, m):
+        code = co.co_code
+        n = len(code)
+        i = 0
+        lastname = None
+        while i < n:
+            c = code[i]
+            i = i+1
+            op = ord(c)
+            if op >= dis.HAVE_ARGUMENT:
+                oparg = ord(code[i]) + ord(code[i+1])*256
+                i = i+2
+            if op == IMPORT_NAME:
+                name = lastname = co.co_names[oparg]
+                if not self.badmodules.has_key(lastname):
+                    try:
+                        self.import_hook(name, m)
+                    except ImportError, msg:
+                        self.msg(2, "ImportError:", str(msg))
+                        if not self.badmodules.has_key(name):
+                            self.badmodules[name] = {}
+                        self.badmodules[name][m.__name__] = None
+            elif op == IMPORT_FROM:
+                name = co.co_names[oparg]
+                assert lastname is not None
+                if not self.badmodules.has_key(lastname):
+                    try:
+                        self.import_hook(lastname, m, [name])
+                    except ImportError, msg:
+                        self.msg(2, "ImportError:", str(msg))
+                        fullname = lastname + "." + name
+                        if not self.badmodules.has_key(fullname):
+                            self.badmodules[fullname] = {}
+                        self.badmodules[fullname][m.__name__] = None
+            else:
+                lastname = None
+        for c in co.co_consts:
+            if isinstance(c, type(co)):
+                self.scan_code(c, m)
+
+    def load_package(self, fqname, pathname):
+        self.msgin(2, "load_package", fqname, pathname)
+        m = self.add_module(fqname)
+        m.__file__ = pathname
+        m.__path__ = [pathname]
+
+        # As per comment at top of file, simulate runtime __path__ additions.
+        m.__path__ = m.__path__ + packagePathMap.get(fqname, [])
+
+        fp, buf, stuff = self.find_module("__init__", m.__path__)
+        self.load_module(fqname, fp, buf, stuff)
+        self.msgout(2, "load_package ->", m)
+        return m
+
+    def add_module(self, fqname):
+        if self.modules.has_key(fqname):
+            return self.modules[fqname]
+        self.modules[fqname] = m = Module(fqname)
+        return m
+
+    def find_module(self, name, path):
+        if name in self.excludes:
+            self.msgout(3, "find_module -> Excluded")
+            raise ImportError, name
+
+        if path is None:
+            if name in sys.builtin_module_names:
+                return (None, None, ("", "", imp.C_BUILTIN))
+
+            # Emulate the Registered Module support on Windows.
+            if sys.platform=="win32" and win32api is not None:
+                HKEY_LOCAL_MACHINE = 0x80000002
+                try:
+                    pathname = win32api.RegQueryValue(HKEY_LOCAL_MACHINE, "Software\\Python\\PythonCore\\%s\\Modules\\%s" % (sys.winver, name))
+                    fp = open(pathname, "rb")
+                    # XXX - To do - remove the hard code of C_EXTENSION.
+                    stuff = "", "rb", imp.C_EXTENSION
+                    return fp, pathname, stuff
+                except win32api.error:
+                    pass
+
+            path = self.path
+        return imp.find_module(name, path)
+
+    def report(self):
+        print
+        print "  %-25s %s" % ("Name", "File")
+        print "  %-25s %s" % ("----", "----")
+        # Print modules found
+        keys = self.modules.keys()
+        keys.sort()
+        for key in keys:
+            m = self.modules[key]
+            if m.__path__:
+                print "P",
+            else:
+                print "m",
+            print "%-25s" % key, m.__file__ or ""
+
+        # Print missing modules
+        keys = self.badmodules.keys()
+        keys.sort()
+        for key in keys:
+            # ... but not if they were explicitely excluded.
+            if key not in self.excludes:
+                mods = self.badmodules[key].keys()
+                mods.sort()
+                print "?", key, "from", string.join(mods, ', ')
+
+
+def test():
+    # Parse command line
+    import getopt
+    try:
+        opts, args = getopt.getopt(sys.argv[1:], "dmp:qx:")
+    except getopt.error, msg:
+        print msg
+        return
+
+    # Process options
+    debug = 1
+    domods = 0
+    addpath = []
+    exclude = []
+    for o, a in opts:
+        if o == '-d':
+            debug = debug + 1
+        if o == '-m':
+            domods = 1
+        if o == '-p':
+            addpath = addpath + string.split(a, os.pathsep)
+        if o == '-q':
+            debug = 0
+        if o == '-x':
+            exclude.append(a)
+
+    # Provide default arguments
+    if not args:
+        script = "hello.py"
+    else:
+        script = args[0]
+
+    # Set the path based on sys.path and the script directory
+    path = sys.path[:]
+    path[0] = os.path.dirname(script)
+    path = addpath + path
+    if debug > 1:
+        print "path:"
+        for item in path:
+            print "   ", `item`
+
+    # Create the module finder and turn its crank
+    mf = ModuleFinder(path, debug, exclude)
+    for arg in args[1:]:
+        if arg == '-m':
+            domods = 1
+            continue
+        if domods:
+            if arg[-2:] == '.*':
+                mf.import_hook(arg[:-2], None, ["*"])
+            else:
+                mf.import_hook(arg)
+        else:
+            mf.load_file(arg)
+    mf.run_script(script)
+    mf.report()
+
+
+if __name__ == '__main__':
+    try:
+        test()
+    except KeyboardInterrupt:
+        print "\n[interrupt]"

+ 317 - 0
direct/src/pyinst/resource.py

@@ -0,0 +1,317 @@
+import os
+import string
+import archivebuilder
+import carchive
+import tocfilter
+import bindepend
+import finder
+
+_cache = {}
+
+def makeresource(name, xtrapath=None):
+    """Factory function that returns a resource subclass.
+    
+       NAME is the logical or physical name of a resource.
+       XTRAPTH is a path or list of paths to search first.
+       return one of the resource subclasses.
+       Warning - logical names can conflict; archive might return a directory,
+       when the module archive.py was desired."""
+    typ, nm, fullname = finder.identify(name, xtrapath)
+    fullname = os.path.normpath(fullname)
+    if _cache.has_key(fullname):
+        return _cache[fullname]
+    elif typ in (finder.SCRIPT, finder.GSCRIPT):
+        rsrc = scriptresource(nm, fullname)
+    elif typ == finder.MODULE:
+        rsrc = moduleresource(nm, fullname)
+    elif typ == finder.PACKAGE:
+        rsrc = pkgresource(nm, fullname)
+    elif typ in (finder.PBINARY, finder.BINARY):
+        rsrc = binaryresource(nm, fullname)
+    elif typ == finder.ZLIB:
+        rsrc = zlibresource(nm, fullname)
+    elif typ == finder.DIRECTORY:
+        rsrc = dirresource(nm, fullname)
+    else:
+        try:
+            carchive.CArchive(fullname)
+        except:
+            rsrc = dataresource(nm, fullname)
+        else:
+            rsrc = archiveresource(nm, fullname)
+    _cache[fullname] = rsrc
+    return rsrc
+
+class resource:
+    """ Base class for all resources.
+    
+        contents() returns of list of what's contained (eg files in dirs)
+        dependencies() for Python resources returns a list of moduleresources
+         and binaryresources """
+    def __init__(self, name, path, typ):
+        """NAME is the logical name of the resource.
+           PATH is the full path to the resource.
+           TYP is the type code.
+           No editting or sanity checks."""
+        self.name = name
+        self.path = path
+        self.typ = typ
+    def __repr__(self):
+        return "(%(name)s, %(path)s, %(typ)s)" % self.__dict__
+    def contents(self):
+        """A list of resources within this resource.
+        
+           Overridable.
+           Base implementation returns [self]"""
+        return [self]
+    def dependencies(self):
+        """A list of resources this resource requires.
+        
+           Overridable.
+           Base implementation returns []"""
+        return []
+    def __cmp__(self, other):
+        if not isinstance(other, self.__class__):
+            return -1
+        return cmp((self.typ, self.name), (other.typ, other.name))
+    def asFilter(self):
+        """Create a tocfilter based on self.
+        
+           Pure virtual"""
+        raise NotImplementedError
+    def asSource(self):
+        """Return self in source form.
+        
+           Base implementation returns self"""
+        return self
+    def asBinary(self):
+        """Return self in binary form.
+        
+           Base implementation returns self"""
+        return self
+
+class pythonresource(resource):
+    """An empty base class.
+    
+       Used to classify resources."""
+    pass
+         
+        
+class scriptresource(pythonresource):
+    """ A top-level python resource.
+    
+        Has (lazily computed) attributes, modules and binaries, which together
+        are the scripts dependencies() """
+    def __init__(self, name, fullname):
+        resource.__init__(self, name, fullname, 's')
+    def __getattr__(self, name):
+        if name == 'modules':
+            print "Analyzing python dependencies of", self.name, self.path
+            self.modules = []
+            self._binaries = []
+            nodes = string.split(self.name, '.')[:-1] # MEInc.Dist.archive -> ['MEInc', 'Dist']
+            for i in range(len(nodes)):
+                nm = string.join(nodes[:i+1], '.')
+                rsrc = makeresource(nm+'.__init__')
+                rsrc.name = nm
+                self.modules.append(rsrc)
+            for (nm, path) in archivebuilder.Dependencies(self.path):
+                path = os.path.normcase(os.path.abspath(path))
+                if os.path.splitext(path)[1] == '.py':
+                    self.modules.append(moduleresource(nm, path))
+                else:
+                    self._binaries.append(binaryresource(nm, path))
+            return self.modules
+        elif name == 'binaries':
+            x = self.modules
+            tmp = {}
+            for br in self._binaries:
+                tmp[br.name] = br
+                for br2 in br.dependencies():
+                    tmp[br2.name] = br2
+            self.binaries = tmp.values()
+            return self.binaries
+        else:
+            raise AttributeError, "%s" % name
+    def dependencies(self):
+        """Return all dependencies (Python and binary) of self."""
+        return self.modules + self.binaries
+    def asFilter(self):
+        """Return a ModFilter based on self."""
+        return tocfilter.ModFilter([self.name])
+    def asSource(self):
+        """Return self as a dataresource (ie, a text file wrapper)."""
+        r = dataresource(self.path) 
+        r.name = apply(os.path.join, string.split(self.name, '.')[:-1]+[r.name])
+        return r 
+               
+class moduleresource(scriptresource):
+    """ A module resource (differs from script in that it will generally 
+        be worked with as a .pyc instead of in source form) """
+    def __init__(self, name, fullname):
+        resource.__init__(self, name, fullname, 'm')
+    def asBinary(self):
+        """Return self as a dataresource (ie, a binary file wrapper)."""
+        r = dataresource(self.path) 
+        r.name = os.path.basename(r.name)
+        r.typ = 'b'
+        return r 
+    def asSource(self):
+        """Return self as a scriptresource (ie, uncompiled form)."""
+        return scriptresource(self.name, self.path[:-1]).asSource()
+        
+class binaryresource(resource):
+    """A .dll or .pyd.
+
+       dependencies() yields more binaryresources """
+    def __init__(self, name, fullname):
+        if string.find(name, '.') == -1:
+            pth, bnm = os.path.split(fullname)
+            junk, ext = os.path.splitext(bnm)
+            fullname = os.path.join(pth, name + ext)
+        resource.__init__(self, name, fullname, 'b')
+        self._depends = None
+    def dependencies(self):
+        """Return a list of binary dependencies."""
+        if self._depends is not None:
+            return self._depends
+        self._depends = []
+        for (lib, path) in bindepend.Dependencies([(self.name, self.path)]):
+            self._depends.append(binaryresource(lib, path))
+        return self._depends
+    def asFilter(self):
+        """Create a FileFilter from self."""
+        return tocfilter.FileFilter([self.name])
+        
+class dataresource(resource):
+    """A subclass for arbitrary files. """
+    def __init__(self, name, fullname=None):
+        resource.__init__(self, name, fullname or name, 'x')
+    def asFilter(self):
+        """Create a FileFilter from self."""
+        return tocfilter.FileFilter([self.name])
+        
+class archiveresource(dataresource):
+    """A sublcass for CArchives. """
+    def __init__(self, name, fullname=None):
+        resource.__init__(self, name, fullname or name, 'a')
+        
+class zlibresource(dataresource):
+    """A subclass for ZlibArchives. """
+    def __init__(self, name, fullname=None):
+        resource.__init__(self, name, fullname or name, 'z')
+        
+class dirresource(resource):
+    """A sublcass for a directory.
+
+       Generally transformed to a list of files through 
+        contents() and filtered by file extensions or resource type. 
+        Note that contents() is smart enough to regard a .py and .pyc
+        as the same resource. """
+    RECURSIVE = 0
+    def __init__(self, name, fullname=None):
+        resource.__init__(self, name, fullname or name, 'd')
+        self._contents = None
+    def contents(self, prefix=''):
+        """Return the list of (typed) resources in self.name"""
+        if self._contents is not None:
+            return self._contents
+        self._contents = []
+        flist = os.listdir(self.path)
+        for fnm in flist:
+            try:
+                bnm, ext = os.path.splitext(fnm)
+                if ext == '.py' and (bnm+'.pyc' in flist or bnm+'.pyo' in flist):
+                    pass
+                elif ext == '.pyo' and (bnm + '.pyc' in flist):
+                    pass
+                else:
+                    rsrc = makeresource(os.path.join(self.path,fnm))
+                    if isinstance(rsrc, pkgresource):
+                        rsrc = self.__class__(rsrc.path)
+                    if self.RECURSIVE:
+                        if isinstance(rsrc, moduleresource) or isinstance(rsrc, scriptresource):
+                            rsrc = rsrc.asSource()
+                            fnm = os.path.basename(rsrc.path)
+                        rsrc.name = os.path.join(prefix, fnm)
+                        if rsrc.typ == 'd':
+                            rsrc.RECURSIVE = 1
+                            self._contents.extend(rsrc.contents(rsrc.name))
+                        else:
+                            self._contents.append(rsrc)
+                    else:
+                        self._contents.append(rsrc)
+            except ValueError,e:
+                raise RuntimeError, "Can't make resource from %s\n ValueError: %s" \
+                      % (os.path.join(self.path, fnm), `e.args`)
+        return self._contents
+    def asFilter(self):
+        return tocfilter.DirFilter([self.path])
+         
+class treeresource(dirresource):
+    """A subclass for a directory and subdirectories."""
+    RECURSIVE = 1
+    def __init__(self, name, fullname=None):
+        dirresource.__init__(self, name, fullname)
+    
+class pkgresource(pythonresource):
+    """A Python package.
+    
+        Note that contents() can be fooled by fancy __path__ statements. """
+    def __init__(self, nm, fullname):
+        resource.__init__(self, nm, fullname, 'p')
+        self._contents = None
+        self._depends = None
+    def contents(self, parent=None):
+        """Return a list of subpackages and modules in self."""
+        if self._contents is not None:
+            return self._contents
+        if parent is None:
+            parent = self.name
+        self._contents = []
+        cheat = treeresource(self.path)
+        for rsrc in cheat.contents():
+            if os.path.splitext(rsrc.path)[1] == '.py':
+                rsrc = moduleresource(string.replace(rsrc.name[:-3], os.sep, '.'),
+                                      rsrc.path)
+                if rsrc.name[-8:] == '__init__':
+                    rsrc.name = rsrc.name[:-9]
+            elif os.path.isdir(rsrc.path):
+                rsrc = makeresource(rsrc.path)
+            else:
+                continue
+            if rsrc.name:
+                rsrc.name = parent + '.' + rsrc.name
+            else:
+                rsrc.name = parent
+            if rsrc.typ == 'm':
+                self._contents.append(rsrc)
+            elif rsrc.typ == 'p':
+                self._contents.extend(rsrc.contents(rsrc.name))
+        return self._contents
+    def dependencies(self):
+        """Return the list of accumulated dependencies of all modules in self."""
+        if self._depends is not None:
+            return self._depends
+        self._depends = []
+        tmp = {}
+        for rsrc in self.contents():
+            for r in rsrc.dependencies():
+                tmp[r.name] = r
+        self._depends = tmp.values()
+        return self._depends
+    def asFilter(self):
+        """Create a PkgFilter from self."""
+        return tocfilter.PkgFilter([os.path.dirname(self.path)])
+        
+        
+        
+        
+        
+        
+        
+if __name__ == '__main__':
+    s = scriptresource('finder.py', './finder.py')
+    print "s.modules:", s.modules
+    print "s.binaries:", s.binaries
+    

+ 131 - 0
direct/src/pyinst/tocfilter.py

@@ -0,0 +1,131 @@
+import os
+import finder
+import re
+import sys
+
+def makefilter(name, xtrapath=None):
+    typ, nm, fullname = finder.identify(name, xtrapath)
+    if typ in (finder.SCRIPT, finder.GSCRIPT, finder.MODULE):
+        return ModFilter([os.path.splitext(nm)[0]])
+    if typ == finder.PACKAGE:
+        return PkgFilter([fullname])
+    if typ == finder.DIRECTORY:
+        return DirFilter([fullname])
+    if typ in (finder.BINARY, finder.PBINARY):
+        return FileFilter([nm])
+    return FileFilter([fullname])
+  
+class _Filter:
+    def __repr__(self):
+        return '<'+self.__class__.__name__+' '+repr(self.elements)+'>'
+    
+class _NameFilter(_Filter):
+    """ A filter mixin that matches (exactly) on name """
+    def matches(self, res):
+        return self.elements.get(res.name, 0)
+        
+class _PathFilter(_Filter):
+    """ A filter mixin that matches if the resource is below any of the paths"""
+    def matches(self, res):
+        p = os.path.normcase(os.path.abspath(res.path))
+        while len(p) > 3:
+            p = os.path.dirname(p)
+            if self.elements.get(p, 0):
+                return 1
+        return 0
+        
+class _ExtFilter(_Filter):
+    """ A filter mixin that matches based on file extensions (either way) """
+    include = 0
+    def matches(self, res):
+        fnd = self.elements.get(os.path.splitext(res.path)[1], 0)
+        if self.include:
+            return not fnd
+        return fnd
+    
+class _TypeFilter(_Filter):
+    """ A filter mixin that matches on resource type (either way) """
+    include = 0
+    def matches(self, res):
+        fnd = self.elements.get(res.typ, 0)
+        if self.include:
+            return not fnd
+        return fnd
+
+class _PatternFilter(_Filter):
+    """ A filter that matches if re.search succeeds on the resource path """
+    def matches(self, res):
+        for regex in self.elements:
+            if regex.search(res.path):
+                return 1
+        return 0
+    
+class ExtFilter(_ExtFilter):
+    """ A file extension filter.
+        ExtFilter(extlist, include=0)
+        where extlist is a list of file extensions """
+    def __init__(self, extlist, include=0):
+        self.elements = {}
+        for ext in extlist:
+            if ext[0:1] != '.':
+                ext = '.'+ext
+            self.elements[ext] = 1
+        self.include = include
+
+class TypeFilter(_TypeFilter):
+    """ A filter for resource types.
+        TypeFilter(typlist, include=0)
+        where typlist is a subset of ['a','b','d','m','p','s','x','z'] """
+    def __init__(self, typlist, include=0):
+        self.elements = {}
+        for typ in typlist:
+            self.elements[typ] = 1
+        self.include = include
+
+class FileFilter(_NameFilter):
+    """ A filter for data files """
+    def __init__(self, filelist):
+        self.elements = {}
+        for f in filelist:
+            self.elements[f] = 1
+              
+class ModFilter(_NameFilter):
+    """ A filter for Python modules.
+        ModFilter(modlist) where modlist is eg ['macpath', 'dospath'] """
+    def __init__(self, modlist):
+        self.elements = {}
+        for mod in modlist:
+            self.elements[mod] = 1
+            
+class DirFilter(_PathFilter):
+    """ A filter based on directories.
+        DirFilter(dirlist)
+        dirs may be relative and will be normalized.
+        Subdirectories of dirs will be excluded. """
+    def __init__(self, dirlist):
+        self.elements = {}
+        for pth in dirlist:
+            pth = os.path.normcase(os.path.abspath(pth))
+            self.elements[pth] = 1
+            
+class PkgFilter(_PathFilter):
+    """At this time, identical to a DirFilter (being lazy) """
+    def __init__(self, pkglist):
+        #warning - pkgs are expected to be full directories
+        self.elements = {}
+        for pkg in pkglist:
+            pth = os.path.normcase(os.path.abspath(pkg))
+            self.elements[pth] = 1
+            
+class StdLibFilter(_PathFilter):
+    """ A filter that excludes anything found in the standard library """
+    def __init__(self):
+        pth = os.path.normcase(os.path.join(sys.exec_prefix, 'lib'))
+        self.elements = {pth:1}
+     
+class PatternFilter(_PatternFilter):
+    """ A filter that excludes if any pattern is found in resource's path """
+    def __init__(self, patterns):
+        self.elements = []
+        for pat in patterns:
+            self.elements.append(re.compile(pat))