Commit ff37baca authored by Anders Blomdell's avatar Anders Blomdell
Browse files

Initial commit

parents
#!/usr/bin/python
"""
Anders Python Archiver
Copyright (C) 2004 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
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
"""
import optparse
import os
import re
import string
import sys
def getModuleName(s):
m = re.match("^(.*)/__init__\.py$", s)
if m:
return string.replace(m.group(1), "/", ".")
m = re.match("^(.*)\.py$", s)
if m:
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 quote(s):
return string.replace(string.replace(s, '\\', '\\\\'), '"', '\\"')
if __name__ == '__main__':
usage = "%prog [options] <main module> <additional modules>*"
optParser = optparse.OptionParser(usage=usage)
optParser.add_option('-d','--documentation',
action='store_true',
help='Show documentation')
optParser.add_option('-o','--output',
action='store',
help='Name of archive')
(options, args) = optParser.parse_args(sys.argv[1:])
if options.documentation:
print __doc__
sys.exit(0)
# Read all python files
code = []
for filename in args:
name = getModuleName(filename)
if name:
f = open(filename)
code.append((name, filename, f.read()))
f.close()
else:
print "Illegal filename '%s'" % filename
sys.exit(1)
if options.output:
apa = file(options.output, 'w')
else:
apa = None
# Emit code
interpreter = code[0][2].splitlines()[0]
if interpreter.find("python") >= 0:
# Take interpreter version from main file
print >> apa, interpreter
else:
# Default interpreter
print >> sys.stderr, "Interpreter defaulting to '#!/usr/bin/python'"
print >> apa, "#!/usr/bin/python"
print >> apa, "\"\"\""
print >> apa, "Executable archive of '%s'" % code[0][0]
print >> apa, "\nThe following modules are archived:"
print >> apa, " %-20s %s" % ('__main__', code[0][1])
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)
To extract as individual files:
* Add a .py suffix to the archive (if needed)
* Start a python interpreter
* Run the following commands:
import <archive name>
<archive name>.extract(<optional destination dir>)
\"\"\"
"""
print >> apa, "code = {"
(n, f, c) = code[0]
emitCode(apa, '__apa__main__', '__main__', f, c)
for (n, f, c) in code[1:]:
print >> apa, ","
emitCode(apa, n, 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):
\"\"\"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
try:
# Second shot, load it from already loaded code
return self.loaded[fqname]
except (KeyError, AttributeError):
pass
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
# 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 extract(dest='.'):
\"\"\"Extracts archived files in dest directory ('.' is default)\"\"\"
for (m, (n, f, c)) in code.iteritems():
filepath = '%s/%s' % (dest, f)
dirpath = os.path.dirname(filepath)
if os.path.exists(filepath):
raise Exception('File already exists: %s' % filepath)
if not os.path.exists(dirpath):
os.makedirs(dirpath)
f = file(filepath, 'w')
f.write(c)
f.close()
os.chmod(filepath, 0755)
if __name__ == '__main__':
importer = StringImporter(code)
importer.install()
# This will start actual execution
try:
import __apa__main__
except exceptions.SystemExit, e:
raise e
except:
sys.exit(1)
"""
if apa:
apa.close()
os.chmod(options.output, 0755)
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