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

Improve code loading

parent ff37baca
apa 100755 → 100644
......@@ -2,12 +2,12 @@
"""
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
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
modify it under the terms of the GNU General Public License
......@@ -39,17 +39,15 @@ def getModuleName(s):
return string.replace(m.group(1), "/", ".")
return None
def emitCode(f, module, name, filename, code):
print >> sys.stderr, "EMIT:", name
print >> f, '"%s" : ( "%s", "%s", """%s""")' % (quote(module),
quote(name),
quote(filename),
quote(code))
def emitCode(f, module, filename, code):
print >> sys.stderr, "EMIT:", module
print >> f, '"%s" : ( "%s", """%s""")' % (quote(module),
quote(filename),
quote(code))
def quote(s):
return string.replace(string.replace(s, '\\', '\\\\'), '"', '\\"')
if __name__ == '__main__':
usage = "%prog [options] <main module> <additional modules>*"
optParser = optparse.OptionParser(usage=usage)
......@@ -59,6 +57,10 @@ if __name__ == '__main__':
optParser.add_option('-o','--output',
action='store',
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:])
if options.documentation:
......@@ -68,10 +70,17 @@ if __name__ == '__main__':
# Read all python files
code = []
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:
f = open(filename)
code.append((name, filename, f.read()))
code.append((name, archivename, f.read()))
f.close()
else:
print "Illegal filename '%s'" % filename
......@@ -81,7 +90,7 @@ if __name__ == '__main__':
apa = file(options.output, 'w')
else:
apa = None
# Emit code
interpreter = code[0][2].splitlines()[0]
if interpreter.find("python") >= 0:
......@@ -98,7 +107,7 @@ if __name__ == '__main__':
for (n, f, c) in code[1:]:
print >> apa, " %-20s %s" % (n, f)
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:
......@@ -111,82 +120,76 @@ To extract as individual files:
"""
print >> apa, "code = {"
(n, f, c) = code[0]
emitCode(apa, '__apa__main__', '__main__', f, c)
emitCode(apa, '__main__', f, c)
for (n, f, c) in code[1:]:
print >> apa, ","
emitCode(apa, n, n, f, c)
emitCode(apa, n, f, c)
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
\"\"\"
def __init__(self, code_dict):
super(StringImporter, self).__init__()
self.code_dict = code_dict;
self.loaded = {}
self.result = None
def import_it(self, partname, fqname, parent, force_load=0):
try:
# First shot, return part from parent module
return parent.__dict__[partname]
except (KeyError, AttributeError):
pass
def __init__(self, code):
self.code = code;
self.path = "<%s>" % str(self.__class__)
if not self.path in sys.path:
sys.path.insert(0, self.path)
def __call__(self, path):
if path == self.path:
return self
return None
def find_module(self, fullname):
try:
# Second shot, load it from already loaded code
return self.loaded[fqname]
except (KeyError, AttributeError):
pass
self.code[fullname]
return self
except:
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:
# Third shot, load it from code_dictionary
(name, filename, code) = self.code_dict[fqname]
module = self.loader.hooks.add_module(fqname)
self.loaded[fqname] = module
module.__name__ = name
module.__file__ = filename
try:
comp = compile(code, filename, 'exec')
exec comp in module.__dict__
except exceptions.SystemExit, e:
# Silently propagate exit
raise e
except Exception, e:
# print module.__file__
# print "StringLoading '%s' failed: %s [%s]" % (fqname,
# e, e.__class__)
traceback.print_exc()
raise exceptions.SystemExit(1)
if parent != None:
parent.__dict__[partname] = module
return module
except (KeyError, AttributeError), e:
pass
code = compile(src, "%s/%s" % (self.path, filename), 'exec')
exec code in mod.__dict__
except exceptions.SystemExit, e:
# Silently propagate exit
raise e
except Exception, e:
# Silently propagate other exceptions as well
BAD = sys.exc_info()
raise e
return mod
def is_package(self, fullname):
(filename, src) = self.code[fullname]
return True
def get_code(self, fullname):
(filename, src) = self.code[fullname]
code = compile(src, "%s/%s" % (self.path, filename), 'exec')
return code
def get_source(self, fullname):
(filename, src) = self.code[fullname]
return src
# Fourth shot, default loader
return ihooks.ModuleImporter.import_it(self, partname, fqname, parent, force_load)
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 get_filename(self, fullname):
(filename, src) = self.code[fullname]
return filename
def extract(dest='.'):
\"\"\"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)
dirpath = os.path.dirname(filepath)
if os.path.exists(filepath):
......@@ -199,16 +202,26 @@ def extract(dest='.'):
os.chmod(filepath, 0755)
if __name__ == '__main__':
importer = StringImporter(code)
importer.install()
# This will start actual execution
import sys
importer = Importer(code)
sys.path_hooks.append(importer)
import exceptions
import imp
try:
import __apa__main__
# This will start actual execution
importer.load_module("__main__")
except exceptions.SystemExit, e:
raise e
except:
if BAD:
import traceback
traceback.print_exception(*BAD)
pass
sys.exit(1)
"""
if apa:
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