Home | History | Annotate | Download | only in scripts
      1 """Create an applet from a Python script.
      2 
      3 This puts up a dialog asking for a Python source file ('TEXT').
      4 The output is a file with the same name but its ".py" suffix dropped.
      5 It is created by copying an applet template and then adding a 'PYC '
      6 resource named __main__ containing the compiled, marshalled script.
      7 """
      8 
      9 
     10 import sys
     11 sys.stdout = sys.stderr
     12 
     13 import os
     14 import MacOS
     15 try:
     16     import EasyDialogs
     17 except ImportError:
     18     EasyDialogs = None
     19 import buildtools
     20 import getopt
     21 
     22 if not sys.executable.startswith(sys.exec_prefix):
     23     # Oh, the joys of using a python script to bootstrap applicatin bundles
     24     # sys.executable points inside the current application bundle. Because this
     25     # path contains blanks (two of them actually) this path isn't usable on
     26     # #! lines. Reset sys.executable to point to the embedded python interpreter
     27     sys.executable = os.path.join(sys.prefix,
     28             'Resources/Python.app/Contents/MacOS/Python')
     29 
     30     # Just in case we're not in a framework:
     31     if not os.path.exists(sys.executable):
     32         sys.executable = os.path.join(sys.exec_prefix,  'bin/python')
     33 
     34 def main():
     35     try:
     36         buildapplet()
     37     except buildtools.BuildError, detail:
     38         if EasyDialogs is None:
     39             print detail
     40         else:
     41             EasyDialogs.Message(detail)
     42 
     43 
     44 def buildapplet():
     45     buildtools.DEBUG=1
     46 
     47     # Find the template
     48     # (there's no point in proceeding if we can't find it)
     49 
     50     template = buildtools.findtemplate()
     51 
     52     # Ask for source text if not specified in sys.argv[1:]
     53 
     54     if not sys.argv[1:]:
     55         if EasyDialogs is None:
     56             usage()
     57             sys.exit(1)
     58 
     59         filename = EasyDialogs.AskFileForOpen(message='Select Python source or applet:',
     60                 typeList=('TEXT', 'APPL'))
     61         if not filename:
     62             return
     63         tp, tf = os.path.split(filename)
     64         if tf[-3:] == '.py':
     65             tf = tf[:-3]
     66         else:
     67             tf = tf + '.applet'
     68         dstfilename = EasyDialogs.AskFileForSave(message='Save application as:',
     69                 savedFileName=tf)
     70         if not dstfilename: return
     71         cr, tp = MacOS.GetCreatorAndType(filename)
     72         if tp == 'APPL':
     73             buildtools.update(template, filename, dstfilename)
     74         else:
     75             buildtools.process(template, filename, dstfilename, 1)
     76     else:
     77 
     78         SHORTOPTS = "o:r:ne:v?PR"
     79         LONGOPTS=("output=", "resource=", "noargv", "extra=", "verbose", "help", "python=", "destroot=")
     80         try:
     81             options, args = getopt.getopt(sys.argv[1:], SHORTOPTS, LONGOPTS)
     82         except getopt.error:
     83             usage()
     84         if options and len(args) > 1:
     85             sys.stderr.write("Cannot use options when specifying multiple input files")
     86             sys.exit(1)
     87         dstfilename = None
     88         rsrcfilename = None
     89         raw = 0
     90         extras = []
     91         verbose = None
     92         destroot = ''
     93         for opt, arg in options:
     94             if opt in ('-o', '--output'):
     95                 dstfilename = arg
     96             elif opt in ('-r', '--resource'):
     97                 rsrcfilename = arg
     98             elif opt in ('-n', '--noargv'):
     99                 raw = 1
    100             elif opt in ('-e', '--extra'):
    101                 if ':' in arg:
    102                     arg = arg.split(':')
    103                 extras.append(arg)
    104             elif opt in ('-P', '--python'):
    105                 # This is a very dirty trick. We set sys.executable
    106                 # so that bundlebuilder will use this in the #! line
    107                 # for the applet bootstrap.
    108                 sys.executable = arg
    109             elif opt in ('-v', '--verbose'):
    110                 verbose = Verbose()
    111             elif opt in ('-?', '--help'):
    112                 usage()
    113             elif opt in ('-d', '--destroot'):
    114                 destroot = arg
    115         # Loop over all files to be processed
    116         for filename in args:
    117             cr, tp = MacOS.GetCreatorAndType(filename)
    118             if tp == 'APPL':
    119                 buildtools.update(template, filename, dstfilename)
    120             else:
    121                 buildtools.process(template, filename, dstfilename, 1,
    122                         rsrcname=rsrcfilename, others=extras, raw=raw,
    123                         progress=verbose, destroot=destroot)
    124 
    125 def usage():
    126     print "BuildApplet creates an application from a Python source file"
    127     print "Usage:"
    128     print "  BuildApplet     interactive, single file, no options"
    129     print "  BuildApplet src1.py src2.py ...   non-interactive multiple file"
    130     print "  BuildApplet [options] src.py    non-interactive single file"
    131     print "Options:"
    132     print "  --output o        Output file; default based on source filename, short -o"
    133     print "  --resource r      Resource file; default based on source filename, short -r"
    134     print "  --noargv          Build applet without drag-and-drop sys.argv emulation, short -n, OSX only"
    135     print "  --extra src[:dst] Extra file to put in .app bundle, short -e, OSX only"
    136     print "  --verbose         Verbose, short -v"
    137     print "  --help            This message, short -?"
    138     sys.exit(1)
    139 
    140 class Verbose:
    141     """This class mimics EasyDialogs.ProgressBar but prints to stderr"""
    142     def __init__(self, *args):
    143         if args and args[0]:
    144             self.label(args[0])
    145 
    146     def set(self, *args):
    147         pass
    148 
    149     def inc(self, *args):
    150         pass
    151 
    152     def label(self, str):
    153         sys.stderr.write(str+'\n')
    154 
    155 if __name__ == '__main__':
    156     main()
    157