From 7bb41d91310eb7d5ee21c657beea0d264bcca05a Mon Sep 17 00:00:00 2001 From: Joe Shochet Date: Wed, 9 May 2001 13:48:46 +0000 Subject: [PATCH] *** empty log message *** --- direct/src/pyinst/Builder.py | 15 +- direct/src/pyinst/archive_rt.py | 226 ++++++++++++++ direct/src/pyinst/carchive_rt.py | 157 ++++++++++ direct/src/pyinst/imputil.py | 487 ++++++++++++++++++++++++++++++ direct/src/pyinst/installutils.py | 91 ++++++ direct/src/pyinst/ltoc.py | 170 +++++------ 6 files changed, 1054 insertions(+), 92 deletions(-) create mode 100644 direct/src/pyinst/archive_rt.py create mode 100644 direct/src/pyinst/carchive_rt.py create mode 100644 direct/src/pyinst/imputil.py create mode 100644 direct/src/pyinst/installutils.py diff --git a/direct/src/pyinst/Builder.py b/direct/src/pyinst/Builder.py index d38c8acf37..305927a7d9 100644 --- a/direct/src/pyinst/Builder.py +++ b/direct/src/pyinst/Builder.py @@ -98,11 +98,12 @@ 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')]) + archivebuilder.GetCompiled([os.path.join(pyinsthome, 'imputil.py')]) + print "pyinsthome:", pyinsthome + imputil = resource.makeresource('imputil.py', [pyinsthome]) 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')]) + archivebuilder.GetCompiled([os.path.join(pyinsthome, 'archive_rt.py')]) + archmodule = resource.makeresource('archive_rt.py', [pyinsthome]) self._dependencies.merge(archmodule.dependencies()) self._dependencies.append(archmodule) self.toc.addFilter(archmodule) @@ -244,8 +245,8 @@ 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')]) + archivebuilder.GetCompiled([os.path.join(pyinsthome, 'carchive_rt.py')]) + carchmodule = resource.makeresource('carchive_rt.py', [pyinsthome]) self._dependencies.merge(carchmodule.dependencies()) self._dependencies.append(carchmodule) @@ -456,7 +457,7 @@ 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')) + # sys.path.insert(0, os.path.join(pyinsthome, 'support')) import installutils copyFile = installutils.copyFile global logfile diff --git a/direct/src/pyinst/archive_rt.py b/direct/src/pyinst/archive_rt.py new file mode 100644 index 0000000000..0716ad44fe --- /dev/null +++ b/direct/src/pyinst/archive_rt.py @@ -0,0 +1,226 @@ +# +# 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. + +#archive_rt is a stripped down version of MEInc.Dist.archive. +#It has had all building logic removed. +#It's purpose is to bootstrap the Python installation. + +import marshal +import struct + +class Archive: + """ A base class for a repository of python code objects. + The extract method is used by imputil.ArchiveImporter + to get code objects by name (fully qualified name), so + an enduser "import a.b" would become + extract('a.__init__') + extract('a.b') + """ + MAGIC = 'PYL\0' + HDRLEN = 12 # default is MAGIC followed by python's magic, int pos of toc + TOCPOS = 8 + TRLLEN = 0 # default - no trailer + TOCTMPLT = {} # + os = None + def __init__(self, path=None, start=0): + "Initialize an Archive. If path is omitted, it will be an empty Archive." + self.toc = None + self.path = path + self.start = start + import imp + self.pymagic = imp.get_magic() + if path is not None: + self.lib = open(self.path, 'rb') + self.checkmagic() + self.loadtoc() + + ####### Sub-methods of __init__ - override as needed ############# + def checkmagic(self): + """ Overridable. + Check to see if the file object self.lib actually has a file + we understand. + """ + self.lib.seek(self.start) #default - magic is at start of file + if self.lib.read(len(self.MAGIC)) != self.MAGIC: + raise RuntimeError, "%s is not a valid %s archive file" \ + % (self.path, self.__class__.__name__) + if self.lib.read(len(self.pymagic)) != self.pymagic: + raise RuntimeError, "%s has version mismatch to dll" % (self.path) + + def loadtoc(self): + """ Overridable. + Default: After magic comes an int (4 byte native) giving the + position of the TOC within self.lib. + Default: The TOC is a marshal-able string. + """ + self.lib.seek(self.start + self.TOCPOS) + (offset,) = struct.unpack('=i', self.lib.read(4)) + self.lib.seek(self.start + offset) + self.toc = marshal.load(self.lib) + + ######## This is what is called by FuncImporter ####### + ## Since an Archive is flat, we ignore parent and modname. + + def get_code(self, parent, modname, fqname): + print "parent: ", parent + print "modname: ", modname + print "fqname: ", fqname + return 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. + For use with imputil ArchiveImporter, object is a python code object. + 'name' is the name as specified in an 'import name'. + 'import a.b' will become: + extract('a') (return None because 'a' is not a code object) + extract('a.__init__') (return a code object) + extract('a.b') (return a code object) + Default implementation: + self.toc is a dict + self.toc[name] is pos + self.lib has the code object marshal-ed at pos + """ + ispkg, pos = self.toc.get(name, (0,None)) + if pos is None: + return None + self.lib.seek(self.start + pos) + return ispkg, marshal.load(self.lib) + + ######################################################################## + # Informational methods + + def contents(self): + """Return a list of the contents + Default implementation assumes self.toc is a dict like object. + Not required by ArchiveImporter. + """ + return self.toc.keys() + + ######################################################################## + # Building + + ####### Top level method - shouldn't need overriding ####### +## def build(self, path, lTOC): +## """Create an archive file of name 'path'. +## lTOC is a 'logical TOC' - a list of (name, path, ...) +## where name is the internal name, eg 'a' +## and path is a file to get the object from, eg './a.pyc'. +## """ +## self.path = path +## self.lib = open(path, 'wb') +## #reserve space for the header +## if self.HDRLEN: +## self.lib.write('\0'*self.HDRLEN) +## +## #create an empty toc +## +## if type(self.TOCTMPLT) == type({}): +## self.toc = {} +## else: # assume callable +## self.toc = self.TOCTMPLT() +## +## for tocentry in lTOC: +## self.add(tocentry) # the guts of the archive +## +## tocpos = self.lib.tell() +## self.save_toc(tocpos) +## if self.TRLLEN: +## self.save_trailer(tocpos) +## if self.HDRLEN: +## self.update_headers(tocpos) +## self.lib.close() +## +## +## ####### manages keeping the internal TOC and the guts in sync ####### +## def add(self, entry): +## """Override this to influence the mechanics of the Archive. +## Assumes entry is a seq beginning with (nm, pth, ...) where +## nm is the key by which we'll be asked for the object. +## pth is the name of where we find the object. Overrides of +## get_obj_from can make use of further elements in entry. +## """ +## if self.os is None: +## import os +## self.os = os +## nm = entry[0] +## pth = entry[1] +## 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): +## """Default - toc is a dict +## Gets marshaled to self.lib +## """ +## marshal.dump(self.toc, self.lib) +## +## def save_trailer(self, tocpos): +## """Default - not used""" +## pass +## +## def update_headers(self, tocpos): +## """Default - MAGIC + Python's magic + tocpos""" +## self.lib.seek(self.start) +## self.lib.write(self.MAGIC) +## self.lib.write(self.pymagic) +## self.lib.write(struct.pack('=i', tocpos)) + +############################################################## +# +# ZlibArchive - an archive with compressed entries +# + +class ZlibArchive(Archive): + 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): + (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): +## 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) +## diff --git a/direct/src/pyinst/carchive_rt.py b/direct/src/pyinst/carchive_rt.py new file mode 100644 index 0000000000..1ba273d2f5 --- /dev/null +++ b/direct/src/pyinst/carchive_rt.py @@ -0,0 +1,157 @@ +# 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. + +#carchive_rt is a stripped down version of MEInc.Dist.carchive. +#It has had all building logic removed. +#It's purpose is to bootstrap the Python installation. + +import archive_rt +import struct +import zlib +import strop + +class CTOC: + ENTRYSTRUCT = 'iiiibc' #(structlen, dpos, dlen, ulen, flag, typcd) followed by name + def __init__(self): + self.data = [] + + def frombinary(self, s): + entrylen = struct.calcsize(self.ENTRYSTRUCT) + p = 0 + while p -1: +## typcd = 'M' +## self.toc.add(where, dlen, ulen, flag, typcd, nm) +## self.lib.write(s) +## +## def save_toc(self, tocpos): +## self.tocpos = tocpos +## tocstr = self.toc.tobinary() +## self.toclen = len(tocstr) +## self.lib.write(tocstr) +## +## def save_trailer(self, tocpos): +## 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): + 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) diff --git a/direct/src/pyinst/imputil.py b/direct/src/pyinst/imputil.py new file mode 100644 index 0000000000..5326c69102 --- /dev/null +++ b/direct/src/pyinst/imputil.py @@ -0,0 +1,487 @@ +# +# imputil.py +# +# Written by Greg Stein. Public Domain. +# No Copyright, no Rights Reserved, and no Warranties. +# +# Utilities to help out with custom import mechanisms. +# +# Additional modifications were contribed by Marc-Andre Lemburg and +# Gordon McMillan. +# + +__version__ = '0.3' + +# note: avoid importing non-builtin modules +import imp +import sys +import strop +import __builtin__ ### why this instead of just using __builtins__ ?? + +# for the DirectoryImporter +import struct +import marshal + +class Importer: + "Base class for replacing standard import functions." + + def install(self): + self.__chain_import = __builtin__.__import__ + self.__chain_reload = __builtin__.reload + __builtin__.__import__ = self._import_hook + __builtin__.reload = self._reload_hook + + ###################################################################### + # + # PRIVATE METHODS + # + def _import_hook(self, name, globals=None, locals=None, fromlist=None): + """Python calls this hook to locate and import a module. + + This method attempts to load the (dotted) module name. If it cannot + find it, then it delegates the import to the next import hook in the + chain (where "next" is defined as the import hook that was in place + at the time this Importer instance was installed). + """ + + # determine the context of this import + parent = self._determine_import_context(globals) + + # import the module within the context, or from the default context + top, tail = self._import_top_module(parent, name) + if top is None: + # the module was not found; delegate to the next import hook + return self.__chain_import(name, globals, locals, fromlist) + + # the top module may be under the control of a different importer. + # if so, then defer to that importer for completion of the import. + # note it may be self, or is undefined so we (self) may as well + # finish the import. + importer = top.__dict__.get('__importer__', self) + return importer._finish_import(top, tail, fromlist) + + def _finish_import(self, top, tail, fromlist): + # if "a.b.c" was provided, then load the ".b.c" portion down from + # below the top-level module. + bottom = self._load_tail(top, tail) + + # if the form is "import a.b.c", then return "a" + if not fromlist: + # no fromlist: return the top of the import tree + return top + + # the top module was imported by self, or it was not imported through + # the Importer mechanism and self is simply handling the import of + # the sub-modules and fromlist. + # + # this means that the bottom module was also imported by self, or we + # are handling things in the absence of a prior Importer + # + # ### why the heck are we handling it? what is the example scenario + # ### where this happens? note that we can't determine is_package() + # ### for non-Importer modules. + # + # since we imported/handled the bottom module, this means that we can + # also handle its fromlist (and reliably determine is_package()). + + # if the bottom node is a package, then (potentially) import some modules. + # + # note: if it is not a package, then "fromlist" refers to names in + # the bottom module rather than modules. + # note: for a mix of names and modules in the fromlist, we will + # import all modules and insert those into the namespace of + # the package module. Python will pick up all fromlist names + # from the bottom (package) module; some will be modules that + # we imported and stored in the namespace, others are expected + # to be present already. + if self._is_package(bottom.__dict__): + self._import_fromlist(bottom, fromlist) + + # if the form is "from a.b import c, d" then return "b" + return bottom + + def _reload_hook(self, module): + "Python calls this hook to reload a module." + + # reloading of a module may or may not be possible (depending on the + # importer), but at least we can validate that it's ours to reload + importer = module.__dict__.get('__importer__', None) + if importer is not self: + return self.__chain_reload(module) + + # okay. it is ours, but we don't know what to do (yet) + ### we should blast the module dict and do another get_code(). need to + ### flesh this out and add proper docco... + raise SystemError, "reload not yet implemented" + + def _determine_import_context(self, globals): + """Returns the context in which a module should be imported. + + The context could be a loaded (package) module and the imported module + will be looked for within that package. The context could also be None, + meaning there is no context -- the module should be looked for as a + "top-level" module. + """ + + if not globals or \ + globals.get('__importer__', None) is not self: + # globals does not refer to one of our modules or packages. + # That implies there is no relative import context, and it + # should just pick it off the standard path. + return None + + # The globals refer to a module or package of ours. It will define + # the context of the new import. Get the module/package fqname. + parent_fqname = globals['__name__'] + + # for a package, return itself (imports refer to pkg contents) + if self._is_package(globals): + parent = sys.modules[parent_fqname] + assert globals is parent.__dict__ + return parent + + i = strop.rfind(parent_fqname, '.') + + # a module outside of a package has no particular import context + if i == -1: + return None + + # for a module in a package, return the package (imports refer to siblings) + parent_fqname = parent_fqname[:i] + parent = sys.modules[parent_fqname] + assert parent.__name__ == parent_fqname + return parent + + def _import_top_module(self, parent, name): + """Locate the top of the import tree (relative or absolute). + + parent defines the context in which the import should occur. See + _determine_import_context() for details. + + Returns a tuple (module, tail). module is the loaded (top-level) module, + or None if the module is not found. tail is the remaining portion of + the dotted name. + """ + i = strop.find(name, '.') + if i == -1: + head = name + tail = "" + else: + head = name[:i] + tail = name[i+1:] + if parent: + fqname = "%s.%s" % (parent.__name__, head) + else: + fqname = head + module = self._import_one(parent, head, fqname) + if module: + # the module was relative, or no context existed (the module was + # simply found on the path). + return module, tail + if parent: + # we tried relative, now try an absolute import (from the path) + module = self._import_one(None, head, head) + if module: + return module, tail + + # the module wasn't found + return None, None + + def _import_one(self, parent, modname, fqname): + "Import a single module." + + # has the module already been imported? + try: + return sys.modules[fqname] + except KeyError: + pass + + # load the module's code, or fetch the module itself + result = self.get_code(parent, modname, fqname) + if result is None: + return None + + # did get_code() return an actual module? (rather than a code object) + is_module = type(result[1]) is type(sys) + + # use the returned module, or create a new one to exec code into + if is_module: + module = result[1] + else: + module = imp.new_module(fqname) + + ### record packages a bit differently?? + module.__importer__ = self + module.__ispkg__ = result[0] + + # if present, the third item is a set of values to insert into the module + if len(result) > 2: + module.__dict__.update(result[2]) + + # the module is almost ready... make it visible + sys.modules[fqname] = module + + # execute the code within the module's namespace + if not is_module: + exec result[1] in module.__dict__ + + # insert the module into its parent + if parent: + setattr(parent, modname, module) + return module + + def _load_tail(self, m, tail): + """Import the rest of the modules, down from the top-level module. + + Returns the last module in the dotted list of modules. + """ + if tail: + for part in strop.splitfields(tail, '.'): + fqname = "%s.%s" % (m.__name__, part) + m = self._import_one(m, part, fqname) + if not m: + raise ImportError, "No module named " + fqname + return m + + def _import_fromlist(self, package, fromlist): + 'Import any sub-modules in the "from" list.' + + # if '*' is present in the fromlist, then look for the '__all__' variable + # to find additional items (modules) to import. + if '*' in fromlist: + fromlist = list(fromlist) + list(package.__dict__.get('__all__', [])) + + for sub in fromlist: + # if the name is already present, then don't try to import it (it + # might not be a module!). + if sub != '*' and not hasattr(package, sub): + subname = "%s.%s" % (package.__name__, sub) + submod = self._import_one(package, sub, subname) + if not submod: + raise ImportError, "cannot import name " + subname + + def _is_package(self, module_dict): + """Determine if a given module (dictionary) specifies a package. + + The package status is in the module-level name __ispkg__. The module + must also have been imported by self, so that we can reliably apply + semantic meaning to __ispkg__. + + ### weaken the test to issubclass(Importer)? + """ + return module_dict.get('__importer__', None) is self and \ + module_dict['__ispkg__'] + + ###################################################################### + # + # METHODS TO OVERRIDE + # + def get_code(self, parent, modname, fqname): + """Find and retrieve the code for the given module. + + parent specifies a parent module to define a context for importing. It + may be None, indicating no particular context for the search. + + modname specifies a single module (not dotted) within the parent. + + fqname specifies the fully-qualified module name. This is a (potentially) + dotted name from the "root" of the module namespace down to the modname. + If there is no parent, then modname==fqname. + + This method should return None, a 2-tuple, or a 3-tuple. + + * If the module was not found, then None should be returned. + + * The first item of the 2- or 3-tuple should be the integer 0 or 1, + specifying whether the module that was found is a package or not. + + * The second item is the code object for the module (it will be + executed within the new module's namespace). This item can also + be a fully-loaded module object (e.g. loaded from a shared lib). + + * If present, the third item is a dictionary of name/value pairs that + will be inserted into new module before the code object is executed. + This provided in case the module's code expects certain values (such + as where the module was found). When the second item is a module + object, then these names/values will be inserted *after* the module + has been loaded/initialized. + """ + raise RuntimeError, "get_code not implemented" + + +###################################################################### +# +# Simple function-based importer +# +class FuncImporter(Importer): + "Importer subclass to use a supplied function rather than method overrides." + def __init__(self, func): + self.func = func + def get_code(self, parent, modname, fqname): + return self.func(parent, modname, fqname) + +def install_with(func): + FuncImporter(func).install() + + +###################################################################### +# +# Base class for archive-based importing +# +class PackageArchiveImporter(Importer): + "Importer subclass to import from (file) archives." + + def get_code(self, parent, modname, fqname): + if parent: + # if a parent "package" is provided, then we are importing a sub-file + # from the archive. + result = self.get_subfile(parent.__archive__, modname) + if result is None: + return None + if type(result) == type(()): + return (0,) + result + return 0, result + + # no parent was provided, so the archive should exist somewhere on the + # default "path". + archive = self.get_archive(modname) + if archive is None: + return None + return 1, "", {'__archive__':archive} + + def get_archive(self, modname): + """Get an archive of modules. + + This method should locate an archive and return a value which can be + used by get_subfile to load modules from it. The value may be a simple + pathname, an open file, or a complex object that caches information + for future imports. + + Return None if the archive was not found. + """ + raise RuntimeError, "get_archive not implemented" + + def get_subfile(self, archive, modname): + """Get code from a subfile in the specified archive. + + Given the specified archive (as returned by get_archive()), locate + and return a code object for the specified module name. + + A 2-tuple may be returned, consisting of a code object and a dict + of name/values to place into the target module. + + Return None if the subfile was not found. + """ + raise RuntimeError, "get_subfile not implemented" + + +class PackageArchive(PackageArchiveImporter): + "PackageArchiveImporter subclass that refers to a specific archive." + + def __init__(self, modname, archive_pathname): + self.__modname = modname + self.__path = archive_pathname + + def get_archive(self, modname): + if modname == self.__modname: + return self.__path + return None + + # get_subfile is passed the full pathname of the archive + + +###################################################################### +# +# Emulate the standard directory-based import mechanism +# + +class DirectoryImporter(Importer): + "Importer subclass to emulate the standard importer." + + def __init__(self, dir): + self.dir = dir + self.ext_char = __debug__ and 'c' or 'o' + self.ext = '.py' + self.ext_char + + def get_code(self, parent, modname, fqname): + if parent: + dir = parent.__pkgdir__ + else: + dir = self.dir + + # pull the os module from our instance data. we don't do this at the + # top-level, because it isn't a builtin module (and we want to defer + # loading non-builtins until as late as possible). + try: + os = self.os + except AttributeError: + import os + self.os = os + + pathname = os.path.join(dir, modname) + if os.path.isdir(pathname): + values = { '__pkgdir__' : pathname } + ispkg = 1 + pathname = os.path.join(pathname, '__init__') + else: + values = { } + ispkg = 0 + + t_py = self._timestamp(pathname + '.py') + t_pyc = self._timestamp(pathname + self.ext) + if t_py is None and t_pyc is None: + return None + code = None + if t_py is None or (t_pyc is not None and t_pyc >= t_py): + f = open(pathname + self.ext, 'rb') + if f.read(4) == imp.get_magic(): + t = struct.unpack('' % (self.__class__.__module__, + self.__class__.__name__, + self.dir, + id(self)) + +def _test_dir(): + "Debug/test function to create DirectoryImporters from sys.path." + path = sys.path[:] + path.reverse() + for d in path: + DirectoryImporter(d).install() + +###################################################################### diff --git a/direct/src/pyinst/installutils.py b/direct/src/pyinst/installutils.py new file mode 100644 index 0000000000..66eca01346 --- /dev/null +++ b/direct/src/pyinst/installutils.py @@ -0,0 +1,91 @@ +# copyright 1999 McMillan Enterprises, Inc. +# demo code - use as you please. +import os +import stat + +def copyFile(srcFiles, destFile, append=0): + ''' + Copy one or more files to another file. If srcFiles is a list, then all + will be concatenated together to destFile. The append flag is also valid + for single file copies. + + destFile will have the mode, ownership and timestamp of the last file + copied/appended. + ''' + if type(srcFiles) == type([]): + # in case we need to overwrite on the first file... + copyFile(srcFiles[0], destFile, append) + for file in srcFiles[1:]: + copyFile(file, destFile, 1) + return + + mode = 'wb' + if append: + mode = 'ab' + print " ", srcFiles, "->", + input = open(srcFiles, 'rb') + if input: + print destFile + output = open(destFile, mode) + while 1: + bytesRead = input.read(8192) + if bytesRead: + output.write(bytesRead) + else: + break + + input.close() + output.close() + + stats = os.stat(srcFiles) + os.chmod(destFile, stats[stat.ST_MODE]) + try: # FAT16 file systems have only one file time + os.utime(destFile, (stats[stat.ST_ATIME], stats[stat.ST_MTIME])) + except: + pass + try: + os.chown(destFile, stats[stat.ST_UID], stats[stat.ST_GID]) + except: + pass + +def ensure(dirct): + dirnm = dirct + plist = [] + try: + while not os.path.exists(dirnm): + dirnm, base = os.path.split(dirnm) + if base == '': + break + plist.insert(0, base) + for d in plist: + dirnm = os.path.join(dirnm, d) + os.mkdir(dirnm) + except: + return 0 + return 1 + +def getinstalldir(prompt="Enter an installation directory: "): + while 1: + installdir = raw_input("Enter an installation directory: ") + installdir = os.path.normpath(installdir) + if ensure(installdir): + break + else: + print installdir, "is not a valid pathname" + r = raw_input("Try again (y/n)?: ") + if r in 'nN': + sys.exit(0) + return installdir + +def installCArchive(nm, basedir, suffixdir): + import carchive_rt + fulldir = os.path.join(basedir, suffixdir) + if ensure(fulldir): + pkg = carchive_rt.CArchive(nm) + for fnm in pkg.contents(): + stuff = pkg.extract(fnm)[1] + outnm = os.path.join(fulldir, fnm) + if ensure(os.path.dirname(outnm)): + open(outnm, 'wb').write(stuff) + pkg = None + os.remove(nm) diff --git a/direct/src/pyinst/ltoc.py b/direct/src/pyinst/ltoc.py index c4b841710b..da51d50340 100644 --- a/direct/src/pyinst/ltoc.py +++ b/direct/src/pyinst/ltoc.py @@ -1,85 +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()) - - +import os, sys, UserList +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()) + +