• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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