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