summaryrefslogtreecommitdiffstats
path: root/Mac/scripts/BuildApplet.py
blob: eeeb82bfd7c14895702a53fd5ec5de5eeef602ab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
"""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
        # On OS9 always be verbose
        if sys.platform == 'mac' and not verbose:
            verbose = 'default'
        # 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()