blob: b51eef1ae305dc5b89b43264baec613bd4f7c2ee [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 Jansenaf647dd1997-05-13 15:42:26 +000023import EasyDialogs
Jack Jansen7571f301995-07-29 13:48:41 +000024
25# .pyc file (and 'PYC ' resource magic number)
26MAGIC = imp.get_magic()
27
28# Template file (searched on sys.path)
29TEMPLATE = "PythonApplet"
30
31# Specification of our resource
32RESTYPE = 'PYC '
33RESNAME = '__main__'
34
35# A resource with this name sets the "owner" (creator) of the destination
Jack Jansen3f14f4a1995-09-24 21:05:24 +000036# XXXX Should look for id=0
Jack Jansen7571f301995-07-29 13:48:41 +000037OWNERNAME = "owner resource"
38
39# OpenResFile mode parameters
40READ = 1
41WRITE = 2
42
Jack Jansen0f452fa1995-09-01 11:54:11 +000043def findtemplate():
44 """Locate the applet template along sys.path"""
Jack Jansen7571f301995-07-29 13:48:41 +000045 for p in sys.path:
46 template = os.path.join(p, TEMPLATE)
47 try:
Jack Jansen7c86b211995-08-31 13:48:43 +000048 template, d1, d2 = macfs.ResolveAliasFile(template)
Jack Jansen7571f301995-07-29 13:48:41 +000049 break
Jack Jansen7c86b211995-08-31 13:48:43 +000050 except (macfs.error, ValueError):
Jack Jansen7571f301995-07-29 13:48:41 +000051 continue
52 else:
Jack Jansen7c86b211995-08-31 13:48:43 +000053 die("Template %s not found on sys.path" % `TEMPLATE`)
Jack Jansen7571f301995-07-29 13:48:41 +000054 return
Jack Jansen7c86b211995-08-31 13:48:43 +000055 template = template.as_pathname()
Jack Jansen0f452fa1995-09-01 11:54:11 +000056 return template
57
58def main():
Jack Jansenaf647dd1997-05-13 15:42:26 +000059 global DEBUG
60 DEBUG=1
Jack Jansen0f452fa1995-09-01 11:54:11 +000061
62 # Find the template
63 # (there's no point in proceeding if we can't find it)
64
65 template = findtemplate()
Jack Jansen7c86b211995-08-31 13:48:43 +000066
Jack Jansen7571f301995-07-29 13:48:41 +000067 # Ask for source text if not specified in sys.argv[1:]
68
69 if not sys.argv[1:]:
Jack Jansen9062fa21995-08-14 12:21:12 +000070 srcfss, ok = macfs.PromptGetFile('Select Python source file:', 'TEXT')
Jack Jansen7571f301995-07-29 13:48:41 +000071 if not ok:
72 return
73 filename = srcfss.as_pathname()
74 tp, tf = os.path.split(filename)
75 if tf[-3:] == '.py':
76 tf = tf[:-3]
77 else:
78 tf = tf + '.applet'
79 dstfss, ok = macfs.StandardPutFile('Save application as:', tf)
80 if not ok: return
81 process(template, filename, dstfss.as_pathname())
82 else:
83
84 # Loop over all files to be processed
85 for filename in sys.argv[1:]:
86 process(template, filename, '')
87
Jack Jansen7571f301995-07-29 13:48:41 +000088def process(template, filename, output):
89
Jack Jansen0f452fa1995-09-01 11:54:11 +000090 if DEBUG:
Jack Jansenaf647dd1997-05-13 15:42:26 +000091 progress = EasyDialogs.ProgressBar("Processing %s..."%os.path.split(filename)[1], 120)
92 progress.label("Compiling...")
93 else:
94 progress = None
Jack Jansen7571f301995-07-29 13:48:41 +000095
96 # Read the source and compile it
97 # (there's no point overwriting the destination if it has a syntax error)
98
99 fp = open(filename)
100 text = fp.read()
101 fp.close()
102 try:
103 code = compile(text, filename, "exec")
104 except (SyntaxError, EOFError):
105 die("Syntax error in script %s" % `filename`)
106 return
107
108 # Set the destination file name
109
110 if string.lower(filename[-3:]) == ".py":
111 destname = filename[:-3]
112 rsrcname = destname + '.rsrc'
113 else:
114 destname = filename + ".applet"
115 rsrcname = filename + '.rsrc'
116
117 if output:
118 destname = output
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000119
120 # Try removing the output file
121 try:
122 os.unlink(output)
123 except os.error:
124 pass
125
126
127 # Create FSSpecs for the various files
128
Jack Jansen7c86b211995-08-31 13:48:43 +0000129 template_fss = macfs.FSSpec(template)
130 template_fss, d1, d2 = macfs.ResolveAliasFile(template_fss)
131 dest_fss = macfs.FSSpec(destname)
132
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000133 # Copy data (not resources, yet) from the template
Jack Jansenaf647dd1997-05-13 15:42:26 +0000134 if DEBUG:
135 progress.label("Copy data fork...")
136 progress.set(10)
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000137
Jack Jansen7571f301995-07-29 13:48:41 +0000138 tmpl = open(template, "rb")
139 dest = open(destname, "wb")
140 data = tmpl.read()
141 if data:
142 dest.write(data)
143 dest.close()
144 tmpl.close()
145
Jack Jansen7571f301995-07-29 13:48:41 +0000146 # Open the output resource fork
147
Jack Jansenaf647dd1997-05-13 15:42:26 +0000148 if DEBUG:
149 progress.label("Copy resources...")
150 progress.set(20)
Jack Jansen7571f301995-07-29 13:48:41 +0000151 try:
Jack Jansen7c86b211995-08-31 13:48:43 +0000152 output = FSpOpenResFile(dest_fss, WRITE)
Jack Jansen7571f301995-07-29 13:48:41 +0000153 except MacOS.Error:
Jack Jansen7571f301995-07-29 13:48:41 +0000154 CreateResFile(destname)
Jack Jansen7c86b211995-08-31 13:48:43 +0000155 output = FSpOpenResFile(dest_fss, WRITE)
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000156
157 # Copy the resources from the target specific resource template, if any
158 typesfound, ownertype = [], None
159 try:
160 input = FSpOpenResFile(rsrcname, READ)
161 except (MacOS.Error, ValueError):
162 pass
Jack Jansenaf647dd1997-05-13 15:42:26 +0000163 if DEBUG:
164 progress.inc(50)
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000165 else:
Jack Jansenaf647dd1997-05-13 15:42:26 +0000166 typesfound, ownertype = copyres(input, output, [], 0, progress)
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000167 CloseResFile(input)
168
169 # Check which resource-types we should not copy from the template
170 skiptypes = []
171 if 'SIZE' in typesfound: skiptypes.append('SIZE')
172 if 'BNDL' in typesfound: skiptypes = skiptypes + ['BNDL', 'FREF', 'icl4',
173 'icl8', 'ics4', 'ics8', 'ICN#', 'ics#']
174 skipowner = (ownertype <> None)
Jack Jansen7571f301995-07-29 13:48:41 +0000175
176 # Copy the resources from the template
177
Jack Jansen7c86b211995-08-31 13:48:43 +0000178 input = FSpOpenResFile(template_fss, READ)
Jack Jansenaf647dd1997-05-13 15:42:26 +0000179 dummy, tmplowner = copyres(input, output, skiptypes, skipowner, progress)
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000180 if ownertype == None:
181 ownertype = tmplowner
Jack Jansen7571f301995-07-29 13:48:41 +0000182 CloseResFile(input)
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000183 if ownertype == None:
184 die("No owner resource found in either resource file or template")
Jack Jansen7571f301995-07-29 13:48:41 +0000185
Jack Jansen7c86b211995-08-31 13:48:43 +0000186 # Now set the creator, type and bundle bit of the destination
187 dest_finfo = dest_fss.GetFInfo()
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000188 dest_finfo.Creator = ownertype
189 dest_finfo.Type = 'APPL'
Jack Jansen7c86b211995-08-31 13:48:43 +0000190 dest_finfo.Flags = dest_finfo.Flags | MACFS.kHasBundle
191 dest_finfo.Flags = dest_finfo.Flags & ~MACFS.kHasBeenInited
192 dest_fss.SetFInfo(dest_finfo)
Jack Jansen7571f301995-07-29 13:48:41 +0000193
194 # Make sure we're manipulating the output resource file now
195
196 UseResFile(output)
197
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000198 # Delete any existing 'PYC ' resource named __main__
Jack Jansen7571f301995-07-29 13:48:41 +0000199
200 try:
201 res = Get1NamedResource(RESTYPE, RESNAME)
202 res.RemoveResource()
203 except Error:
204 pass
205
206 # Create the raw data for the resource from the code object
Jack Jansenaf647dd1997-05-13 15:42:26 +0000207 if DEBUG:
208 progress.label("Write PYC resource...")
209 progress.set(120)
Jack Jansen7571f301995-07-29 13:48:41 +0000210
211 data = marshal.dumps(code)
212 del code
213 data = (MAGIC + '\0\0\0\0') + data
214
215 # Create the resource and write it
216
217 id = 0
218 while id < 128:
219 id = Unique1ID(RESTYPE)
220 res = Resource(data)
221 res.AddResource(RESTYPE, id, RESNAME)
222 res.WriteResource()
223 res.ReleaseResource()
224
225 # Close the output file
226
227 CloseResFile(output)
228
Jack Jansen29a33551996-09-15 22:13:59 +0000229 macostools.touched(dest_fss)
Jack Jansen055782a1996-08-28 14:16:39 +0000230 if DEBUG:
Jack Jansenaf647dd1997-05-13 15:42:26 +0000231 progress.label("Done.")
Jack Jansen7571f301995-07-29 13:48:41 +0000232
233
234# Copy resources between two resource file descriptors.
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000235# skip a resource named '__main__' or (if skipowner is set) 'Owner resource'.
236# Also skip resources with a type listed in skiptypes.
237#
Jack Jansenaf647dd1997-05-13 15:42:26 +0000238def copyres(input, output, skiptypes, skipowner, progress=None):
Jack Jansen7571f301995-07-29 13:48:41 +0000239 ctor = None
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000240 alltypes = []
Jack Jansen7571f301995-07-29 13:48:41 +0000241 UseResFile(input)
242 ntypes = Count1Types()
Jack Jansenaf647dd1997-05-13 15:42:26 +0000243 progress_type_inc = 50/ntypes
Jack Jansen7571f301995-07-29 13:48:41 +0000244 for itype in range(1, 1+ntypes):
245 type = Get1IndType(itype)
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000246 if type in skiptypes:
247 continue
248 alltypes.append(type)
Jack Jansen7571f301995-07-29 13:48:41 +0000249 nresources = Count1Resources(type)
Jack Jansenaf647dd1997-05-13 15:42:26 +0000250 progress_cur_inc = progress_type_inc/nresources
Jack Jansen7571f301995-07-29 13:48:41 +0000251 for ires in range(1, 1+nresources):
252 res = Get1IndResource(type, ires)
253 id, type, name = res.GetResInfo()
254 lcname = string.lower(name)
255 if (type, lcname) == (RESTYPE, RESNAME):
256 continue # Don't copy __main__ from template
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000257 # XXXX should look for id=0
258 if lcname == OWNERNAME:
259 if skipowner:
260 continue # Skip this one
261 else:
262 ctor = type
Jack Jansen7571f301995-07-29 13:48:41 +0000263 size = res.size
264 attrs = res.GetResAttrs()
Jack Jansenaf647dd1997-05-13 15:42:26 +0000265 if DEBUG and progress:
266 progress.label("Copy %s %d %s"%(type, id, name))
267 progress.inc(progress_cur_inc)
Jack Jansen7571f301995-07-29 13:48:41 +0000268 res.LoadResource()
269 res.DetachResource()
270 UseResFile(output)
271 try:
272 res2 = Get1Resource(type, id)
273 except MacOS.Error:
274 res2 = None
275 if res2:
Jack Jansenaf647dd1997-05-13 15:42:26 +0000276 if DEBUG and progress:
277 progress.label("Overwrite %s %d %s"%(type, id, name))
Jack Jansen7571f301995-07-29 13:48:41 +0000278 res2.RemoveResource()
279 res.AddResource(type, id, name)
280 res.WriteResource()
281 attrs = attrs | res.GetResAttrs()
Jack Jansen7571f301995-07-29 13:48:41 +0000282 res.SetResAttrs(attrs)
283 UseResFile(input)
Jack Jansen3f14f4a1995-09-24 21:05:24 +0000284 return alltypes, ctor
Jack Jansen7571f301995-07-29 13:48:41 +0000285
286
287# Show a message and exit
288
289def die(str):
290 message(str)
291 sys.exit(1)
292
293
294# Show a message
295
296def message(str, id = 256):
297 from Dlg import *
298 d = GetNewDialog(id, -1)
299 if not d:
300 print "Error:", `str`
301 print "DLOG id =", id, "not found."
302 return
303 tp, h, rect = d.GetDialogItem(2)
304 SetDialogItemText(h, str)
Jack Jansen6c6ad831996-01-22 14:55:52 +0000305 d.SetDialogDefaultItem(1)
Jack Jansen7571f301995-07-29 13:48:41 +0000306 while 1:
307 n = ModalDialog(None)
308 if n == 1: break
309 del d
310
311
312if __name__ == '__main__':
313 main()