|
1 | | -"""Add a 'PYC ' resource named "__main__" to a resource file. |
| 1 | +"""Create an applet from a Python script. |
2 | 2 |
|
3 | | -This first puts up a dialog asking for a Python source file ('TEXT'), |
4 | | -then one asking for an existing destination file ('APPL' or 'rsrc'). |
5 | | -
|
6 | | -It compiles the Python source into a code object, marshals it into a string, |
7 | | -prefixes the string with a .pyc header, and turns it into a resource, |
8 | | -which is then written to the destination. |
9 | | -
|
10 | | -If the destination already contains a resource with the same name and type, |
11 | | -it is overwritten. |
| 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. |
12 | 7 | """ |
13 | 8 |
|
| 9 | +import sys |
| 10 | +import string |
| 11 | +import os |
14 | 12 | import marshal |
15 | 13 | import imp |
16 | 14 | import macfs |
| 15 | +import MacOS |
17 | 16 | from Res import * |
18 | 17 |
|
19 | 18 | # .pyc file (and 'PYC ' resource magic number) |
20 | 19 | MAGIC = imp.get_magic() |
21 | 20 |
|
22 | | -# Complete specification of our resource |
| 21 | +# Template file (searched on sys.path) |
| 22 | +TEMPLATE = "PythonApplet" |
| 23 | + |
| 24 | +# Specification of our resource |
23 | 25 | RESTYPE = 'PYC ' |
24 | | -RESID = 128 |
25 | 26 | RESNAME = '__main__' |
26 | 27 |
|
27 | 28 | # OpenResFile mode parameters |
|
30 | 31 |
|
31 | 32 | def main(): |
32 | 33 |
|
| 34 | + # Find the template |
| 35 | + # (there's no point in proceeding if we can't find it) |
| 36 | + |
| 37 | + for p in sys.path: |
| 38 | + template = os.path.join(p, TEMPLATE) |
| 39 | + try: |
| 40 | + tmpl = open(template, "rb") |
| 41 | + break |
| 42 | + except IOError: |
| 43 | + continue |
| 44 | + else: |
| 45 | + # XXX Ought to put up a dialog |
| 46 | + print "Template not found. Exit." |
| 47 | + return |
| 48 | + |
33 | 49 | # Ask for source text |
34 | 50 |
|
35 | 51 | srcfss, ok = macfs.StandardGetFile('TEXT') |
36 | | - if not ok: return |
| 52 | + if not ok: |
| 53 | + tmpl.close() |
| 54 | + return |
| 55 | + filename = srcfss.as_pathname() |
37 | 56 |
|
38 | 57 | # Read the source and compile it |
39 | | - # (there's no point asking for a destination if it has a syntax error) |
| 58 | + # (there's no point overwriting the destination if it has a syntax error) |
40 | 59 |
|
41 | | - filename = srcfss.as_pathname() |
42 | 60 | fp = open(filename) |
43 | 61 | text = fp.read() |
44 | 62 | fp.close() |
45 | | - code = compile(text, filename, "exec") |
| 63 | + try: |
| 64 | + code = compile(text, filename, "exec") |
| 65 | + except (SyntaxError, EOFError): |
| 66 | + print "Syntax error in script" |
| 67 | + tmpl.close() |
| 68 | + return |
46 | 69 |
|
47 | | - # Ask for destination file |
| 70 | + # Set the destination file name |
48 | 71 |
|
49 | | - dstfss, ok = macfs.StandardGetFile('APPL', 'rsrc') |
50 | | - if not ok: return |
| 72 | + if string.lower(filename[-3:]) == ".py": |
| 73 | + destname = filename[:-3] |
| 74 | + else: |
| 75 | + destname = filename + ".applet" |
51 | 76 |
|
52 | | - # Create the raw data for the resource from the code object |
| 77 | + # Copy the data from the template (creating the file as well) |
53 | 78 |
|
54 | | - data = marshal.dumps(code) |
55 | | - del code |
56 | | - data = (MAGIC + '\0\0\0\0') + data |
| 79 | + dest = open(destname, "wb") |
| 80 | + data = tmpl.read() |
| 81 | + if data: |
| 82 | + dest.write(data) |
| 83 | + dest.close() |
| 84 | + tmpl.close() |
57 | 85 |
|
58 | | - # Open the resource file |
| 86 | + # Copy the creator and type of the template to the destination |
59 | 87 |
|
60 | | - fnum = FSpOpenResFile(dstfss.as_pathname(), WRITE) |
| 88 | + ctor, type = MacOS.GetCreatorAndType(template) |
| 89 | + MacOS.SetCreatorAndType(destname, ctor, type) |
61 | 90 |
|
62 | | - # Delete any existing resource with name __main__ or number 128 |
| 91 | + # Open the input and output resource forks |
63 | 92 |
|
| 93 | + input = FSpOpenResFile(template, READ) |
64 | 94 | try: |
65 | | - res = Get1NamedResource(RESTYPE, RESNAME) |
66 | | - res.RmveResource() |
67 | | - except Error: |
68 | | - pass |
| 95 | + output = FSpOpenResFile(destname, WRITE) |
| 96 | + except MacOS.Error: |
| 97 | + print "Creating resource fork..." |
| 98 | + CreateResFile(destname) |
| 99 | + output = FSpOpenResFile(destname, WRITE) |
| 100 | + |
| 101 | + # Copy the resources from the template, |
| 102 | + # except a 'PYC ' resource named __main__ |
| 103 | + |
| 104 | + UseResFile(input) |
| 105 | + ntypes = Count1Types() |
| 106 | + for itype in range(1, 1+ntypes): |
| 107 | + type = Get1IndType(itype) |
| 108 | + nresources = Count1Resources(type) |
| 109 | + for ires in range(1, 1+nresources): |
| 110 | + res = Get1IndResource(type, ires) |
| 111 | + id, type, name = res.GetResInfo() |
| 112 | + if (type, name) == (RESTYPE, RESNAME): |
| 113 | + continue # Don't copy __main__ from template |
| 114 | + size = res.SizeResource() |
| 115 | + attrs = res.GetResAttrs() |
| 116 | + print id, type, name, size, hex(attrs) |
| 117 | + res.LoadResource() |
| 118 | + res.DetachResource() |
| 119 | + UseResFile(output) |
| 120 | + try: |
| 121 | + res2 = Get1Resource(type, id) |
| 122 | + except MacOS.Error: |
| 123 | + res2 = None |
| 124 | + if res2: |
| 125 | + print "Overwriting..." |
| 126 | + res2.RmveResource() |
| 127 | + res.AddResource(type, id, name) |
| 128 | + #res.SetResAttrs(attrs) |
| 129 | + res.WriteResource() |
| 130 | + UseResFile(input) |
| 131 | + CloseResFile(input) |
| 132 | + |
| 133 | + # Make sure we're manipulating the output resource file now |
| 134 | + |
| 135 | + UseResFile(output) |
| 136 | + |
| 137 | + # Delete any existing 'PYC 'resource named __main__ |
69 | 138 |
|
70 | 139 | try: |
71 | | - res = Get1Resource(RESTYPE, RESID) |
| 140 | + res = Get1NamedResource(RESTYPE, RESNAME) |
72 | 141 | res.RmveResource() |
73 | 142 | except Error: |
74 | 143 | pass |
75 | 144 |
|
| 145 | + # Create the raw data for the resource from the code object |
| 146 | + |
| 147 | + data = marshal.dumps(code) |
| 148 | + del code |
| 149 | + data = (MAGIC + '\0\0\0\0') + data |
| 150 | + |
76 | 151 | # Create the resource and write it |
77 | 152 |
|
| 153 | + id = 0 |
| 154 | + while id < 128: |
| 155 | + id = Unique1ID(RESTYPE) |
78 | 156 | res = Resource(data) |
79 | | - res.AddResource(RESTYPE, RESID, RESNAME) |
80 | | - # XXX Are the following two calls needed? |
| 157 | + res.AddResource(RESTYPE, id, RESNAME) |
81 | 158 | res.WriteResource() |
82 | 159 | res.ReleaseResource() |
83 | 160 |
|
84 | 161 | # Close the resource file |
85 | 162 |
|
86 | | - CloseResFile(fnum) |
| 163 | + CloseResFile(output) |
87 | 164 |
|
88 | 165 | if __name__ == '__main__': |
89 | 166 | main() |
0 commit comments