Poodletooth-iLand/panda/direct/pyinst/resource.py
2015-03-03 17:10:12 -05:00

317 lines
11 KiB
Python

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 fullname in _cache:
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), repr(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