blob: a76ed90872d9b7a1dcf269245e28bd5bd6f81b72 [file] [log] [blame]
"""Create an applet from a Python script.
This puts up a dialog asking for a Python source file ('TEXT').
The output is a file with the same name but its ".py" suffix dropped.
It is created by copying an applet template and then adding a 'PYC '
resource named __main__ containing the compiled, marshalled script.
"""
import sys
sys.stdout = sys.stderr
import os
import MacOS
try:
import EasyDialogs
except ImportError:
EasyDialogs = None
import buildtools
import getopt
if not sys.executable.startswith(sys.exec_prefix):
# Oh, the joys of using a python script to bootstrap applicatin bundles
# sys.executable points inside the current application bundle. Because this
# path contains blanks (two of them actually) this path isn't usable on
# #! lines. Reset sys.executable to point to the embedded python interpreter
sys.executable = os.path.join(sys.prefix,
'Resources/Python.app/Contents/MacOS/Python')
# Just in case we're not in a framework:
if not os.path.exists(sys.executable):
sys.executable = os.path.join(sys.exec_prefix, 'bin/python')
def main():
try:
buildapplet()
except buildtools.BuildError, detail:
if EasyDialogs is None:
print detail
else:
EasyDialogs.Message(detail)
def buildapplet():
buildtools.DEBUG=1
# Find the template
# (there's no point in proceeding if we can't find it)
template = buildtools.findtemplate()
# Ask for source text if not specified in sys.argv[1:]
if not sys.argv[1:]:
if EasyDialogs is None:
usage()
sys.exit(1)
filename = EasyDialogs.AskFileForOpen(message='Select Python source or applet:',
typeList=('TEXT', 'APPL'))
if not filename:
return
tp, tf = os.path.split(filename)
if tf[-3:] == '.py':
tf = tf[:-3]
else:
tf = tf + '.applet'
dstfilename = EasyDialogs.AskFileForSave(message='Save application as:',
savedFileName=tf)
if not dstfilename: return
cr, tp = MacOS.GetCreatorAndType(filename)
if tp == 'APPL':
buildtools.update(template, filename, dstfilename)
else:
buildtools.process(template, filename, dstfilename, 1)
else:
SHORTOPTS = "o:r:ne:v?PR"
LONGOPTS=("output=", "resource=", "noargv", "extra=", "verbose", "help", "python=", "destroot=")
try:
options, args = getopt.getopt(sys.argv[1:], SHORTOPTS, LONGOPTS)
except getopt.error:
usage()
if options and len(args) > 1:
sys.stderr.write("Cannot use options when specifying multiple input files")
sys.exit(1)
dstfilename = None
rsrcfilename = None
raw = 0
extras = []
verbose = None
destroot = ''
for opt, arg in options:
if opt in ('-o', '--output'):
dstfilename = arg
elif opt in ('-r', '--resource'):
rsrcfilename = arg
elif opt in ('-n', '--noargv'):
raw = 1
elif opt in ('-e', '--extra'):
if ':' in arg:
arg = arg.split(':')
extras.append(arg)
elif opt in ('-P', '--python'):
# This is a very dirty trick. We set sys.executable
# so that bundlebuilder will use this in the #! line
# for the applet bootstrap.
sys.executable = arg
elif opt in ('-v', '--verbose'):
verbose = Verbose()
elif opt in ('-?', '--help'):
usage()
elif opt in ('-d', '--destroot'):
destroot = arg
# Loop over all files to be processed
for filename in args:
cr, tp = MacOS.GetCreatorAndType(filename)
if tp == 'APPL':
buildtools.update(template, filename, dstfilename)
else:
buildtools.process(template, filename, dstfilename, 1,
rsrcname=rsrcfilename, others=extras, raw=raw,
progress=verbose, destroot=destroot)
def usage():
print "BuildApplet creates an application from a Python source file"
print "Usage:"
print " BuildApplet interactive, single file, no options"
print " BuildApplet src1.py src2.py ... non-interactive multiple file"
print " BuildApplet [options] src.py non-interactive single file"
print "Options:"
print " --output o Output file; default based on source filename, short -o"
print " --resource r Resource file; default based on source filename, short -r"
print " --noargv Build applet without drag-and-drop sys.argv emulation, short -n, OSX only"
print " --extra src[:dst] Extra file to put in .app bundle, short -e, OSX only"
print " --verbose Verbose, short -v"
print " --help This message, short -?"
sys.exit(1)
class Verbose:
"""This class mimics EasyDialogs.ProgressBar but prints to stderr"""
def __init__(self, *args):
if args and args[0]:
self.label(args[0])
def set(self, *args):
pass
def inc(self, *args):
pass
def label(self, str):
sys.stderr.write(str+'\n')
if __name__ == '__main__':
main()