1"""Create an applet from a Python script. 2 3This puts up a dialog asking for a Python source file ('TEXT'). 4The output is a file with the same name but its ".py" suffix dropped. 5It is created by copying an applet template and then adding a 'PYC ' 6resource named __main__ containing the compiled, marshalled script. 7""" 8 9 10import sys 11sys.stdout = sys.stderr 12 13import os 14import MacOS 15try: 16 import EasyDialogs 17except ImportError: 18 EasyDialogs = None 19import buildtools 20import getopt 21 22if 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 34def 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 44def 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 125def 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 140class 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 155if __name__ == '__main__': 156 main() 157