Commit 7f5fa3fd authored by Anders Blomdell's avatar Anders Blomdell
Browse files

Improve code loading

parent ff37baca
apa 100755 → 100644
...@@ -2,12 +2,12 @@ ...@@ -2,12 +2,12 @@
""" """
Anders Python Archiver Anders Python Archiver
Copyright (C) 2004 Anders Blomdell <anders.blomdell@control.lth.se> Copyright (C) 2004-2009 Anders Blomdell <anders.blomdell@control.lth.se>
A small utility program to join a number of python modules A small utility program to join a number of python modules
into a single executable python program. into a single executable python program.
http://www.control.lth.se/~andersb/software/apa http://www.control.lth.se/user/andersb/software/apa
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
...@@ -39,17 +39,15 @@ def getModuleName(s): ...@@ -39,17 +39,15 @@ def getModuleName(s):
return string.replace(m.group(1), "/", ".") return string.replace(m.group(1), "/", ".")
return None return None
def emitCode(f, module, name, filename, code): def emitCode(f, module, filename, code):
print >> sys.stderr, "EMIT:", name print >> sys.stderr, "EMIT:", module
print >> f, '"%s" : ( "%s", "%s", """%s""")' % (quote(module), print >> f, '"%s" : ( "%s", """%s""")' % (quote(module),
quote(name), quote(filename),
quote(filename), quote(code))
quote(code))
def quote(s): def quote(s):
return string.replace(string.replace(s, '\\', '\\\\'), '"', '\\"') return string.replace(string.replace(s, '\\', '\\\\'), '"', '\\"')
if __name__ == '__main__': if __name__ == '__main__':
usage = "%prog [options] <main module> <additional modules>*" usage = "%prog [options] <main module> <additional modules>*"
optParser = optparse.OptionParser(usage=usage) optParser = optparse.OptionParser(usage=usage)
...@@ -59,6 +57,10 @@ if __name__ == '__main__': ...@@ -59,6 +57,10 @@ if __name__ == '__main__':
optParser.add_option('-o','--output', optParser.add_option('-o','--output',
action='store', action='store',
help='Name of archive') help='Name of archive')
optParser.add_option('-s','--strip',
action='append',
default=[],
help='Strip this part from filenames')
(options, args) = optParser.parse_args(sys.argv[1:]) (options, args) = optParser.parse_args(sys.argv[1:])
if options.documentation: if options.documentation:
...@@ -68,10 +70,17 @@ if __name__ == '__main__': ...@@ -68,10 +70,17 @@ if __name__ == '__main__':
# Read all python files # Read all python files
code = [] code = []
for filename in args: for filename in args:
name = getModuleName(filename) archivename = filename
for strip in options.strip:
m = re.match("^%s/*(.*)" % strip, filename)
if m:
archivename = m.group(1)
break
name = getModuleName(archivename)
if name: if name:
f = open(filename) f = open(filename)
code.append((name, filename, f.read())) code.append((name, archivename, f.read()))
f.close() f.close()
else: else:
print "Illegal filename '%s'" % filename print "Illegal filename '%s'" % filename
...@@ -81,7 +90,7 @@ if __name__ == '__main__': ...@@ -81,7 +90,7 @@ if __name__ == '__main__':
apa = file(options.output, 'w') apa = file(options.output, 'w')
else: else:
apa = None apa = None
# Emit code # Emit code
interpreter = code[0][2].splitlines()[0] interpreter = code[0][2].splitlines()[0]
if interpreter.find("python") >= 0: if interpreter.find("python") >= 0:
...@@ -98,7 +107,7 @@ if __name__ == '__main__': ...@@ -98,7 +107,7 @@ if __name__ == '__main__':
for (n, f, c) in code[1:]: for (n, f, c) in code[1:]:
print >> apa, " %-20s %s" % (n, f) print >> apa, " %-20s %s" % (n, f)
print >> apa, """ print >> apa, """
Archive created by 'apa' (http://www.control.lth.se/~andersb/software/apa) Archive created by 'apa' (http://www.control.lth.se/user/andersb/software/apa)
To extract as individual files: To extract as individual files:
...@@ -111,82 +120,76 @@ To extract as individual files: ...@@ -111,82 +120,76 @@ To extract as individual files:
""" """
print >> apa, "code = {" print >> apa, "code = {"
(n, f, c) = code[0] (n, f, c) = code[0]
emitCode(apa, '__apa__main__', '__main__', f, c) emitCode(apa, '__main__', f, c)
for (n, f, c) in code[1:]: for (n, f, c) in code[1:]:
print >> apa, "," print >> apa, ","
emitCode(apa, n, n, f, c) emitCode(apa, n, f, c)
print >> apa, "}" print >> apa, "}"
print >> apa, """ print >> apa, """
import exceptions
import ihooks
import imp
import os
import os.path
import sys
import traceback
class StringImporter(ihooks.ModuleImporter, object): class Importer:
\"\"\"Loads modules from local code dictionary \"\"\"Loads modules from local code dictionary
\"\"\" \"\"\"
def __init__(self, code_dict): def __init__(self, code):
super(StringImporter, self).__init__() self.code = code;
self.code_dict = code_dict; self.path = "<%s>" % str(self.__class__)
self.loaded = {} if not self.path in sys.path:
self.result = None sys.path.insert(0, self.path)
def import_it(self, partname, fqname, parent, force_load=0): def __call__(self, path):
try: if path == self.path:
# First shot, return part from parent module return self
return parent.__dict__[partname] return None
except (KeyError, AttributeError):
pass def find_module(self, fullname):
try: try:
# Second shot, load it from already loaded code self.code[fullname]
return self.loaded[fqname] return self
except (KeyError, AttributeError): except:
pass return None
def load_module(self, fullname):
mod = sys.modules.setdefault(fullname, imp.new_module(fullname))
(filename, src) = self.code[fullname]
mod.__file__ = filename
mod.__loader__ = self
mod.__path__ = [ self.path ]
global BAD
BAD = None
try: try:
# Third shot, load it from code_dictionary code = compile(src, "%s/%s" % (self.path, filename), 'exec')
(name, filename, code) = self.code_dict[fqname] exec code in mod.__dict__
module = self.loader.hooks.add_module(fqname) except exceptions.SystemExit, e:
self.loaded[fqname] = module # Silently propagate exit
module.__name__ = name raise e
module.__file__ = filename except Exception, e:
try: # Silently propagate other exceptions as well
comp = compile(code, filename, 'exec') BAD = sys.exc_info()
exec comp in module.__dict__ raise e
except exceptions.SystemExit, e: return mod
# Silently propagate exit
raise e def is_package(self, fullname):
except Exception, e: (filename, src) = self.code[fullname]
# print module.__file__ return True
# print "StringLoading '%s' failed: %s [%s]" % (fqname,
# e, e.__class__) def get_code(self, fullname):
traceback.print_exc() (filename, src) = self.code[fullname]
raise exceptions.SystemExit(1) code = compile(src, "%s/%s" % (self.path, filename), 'exec')
return code
if parent != None:
parent.__dict__[partname] = module def get_source(self, fullname):
return module (filename, src) = self.code[fullname]
except (KeyError, AttributeError), e: return src
pass
# Fourth shot, default loader def get_filename(self, fullname):
return ihooks.ModuleImporter.import_it(self, partname, fqname, parent, force_load) (filename, src) = self.code[fullname]
return filename
def reload(self, module):
for (n, m) in self.loaded.iteritems():
if m is module:
(filename, code) = self.code_dict[n]
exec code in module.__dict__
return
return super(StringImporter, self).reload(module)
def extract(dest='.'): def extract(dest='.'):
\"\"\"Extracts archived files in dest directory ('.' is default)\"\"\" \"\"\"Extracts archived files in dest directory ('.' is default)\"\"\"
for (m, (n, f, c)) in code.iteritems(): import os
import os.path
for (m, (f, c)) in code.iteritems():
filepath = '%s/%s' % (dest, f) filepath = '%s/%s' % (dest, f)
dirpath = os.path.dirname(filepath) dirpath = os.path.dirname(filepath)
if os.path.exists(filepath): if os.path.exists(filepath):
...@@ -199,16 +202,26 @@ def extract(dest='.'): ...@@ -199,16 +202,26 @@ def extract(dest='.'):
os.chmod(filepath, 0755) os.chmod(filepath, 0755)
if __name__ == '__main__': if __name__ == '__main__':
importer = StringImporter(code) import sys
importer.install() importer = Importer(code)
# This will start actual execution sys.path_hooks.append(importer)
import exceptions
import imp
try: try:
import __apa__main__ # This will start actual execution
importer.load_module("__main__")
except exceptions.SystemExit, e: except exceptions.SystemExit, e:
raise e raise e
except: except:
if BAD:
import traceback
traceback.print_exception(*BAD)
pass
sys.exit(1) sys.exit(1)
""" """
if apa: if apa:
apa.close() apa.close()
os.chmod(options.output, 0755) try:
os.chmod(options.output, 0755)
except:
pass
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment