blob: a7e35f37e6b06e445ad01c58728b57dc4a088141 [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 *
Jack Jansen29a33551996-09-15 22:13:59 +000022import macostools
Jack Jansen7571f301995-07-29 13:48:41 +000023
24# .pyc file (and 'PYC ' resource magic number)
25MAGIC = imp.get_magic()
26
27# Template file (searched on sys.path)
28TEMPLATE = "PythonApplet"
29
30# Specification of our resource
31RESTYPE = 'PYC '
32RESNAME = '__main__'
33
34# A resource with this name sets the "owner" (creator) of the destination
Jack Jansen3f14f4a1995-09-24 21:05:24 +000035# XXXX Should look for id=0
Jack Jansen7571f301995-07-29 13:48:41 +000036OWNERNAME = "owner resource"
37
38# OpenResFile mode parameters
39READ = 1
40WRITE = 2
41
Jack Jansen0f452fa1995-09-01 11:54:11 +000042def findtemplate():
43 """Locate the applet template along sys.path"""
Jack Jansen7571f301995-07-29 13:48:41 +000044 for p in sys.path:
45 template = os.path.join(p, TEMPLATE)
46 try:
Jack Jansen7c86b211995-08-31 13:48:43 +000047 template, d1, d2 = macfs.ResolveAliasFile(template)
Jack Jansen7571f301995-07-29 13:48:41 +000048 break
Jack Jansen7c86b211995-08-31 13:48:43 +000049 except (macfs.error, ValueError):
Jack Jansen7571f301995-07-29 13:48:41 +000050 continue
51 else:
Jack Jansen7c86b211995-08-31 13:48:43 +000052 die("Template %s not found on sys.path" % `TEMPLATE`)
Jack Jansen7571f301995-07-29 13:48:41 +000053 return
Jack Jansen7c86b211995-08-31 13:48:43 +000054 template = template.as_pathname()
Jack Jansen0f452fa1995-09-01 11:54:11 +000055 return template
56
57def main():
Jack Jansen0f452fa1995-09-01 11:54:11 +000058
59 # Find the template
60 # (there's no point in proceeding if we can't find it)
61
62 template = findtemplate()
Jack Jansen3f14f4a1995-09-24 21:05:24 +000063 if DEBUG:
64 print 'Using template', template
Jack Jansen7c86b211995-08-31 13:48:43 +000065
Jack Jansen7571f301995-07-29 13:48:41 +000066 # Ask for source text if not specified in sys.argv[1:]
67
68 if not sys.argv[1:]:
Jack Jansen9062fa21995-08-14 12:21:12 +000069 srcfss, ok = macfs.PromptGetFile('Select Python source file:', 'TEXT')
Jack Jansen7571f301995-07-29 13:48:41 +000070 if not ok:
71 return
72 filename = srcfss.as_pathname()
73 tp, tf = os.path.split(filename)
74 if tf[-3:] == '.py':
75 tf = tf[:-3]
76 else:
77 tf = tf + '.applet'
78 dstfss, ok = macfs.StandardPutFile('Save application as:', tf)
79 if not ok: return
80 process(template, filename, dstfss.as_pathname())
81 else:
82
83 # Loop over all files to be processed
84 for filename in sys.argv[1:]:
85 process(template, filename, '')
86
Jack Jansen7571f301995-07-29 13:48:41 +000087def process(template, filename, output):
88
Jack Jansen0f452fa1995-09-01 11:54:11 +000089 if DEBUG:
90 print "Processing", `filename`, "..."
Jack Jansen7571f301995-07-29 13:48:41 +000091
92 # Read the source and compile it
93 # (there's no point overwriting the destination if it has a syntax error)
94
95 fp = open(filename)
96 text = fp.read()
97 fp.close()
98 try:
99 code = compile(text, filename, "exec")
100 except (SyntaxError, EOFError):
101 die("Syntax error in script %s" % `filename`)
102 return
103
104 # Set the destination file name
105
106 if string.lower(filename[-3:]) == ".py":
107 destname = filename[:-3]
108 rsrcname = destname + '.rsrc'
109 else:
110 destname = filename + ".applet"
111 rsrcname = filename + '.rsrc'
112
113 if output:
114 destname = output
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000115
116 # Try removing the output file
117 try:
118 os.unlink(output)
119 except os.error:
120 pass
121
122
123 # Create FSSpecs for the various files
124
Jack Jansen7c86b211995-08-31 13:48:43 +0000125 template_fss = macfs.FSSpec(template)
126 template_fss, d1, d2 = macfs.ResolveAliasFile(template_fss)
127 dest_fss = macfs.FSSpec(destname)
128
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000129 # Copy data (not resources, yet) from the template
130
Jack Jansen7571f301995-07-29 13:48:41 +0000131 tmpl = open(template, "rb")
132 dest = open(destname, "wb")
133 data = tmpl.read()
134 if data:
135 dest.write(data)
136 dest.close()
137 tmpl.close()
138
Jack Jansen7571f301995-07-29 13:48:41 +0000139 # Open the output resource fork
140
141 try:
Jack Jansen7c86b211995-08-31 13:48:43 +0000142 output = FSpOpenResFile(dest_fss, WRITE)
Jack Jansen7571f301995-07-29 13:48:41 +0000143 except MacOS.Error:
Jack Jansen0f452fa1995-09-01 11:54:11 +0000144 if DEBUG:
145 print "Creating resource fork..."
Jack Jansen7571f301995-07-29 13:48:41 +0000146 CreateResFile(destname)
Jack Jansen7c86b211995-08-31 13:48:43 +0000147 output = FSpOpenResFile(dest_fss, WRITE)
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000148
149 # Copy the resources from the target specific resource template, if any
150 typesfound, ownertype = [], None
151 try:
152 input = FSpOpenResFile(rsrcname, READ)
153 except (MacOS.Error, ValueError):
154 pass
155 else:
156 typesfound, ownertype = copyres(input, output, [], 0)
157 CloseResFile(input)
158
159 # Check which resource-types we should not copy from the template
160 skiptypes = []
161 if 'SIZE' in typesfound: skiptypes.append('SIZE')
162 if 'BNDL' in typesfound: skiptypes = skiptypes + ['BNDL', 'FREF', 'icl4',
163 'icl8', 'ics4', 'ics8', 'ICN#', 'ics#']
164 skipowner = (ownertype <> None)
Jack Jansen7571f301995-07-29 13:48:41 +0000165
166 # Copy the resources from the template
167
Jack Jansen7c86b211995-08-31 13:48:43 +0000168 input = FSpOpenResFile(template_fss, READ)
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000169 dummy, tmplowner = copyres(input, output, skiptypes, skipowner)
170 if ownertype == None:
171 ownertype = tmplowner
Jack Jansen7571f301995-07-29 13:48:41 +0000172 CloseResFile(input)
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000173 if ownertype == None:
174 die("No owner resource found in either resource file or template")
Jack Jansen7571f301995-07-29 13:48:41 +0000175
Jack Jansen7c86b211995-08-31 13:48:43 +0000176 # Now set the creator, type and bundle bit of the destination
177 dest_finfo = dest_fss.GetFInfo()
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000178 dest_finfo.Creator = ownertype
179 dest_finfo.Type = 'APPL'
Jack Jansen7c86b211995-08-31 13:48:43 +0000180 dest_finfo.Flags = dest_finfo.Flags | MACFS.kHasBundle
181 dest_finfo.Flags = dest_finfo.Flags & ~MACFS.kHasBeenInited
182 dest_fss.SetFInfo(dest_finfo)
Jack Jansen7571f301995-07-29 13:48:41 +0000183
184 # Make sure we're manipulating the output resource file now
185
186 UseResFile(output)
187
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000188 # Delete any existing 'PYC ' resource named __main__
Jack Jansen7571f301995-07-29 13:48:41 +0000189
190 try:
191 res = Get1NamedResource(RESTYPE, RESNAME)
192 res.RemoveResource()
193 except Error:
194 pass
195
196 # Create the raw data for the resource from the code object
197
198 data = marshal.dumps(code)
199 del code
200 data = (MAGIC + '\0\0\0\0') + data
201
202 # Create the resource and write it
203
204 id = 0
205 while id < 128:
206 id = Unique1ID(RESTYPE)
207 res = Resource(data)
208 res.AddResource(RESTYPE, id, RESNAME)
209 res.WriteResource()
210 res.ReleaseResource()
211
212 # Close the output file
213
214 CloseResFile(output)
215
Jack Jansen29a33551996-09-15 22:13:59 +0000216 macostools.touched(dest_fss)
Jack Jansen055782a1996-08-28 14:16:39 +0000217 if DEBUG:
218 print "Applet created:", destname
Jack Jansen7571f301995-07-29 13:48:41 +0000219
220
221# Copy resources between two resource file descriptors.
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000222# skip a resource named '__main__' or (if skipowner is set) 'Owner resource'.
223# Also skip resources with a type listed in skiptypes.
224#
225def copyres(input, output, skiptypes, skipowner):
Jack Jansen7571f301995-07-29 13:48:41 +0000226 ctor = None
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000227 alltypes = []
Jack Jansen7571f301995-07-29 13:48:41 +0000228 UseResFile(input)
229 ntypes = Count1Types()
230 for itype in range(1, 1+ntypes):
231 type = Get1IndType(itype)
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000232 if type in skiptypes:
233 continue
234 alltypes.append(type)
Jack Jansen7571f301995-07-29 13:48:41 +0000235 nresources = Count1Resources(type)
236 for ires in range(1, 1+nresources):
237 res = Get1IndResource(type, ires)
238 id, type, name = res.GetResInfo()
239 lcname = string.lower(name)
240 if (type, lcname) == (RESTYPE, RESNAME):
241 continue # Don't copy __main__ from template
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000242 # XXXX should look for id=0
243 if lcname == OWNERNAME:
244 if skipowner:
245 continue # Skip this one
246 else:
247 ctor = type
Jack Jansen7571f301995-07-29 13:48:41 +0000248 size = res.size
249 attrs = res.GetResAttrs()
Jack Jansen0f452fa1995-09-01 11:54:11 +0000250 if DEBUG:
251 print id, type, name, size, hex(attrs)
Jack Jansen7571f301995-07-29 13:48:41 +0000252 res.LoadResource()
253 res.DetachResource()
254 UseResFile(output)
255 try:
256 res2 = Get1Resource(type, id)
257 except MacOS.Error:
258 res2 = None
259 if res2:
Jack Jansen0f452fa1995-09-01 11:54:11 +0000260 if DEBUG:
261 print "Overwriting..."
Jack Jansen7571f301995-07-29 13:48:41 +0000262 res2.RemoveResource()
263 res.AddResource(type, id, name)
264 res.WriteResource()
265 attrs = attrs | res.GetResAttrs()
Jack Jansen0f452fa1995-09-01 11:54:11 +0000266 if DEBUG:
267 print "New attrs =", hex(attrs)
Jack Jansen7571f301995-07-29 13:48:41 +0000268 res.SetResAttrs(attrs)
269 UseResFile(input)
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000270 return alltypes, ctor
Jack Jansen7571f301995-07-29 13:48:41 +0000271
272
273# Show a message and exit
274
275def die(str):
276 message(str)
277 sys.exit(1)
278
279
280# Show a message
281
282def message(str, id = 256):
283 from Dlg import *
284 d = GetNewDialog(id, -1)
285 if not d:
286 print "Error:", `str`
287 print "DLOG id =", id, "not found."
288 return
289 tp, h, rect = d.GetDialogItem(2)
290 SetDialogItemText(h, str)
Jack Jansen6c6ad831996-01-22 14:55:52 +0000291 d.SetDialogDefaultItem(1)
Jack Jansen7571f301995-07-29 13:48:41 +0000292 while 1:
293 n = ModalDialog(None)
294 if n == 1: break
295 del d
296
297
298if __name__ == '__main__':
299 main()