blob: 55cf526f5b236c0ef305a9008fff4d6df965d854 [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
9import sys
10sys.stdout = sys.stderr
11
12import string
13import os
14import marshal
15import imp
16import macfs
Jack Jansen7c86b211995-08-31 13:48:43 +000017import MACFS
Jack Jansen7571f301995-07-29 13:48:41 +000018import MacOS
19from Res import *
20
21# .pyc file (and 'PYC ' resource magic number)
22MAGIC = imp.get_magic()
23
24# Template file (searched on sys.path)
25TEMPLATE = "PythonApplet"
26
27# Specification of our resource
28RESTYPE = 'PYC '
29RESNAME = '__main__'
30
31# A resource with this name sets the "owner" (creator) of the destination
32OWNERNAME = "owner resource"
33
34# OpenResFile mode parameters
35READ = 1
36WRITE = 2
37
38def main():
39
40 # Find the template
41 # (there's no point in proceeding if we can't find it)
42
43 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()
54 print 'Using template', template
55
Jack Jansen7571f301995-07-29 13:48:41 +000056 # Ask for source text if not specified in sys.argv[1:]
57
58 if not sys.argv[1:]:
Jack Jansen9062fa21995-08-14 12:21:12 +000059 srcfss, ok = macfs.PromptGetFile('Select Python source file:', 'TEXT')
Jack Jansen7571f301995-07-29 13:48:41 +000060 if not ok:
61 return
62 filename = srcfss.as_pathname()
63 tp, tf = os.path.split(filename)
64 if tf[-3:] == '.py':
65 tf = tf[:-3]
66 else:
67 tf = tf + '.applet'
68 dstfss, ok = macfs.StandardPutFile('Save application as:', tf)
69 if not ok: return
70 process(template, filename, dstfss.as_pathname())
71 else:
72
73 # Loop over all files to be processed
74 for filename in sys.argv[1:]:
75 process(template, filename, '')
76
77undefs = ('Atmp', '????', ' ', '\0\0\0\0', 'BINA')
78
79def process(template, filename, output):
80
81 print "Processing", `filename`, "..."
82
83 # Read the source and compile it
84 # (there's no point overwriting the destination if it has a syntax error)
85
86 fp = open(filename)
87 text = fp.read()
88 fp.close()
89 try:
90 code = compile(text, filename, "exec")
91 except (SyntaxError, EOFError):
92 die("Syntax error in script %s" % `filename`)
93 return
94
95 # Set the destination file name
96
97 if string.lower(filename[-3:]) == ".py":
98 destname = filename[:-3]
99 rsrcname = destname + '.rsrc'
100 else:
101 destname = filename + ".applet"
102 rsrcname = filename + '.rsrc'
103
104 if output:
105 destname = output
106 # Copy the data from the template (creating the file as well)
107
Jack Jansen7c86b211995-08-31 13:48:43 +0000108 template_fss = macfs.FSSpec(template)
109 template_fss, d1, d2 = macfs.ResolveAliasFile(template_fss)
110 dest_fss = macfs.FSSpec(destname)
111
Jack Jansen7571f301995-07-29 13:48:41 +0000112 tmpl = open(template, "rb")
113 dest = open(destname, "wb")
114 data = tmpl.read()
115 if data:
116 dest.write(data)
117 dest.close()
118 tmpl.close()
119
120 # Copy the creator of the template to the destination
121 # unless it already got one. Set type to APPL
122
Jack Jansen7c86b211995-08-31 13:48:43 +0000123 tctor, ttype = template_fss.GetCreatorType()
124 ctor, type = dest_fss.GetCreatorType()
Jack Jansen7571f301995-07-29 13:48:41 +0000125 if type in undefs: type = 'APPL'
126 if ctor in undefs: ctor = tctor
127
128 # Open the output resource fork
129
130 try:
Jack Jansen7c86b211995-08-31 13:48:43 +0000131 output = FSpOpenResFile(dest_fss, WRITE)
Jack Jansen7571f301995-07-29 13:48:41 +0000132 except MacOS.Error:
133 print "Creating resource fork..."
134 CreateResFile(destname)
Jack Jansen7c86b211995-08-31 13:48:43 +0000135 output = FSpOpenResFile(dest_fss, WRITE)
Jack Jansen7571f301995-07-29 13:48:41 +0000136
137 # Copy the resources from the template
138
Jack Jansen7c86b211995-08-31 13:48:43 +0000139 input = FSpOpenResFile(template_fss, READ)
Jack Jansen7571f301995-07-29 13:48:41 +0000140 newctor = copyres(input, output)
141 CloseResFile(input)
142 if newctor: ctor = newctor
143
144 # Copy the resources from the target specific resource template, if any
145
146 try:
147 input = FSpOpenResFile(rsrcname, READ)
148 except MacOS.Error:
149 pass
150 else:
151 newctor = copyres(input, output)
152 CloseResFile(input)
153 if newctor: ctor = newctor
154
Jack Jansen7c86b211995-08-31 13:48:43 +0000155 # Now set the creator, type and bundle bit of the destination
156 dest_finfo = dest_fss.GetFInfo()
157 dest_finfo.Creator = ctor
158 dest_finfo.Type = type
159 dest_finfo.Flags = dest_finfo.Flags | MACFS.kHasBundle
160 dest_finfo.Flags = dest_finfo.Flags & ~MACFS.kHasBeenInited
161 dest_fss.SetFInfo(dest_finfo)
Jack Jansen7571f301995-07-29 13:48:41 +0000162
163 # Make sure we're manipulating the output resource file now
164
165 UseResFile(output)
166
167 # Delete any existing 'PYC 'resource named __main__
168
169 try:
170 res = Get1NamedResource(RESTYPE, RESNAME)
171 res.RemoveResource()
172 except Error:
173 pass
174
175 # Create the raw data for the resource from the code object
176
177 data = marshal.dumps(code)
178 del code
179 data = (MAGIC + '\0\0\0\0') + data
180
181 # Create the resource and write it
182
183 id = 0
184 while id < 128:
185 id = Unique1ID(RESTYPE)
186 res = Resource(data)
187 res.AddResource(RESTYPE, id, RESNAME)
188 res.WriteResource()
189 res.ReleaseResource()
190
191 # Close the output file
192
193 CloseResFile(output)
194
195 # Give positive feedback
196
197 message("Applet %s created." % `destname`)
198
199
200# Copy resources between two resource file descriptors.
201# Exception: don't copy a __main__ resource.
202# If a resource's name is "owner resource", its type is returned
203# (so the caller can use it to set the destination's creator)
204
205def copyres(input, output):
206 ctor = None
207 UseResFile(input)
208 ntypes = Count1Types()
209 for itype in range(1, 1+ntypes):
210 type = Get1IndType(itype)
211 nresources = Count1Resources(type)
212 for ires in range(1, 1+nresources):
213 res = Get1IndResource(type, ires)
214 id, type, name = res.GetResInfo()
215 lcname = string.lower(name)
216 if (type, lcname) == (RESTYPE, RESNAME):
217 continue # Don't copy __main__ from template
218 if lcname == OWNERNAME: ctor = type
219 size = res.size
220 attrs = res.GetResAttrs()
221 print id, type, name, size, hex(attrs)
222 res.LoadResource()
223 res.DetachResource()
224 UseResFile(output)
225 try:
226 res2 = Get1Resource(type, id)
227 except MacOS.Error:
228 res2 = None
229 if res2:
230 print "Overwriting..."
231 res2.RemoveResource()
232 res.AddResource(type, id, name)
233 res.WriteResource()
234 attrs = attrs | res.GetResAttrs()
235 print "New attrs =", hex(attrs)
236 res.SetResAttrs(attrs)
237 UseResFile(input)
238 return ctor
239
240
241# Show a message and exit
242
243def die(str):
244 message(str)
245 sys.exit(1)
246
247
248# Show a message
249
250def message(str, id = 256):
251 from Dlg import *
252 d = GetNewDialog(id, -1)
253 if not d:
254 print "Error:", `str`
255 print "DLOG id =", id, "not found."
256 return
257 tp, h, rect = d.GetDialogItem(2)
258 SetDialogItemText(h, str)
259 while 1:
260 n = ModalDialog(None)
261 if n == 1: break
262 del d
263
264
265if __name__ == '__main__':
266 main()
267