blob: e0b58e7cb6ee0e08d0ea0c1256bc6843b430578f [file] [log] [blame]
Jack Jansen7571f301995-07-29 13:48:41 +00001"""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
Jack Jansen0f452fa1995-09-01 11:54:11 +00009DEBUG=0
10
Jack Jansen7571f301995-07-29 13:48:41 +000011import sys
12sys.stdout = sys.stderr
13
14import string
15import os
16import marshal
17import imp
18import macfs
Jack Jansen7c86b211995-08-31 13:48:43 +000019import MACFS
Jack Jansen7571f301995-07-29 13:48:41 +000020import MacOS
21from Res import *
22
23# .pyc file (and 'PYC ' resource magic number)
24MAGIC = imp.get_magic()
25
26# Template file (searched on sys.path)
27TEMPLATE = "PythonApplet"
28
29# Specification of our resource
30RESTYPE = 'PYC '
31RESNAME = '__main__'
32
33# A resource with this name sets the "owner" (creator) of the destination
Jack Jansen3f14f4a1995-09-24 21:05:24 +000034# XXXX Should look for id=0
Jack Jansen7571f301995-07-29 13:48:41 +000035OWNERNAME = "owner resource"
36
37# OpenResFile mode parameters
38READ = 1
39WRITE = 2
40
Jack Jansen0f452fa1995-09-01 11:54:11 +000041def findtemplate():
42 """Locate the applet template along sys.path"""
Jack Jansen7571f301995-07-29 13:48:41 +000043 for p in sys.path:
44 template = os.path.join(p, TEMPLATE)
45 try:
Jack Jansen7c86b211995-08-31 13:48:43 +000046 template, d1, d2 = macfs.ResolveAliasFile(template)
Jack Jansen7571f301995-07-29 13:48:41 +000047 break
Jack Jansen7c86b211995-08-31 13:48:43 +000048 except (macfs.error, ValueError):
Jack Jansen7571f301995-07-29 13:48:41 +000049 continue
50 else:
Jack Jansen7c86b211995-08-31 13:48:43 +000051 die("Template %s not found on sys.path" % `TEMPLATE`)
Jack Jansen7571f301995-07-29 13:48:41 +000052 return
Jack Jansen7c86b211995-08-31 13:48:43 +000053 template = template.as_pathname()
Jack Jansen0f452fa1995-09-01 11:54:11 +000054 return template
55
56def main():
Jack Jansen0f452fa1995-09-01 11:54:11 +000057
58 # Find the template
59 # (there's no point in proceeding if we can't find it)
60
61 template = findtemplate()
Jack Jansen3f14f4a1995-09-24 21:05:24 +000062 if DEBUG:
63 print 'Using template', template
Jack Jansen7c86b211995-08-31 13:48:43 +000064
Jack Jansen7571f301995-07-29 13:48:41 +000065 # Ask for source text if not specified in sys.argv[1:]
66
67 if not sys.argv[1:]:
Jack Jansen9062fa21995-08-14 12:21:12 +000068 srcfss, ok = macfs.PromptGetFile('Select Python source file:', 'TEXT')
Jack Jansen7571f301995-07-29 13:48:41 +000069 if not ok:
70 return
71 filename = srcfss.as_pathname()
72 tp, tf = os.path.split(filename)
73 if tf[-3:] == '.py':
74 tf = tf[:-3]
75 else:
76 tf = tf + '.applet'
77 dstfss, ok = macfs.StandardPutFile('Save application as:', tf)
78 if not ok: return
79 process(template, filename, dstfss.as_pathname())
80 else:
81
82 # Loop over all files to be processed
83 for filename in sys.argv[1:]:
84 process(template, filename, '')
85
Jack Jansen7571f301995-07-29 13:48:41 +000086def process(template, filename, output):
87
Jack Jansen0f452fa1995-09-01 11:54:11 +000088 if DEBUG:
89 print "Processing", `filename`, "..."
Jack Jansen7571f301995-07-29 13:48:41 +000090
91 # Read the source and compile it
92 # (there's no point overwriting the destination if it has a syntax error)
93
94 fp = open(filename)
95 text = fp.read()
96 fp.close()
97 try:
98 code = compile(text, filename, "exec")
99 except (SyntaxError, EOFError):
100 die("Syntax error in script %s" % `filename`)
101 return
102
103 # Set the destination file name
104
105 if string.lower(filename[-3:]) == ".py":
106 destname = filename[:-3]
107 rsrcname = destname + '.rsrc'
108 else:
109 destname = filename + ".applet"
110 rsrcname = filename + '.rsrc'
111
112 if output:
113 destname = output
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000114
115 # Try removing the output file
116 try:
117 os.unlink(output)
118 except os.error:
119 pass
120
121
122 # Create FSSpecs for the various files
123
Jack Jansen7c86b211995-08-31 13:48:43 +0000124 template_fss = macfs.FSSpec(template)
125 template_fss, d1, d2 = macfs.ResolveAliasFile(template_fss)
126 dest_fss = macfs.FSSpec(destname)
127
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000128 # Copy data (not resources, yet) from the template
129
Jack Jansen7571f301995-07-29 13:48:41 +0000130 tmpl = open(template, "rb")
131 dest = open(destname, "wb")
132 data = tmpl.read()
133 if data:
134 dest.write(data)
135 dest.close()
136 tmpl.close()
137
Jack Jansen7571f301995-07-29 13:48:41 +0000138 # Open the output resource fork
139
140 try:
Jack Jansen7c86b211995-08-31 13:48:43 +0000141 output = FSpOpenResFile(dest_fss, WRITE)
Jack Jansen7571f301995-07-29 13:48:41 +0000142 except MacOS.Error:
Jack Jansen0f452fa1995-09-01 11:54:11 +0000143 if DEBUG:
144 print "Creating resource fork..."
Jack Jansen7571f301995-07-29 13:48:41 +0000145 CreateResFile(destname)
Jack Jansen7c86b211995-08-31 13:48:43 +0000146 output = FSpOpenResFile(dest_fss, WRITE)
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000147
148 # Copy the resources from the target specific resource template, if any
149 typesfound, ownertype = [], None
150 try:
151 input = FSpOpenResFile(rsrcname, READ)
152 except (MacOS.Error, ValueError):
153 pass
154 else:
155 typesfound, ownertype = copyres(input, output, [], 0)
156 CloseResFile(input)
157
158 # Check which resource-types we should not copy from the template
159 skiptypes = []
160 if 'SIZE' in typesfound: skiptypes.append('SIZE')
161 if 'BNDL' in typesfound: skiptypes = skiptypes + ['BNDL', 'FREF', 'icl4',
162 'icl8', 'ics4', 'ics8', 'ICN#', 'ics#']
163 skipowner = (ownertype <> None)
Jack Jansen7571f301995-07-29 13:48:41 +0000164
165 # Copy the resources from the template
166
Jack Jansen7c86b211995-08-31 13:48:43 +0000167 input = FSpOpenResFile(template_fss, READ)
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000168 dummy, tmplowner = copyres(input, output, skiptypes, skipowner)
169 if ownertype == None:
170 ownertype = tmplowner
Jack Jansen7571f301995-07-29 13:48:41 +0000171 CloseResFile(input)
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000172 if ownertype == None:
173 die("No owner resource found in either resource file or template")
Jack Jansen7571f301995-07-29 13:48:41 +0000174
Jack Jansen7c86b211995-08-31 13:48:43 +0000175 # Now set the creator, type and bundle bit of the destination
176 dest_finfo = dest_fss.GetFInfo()
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000177 dest_finfo.Creator = ownertype
178 dest_finfo.Type = 'APPL'
Jack Jansen7c86b211995-08-31 13:48:43 +0000179 dest_finfo.Flags = dest_finfo.Flags | MACFS.kHasBundle
180 dest_finfo.Flags = dest_finfo.Flags & ~MACFS.kHasBeenInited
181 dest_fss.SetFInfo(dest_finfo)
Jack Jansen7571f301995-07-29 13:48:41 +0000182
183 # Make sure we're manipulating the output resource file now
184
185 UseResFile(output)
186
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000187 # Delete any existing 'PYC ' resource named __main__
Jack Jansen7571f301995-07-29 13:48:41 +0000188
189 try:
190 res = Get1NamedResource(RESTYPE, RESNAME)
191 res.RemoveResource()
192 except Error:
193 pass
194
195 # Create the raw data for the resource from the code object
196
197 data = marshal.dumps(code)
198 del code
199 data = (MAGIC + '\0\0\0\0') + data
200
201 # Create the resource and write it
202
203 id = 0
204 while id < 128:
205 id = Unique1ID(RESTYPE)
206 res = Resource(data)
207 res.AddResource(RESTYPE, id, RESNAME)
208 res.WriteResource()
209 res.ReleaseResource()
210
211 # Close the output file
212
213 CloseResFile(output)
214
Jack Jansen055782a1996-08-28 14:16:39 +0000215 if DEBUG:
216 print "Applet created:", destname
Jack Jansen7571f301995-07-29 13:48:41 +0000217
218
219# Copy resources between two resource file descriptors.
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000220# skip a resource named '__main__' or (if skipowner is set) 'Owner resource'.
221# Also skip resources with a type listed in skiptypes.
222#
223def copyres(input, output, skiptypes, skipowner):
Jack Jansen7571f301995-07-29 13:48:41 +0000224 ctor = None
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000225 alltypes = []
Jack Jansen7571f301995-07-29 13:48:41 +0000226 UseResFile(input)
227 ntypes = Count1Types()
228 for itype in range(1, 1+ntypes):
229 type = Get1IndType(itype)
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000230 if type in skiptypes:
231 continue
232 alltypes.append(type)
Jack Jansen7571f301995-07-29 13:48:41 +0000233 nresources = Count1Resources(type)
234 for ires in range(1, 1+nresources):
235 res = Get1IndResource(type, ires)
236 id, type, name = res.GetResInfo()
237 lcname = string.lower(name)
238 if (type, lcname) == (RESTYPE, RESNAME):
239 continue # Don't copy __main__ from template
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000240 # XXXX should look for id=0
241 if lcname == OWNERNAME:
242 if skipowner:
243 continue # Skip this one
244 else:
245 ctor = type
Jack Jansen7571f301995-07-29 13:48:41 +0000246 size = res.size
247 attrs = res.GetResAttrs()
Jack Jansen0f452fa1995-09-01 11:54:11 +0000248 if DEBUG:
249 print id, type, name, size, hex(attrs)
Jack Jansen7571f301995-07-29 13:48:41 +0000250 res.LoadResource()
251 res.DetachResource()
252 UseResFile(output)
253 try:
254 res2 = Get1Resource(type, id)
255 except MacOS.Error:
256 res2 = None
257 if res2:
Jack Jansen0f452fa1995-09-01 11:54:11 +0000258 if DEBUG:
259 print "Overwriting..."
Jack Jansen7571f301995-07-29 13:48:41 +0000260 res2.RemoveResource()
261 res.AddResource(type, id, name)
262 res.WriteResource()
263 attrs = attrs | res.GetResAttrs()
Jack Jansen0f452fa1995-09-01 11:54:11 +0000264 if DEBUG:
265 print "New attrs =", hex(attrs)
Jack Jansen7571f301995-07-29 13:48:41 +0000266 res.SetResAttrs(attrs)
267 UseResFile(input)
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000268 return alltypes, ctor
Jack Jansen7571f301995-07-29 13:48:41 +0000269
270
271# Show a message and exit
272
273def die(str):
274 message(str)
275 sys.exit(1)
276
277
278# Show a message
279
280def message(str, id = 256):
281 from Dlg import *
282 d = GetNewDialog(id, -1)
283 if not d:
284 print "Error:", `str`
285 print "DLOG id =", id, "not found."
286 return
287 tp, h, rect = d.GetDialogItem(2)
288 SetDialogItemText(h, str)
Jack Jansen6c6ad831996-01-22 14:55:52 +0000289 d.SetDialogDefaultItem(1)
Jack Jansen7571f301995-07-29 13:48:41 +0000290 while 1:
291 n = ModalDialog(None)
292 if n == 1: break
293 del d
294
295
296if __name__ == '__main__':
297 main()