blob: 45f3e9e1775ad9dcafcddf49e0d9270f34fc1538 [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
34OWNERNAME = "owner resource"
35
36# OpenResFile mode parameters
37READ = 1
38WRITE = 2
39
Jack Jansen0f452fa1995-09-01 11:54:11 +000040def findtemplate():
41 """Locate the applet template along sys.path"""
Jack Jansen7571f301995-07-29 13:48:41 +000042 for p in sys.path:
43 template = os.path.join(p, TEMPLATE)
44 try:
Jack Jansen7c86b211995-08-31 13:48:43 +000045 template, d1, d2 = macfs.ResolveAliasFile(template)
Jack Jansen7571f301995-07-29 13:48:41 +000046 break
Jack Jansen7c86b211995-08-31 13:48:43 +000047 except (macfs.error, ValueError):
Jack Jansen7571f301995-07-29 13:48:41 +000048 continue
49 else:
Jack Jansen7c86b211995-08-31 13:48:43 +000050 die("Template %s not found on sys.path" % `TEMPLATE`)
Jack Jansen7571f301995-07-29 13:48:41 +000051 return
Jack Jansen7c86b211995-08-31 13:48:43 +000052 template = template.as_pathname()
Jack Jansen0f452fa1995-09-01 11:54:11 +000053 return template
54
55def main():
56 global DEBUG
57 DEBUG=1
58
59 # Find the template
60 # (there's no point in proceeding if we can't find it)
61
62 template = findtemplate()
Jack Jansen7c86b211995-08-31 13:48:43 +000063 print 'Using template', template
64
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
86undefs = ('Atmp', '????', ' ', '\0\0\0\0', 'BINA')
87
88def process(template, filename, output):
89
Jack Jansen0f452fa1995-09-01 11:54:11 +000090 if DEBUG:
91 print "Processing", `filename`, "..."
Jack Jansen7571f301995-07-29 13:48:41 +000092
93 # Read the source and compile it
94 # (there's no point overwriting the destination if it has a syntax error)
95
96 fp = open(filename)
97 text = fp.read()
98 fp.close()
99 try:
100 code = compile(text, filename, "exec")
101 except (SyntaxError, EOFError):
102 die("Syntax error in script %s" % `filename`)
103 return
104
105 # Set the destination file name
106
107 if string.lower(filename[-3:]) == ".py":
108 destname = filename[:-3]
109 rsrcname = destname + '.rsrc'
110 else:
111 destname = filename + ".applet"
112 rsrcname = filename + '.rsrc'
113
114 if output:
115 destname = output
116 # Copy the data from the template (creating the file as well)
117
Jack Jansen7c86b211995-08-31 13:48:43 +0000118 template_fss = macfs.FSSpec(template)
119 template_fss, d1, d2 = macfs.ResolveAliasFile(template_fss)
120 dest_fss = macfs.FSSpec(destname)
121
Jack Jansen7571f301995-07-29 13:48:41 +0000122 tmpl = open(template, "rb")
123 dest = open(destname, "wb")
124 data = tmpl.read()
125 if data:
126 dest.write(data)
127 dest.close()
128 tmpl.close()
129
130 # Copy the creator of the template to the destination
131 # unless it already got one. Set type to APPL
132
Jack Jansen7c86b211995-08-31 13:48:43 +0000133 tctor, ttype = template_fss.GetCreatorType()
134 ctor, type = dest_fss.GetCreatorType()
Jack Jansen7571f301995-07-29 13:48:41 +0000135 if type in undefs: type = 'APPL'
136 if ctor in undefs: ctor = tctor
137
138 # 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 Jansen7571f301995-07-29 13:48:41 +0000147
148 # Copy the resources from the template
149
Jack Jansen7c86b211995-08-31 13:48:43 +0000150 input = FSpOpenResFile(template_fss, READ)
Jack Jansen7571f301995-07-29 13:48:41 +0000151 newctor = copyres(input, output)
152 CloseResFile(input)
153 if newctor: ctor = newctor
154
155 # Copy the resources from the target specific resource template, if any
156
157 try:
158 input = FSpOpenResFile(rsrcname, READ)
Jack Jansen0f452fa1995-09-01 11:54:11 +0000159 except (MacOS.Error, ValueError):
160 print 'No resource file', rsrcname
Jack Jansen7571f301995-07-29 13:48:41 +0000161 pass
162 else:
163 newctor = copyres(input, output)
164 CloseResFile(input)
165 if newctor: ctor = newctor
166
Jack Jansen7c86b211995-08-31 13:48:43 +0000167 # Now set the creator, type and bundle bit of the destination
168 dest_finfo = dest_fss.GetFInfo()
169 dest_finfo.Creator = ctor
170 dest_finfo.Type = type
171 dest_finfo.Flags = dest_finfo.Flags | MACFS.kHasBundle
172 dest_finfo.Flags = dest_finfo.Flags & ~MACFS.kHasBeenInited
173 dest_fss.SetFInfo(dest_finfo)
Jack Jansen7571f301995-07-29 13:48:41 +0000174
175 # Make sure we're manipulating the output resource file now
176
177 UseResFile(output)
178
179 # Delete any existing 'PYC 'resource named __main__
180
181 try:
182 res = Get1NamedResource(RESTYPE, RESNAME)
183 res.RemoveResource()
184 except Error:
185 pass
186
187 # Create the raw data for the resource from the code object
188
189 data = marshal.dumps(code)
190 del code
191 data = (MAGIC + '\0\0\0\0') + data
192
193 # Create the resource and write it
194
195 id = 0
196 while id < 128:
197 id = Unique1ID(RESTYPE)
198 res = Resource(data)
199 res.AddResource(RESTYPE, id, RESNAME)
200 res.WriteResource()
201 res.ReleaseResource()
202
203 # Close the output file
204
205 CloseResFile(output)
206
207 # Give positive feedback
208
209 message("Applet %s created." % `destname`)
210
211
212# Copy resources between two resource file descriptors.
213# Exception: don't copy a __main__ resource.
214# If a resource's name is "owner resource", its type is returned
215# (so the caller can use it to set the destination's creator)
216
217def copyres(input, output):
218 ctor = None
219 UseResFile(input)
220 ntypes = Count1Types()
221 for itype in range(1, 1+ntypes):
222 type = Get1IndType(itype)
223 nresources = Count1Resources(type)
224 for ires in range(1, 1+nresources):
225 res = Get1IndResource(type, ires)
226 id, type, name = res.GetResInfo()
227 lcname = string.lower(name)
228 if (type, lcname) == (RESTYPE, RESNAME):
229 continue # Don't copy __main__ from template
230 if lcname == OWNERNAME: ctor = type
231 size = res.size
232 attrs = res.GetResAttrs()
Jack Jansen0f452fa1995-09-01 11:54:11 +0000233 if DEBUG:
234 print id, type, name, size, hex(attrs)
Jack Jansen7571f301995-07-29 13:48:41 +0000235 res.LoadResource()
236 res.DetachResource()
237 UseResFile(output)
238 try:
239 res2 = Get1Resource(type, id)
240 except MacOS.Error:
241 res2 = None
242 if res2:
Jack Jansen0f452fa1995-09-01 11:54:11 +0000243 if DEBUG:
244 print "Overwriting..."
Jack Jansen7571f301995-07-29 13:48:41 +0000245 res2.RemoveResource()
246 res.AddResource(type, id, name)
247 res.WriteResource()
248 attrs = attrs | res.GetResAttrs()
Jack Jansen0f452fa1995-09-01 11:54:11 +0000249 if DEBUG:
250 print "New attrs =", hex(attrs)
Jack Jansen7571f301995-07-29 13:48:41 +0000251 res.SetResAttrs(attrs)
252 UseResFile(input)
253 return ctor
254
255
256# Show a message and exit
257
258def die(str):
259 message(str)
260 sys.exit(1)
261
262
263# Show a message
264
265def message(str, id = 256):
266 from Dlg import *
267 d = GetNewDialog(id, -1)
268 if not d:
269 print "Error:", `str`
270 print "DLOG id =", id, "not found."
271 return
272 tp, h, rect = d.GetDialogItem(2)
273 SetDialogItemText(h, str)
274 while 1:
275 n = ModalDialog(None)
276 if n == 1: break
277 del d
278
279
280if __name__ == '__main__':
281 main()
282