1 """Create an applet from a Python script.
3 This puts up a dialog asking for a Python source file ('TEXT').
4 The output is a file with the same name but its ".py" suffix dropped.
5 It is created by copying an applet template and then adding a 'PYC '
6 resource named __main__ containing the compiled, marshalled script.
12 sys
.stdout
= sys
.stderr
25 # .pyc file (and 'PYC ' resource magic number)
26 MAGIC
= imp
.get_magic()
28 # Template file (searched on sys.path)
29 TEMPLATE
= "PythonApplet"
31 # Specification of our resource
35 # A resource with this name sets the "owner" (creator) of the destination
36 # XXXX Should look for id=0
37 OWNERNAME
= "owner resource"
39 # OpenResFile mode parameters
44 """Locate the applet template along sys.path"""
46 template
= os
.path
.join(p
, TEMPLATE
)
48 template
, d1
, d2
= macfs
.ResolveAliasFile(template
)
50 except (macfs
.error
, ValueError):
53 die("Template %s not found on sys.path" % `TEMPLATE`
)
55 template
= template
.as_pathname()
63 # (there's no point in proceeding if we can't find it)
65 template
= findtemplate()
67 # Ask for source text if not specified in sys.argv[1:]
70 srcfss
, ok
= macfs
.PromptGetFile('Select Python source or applet:', 'TEXT', 'APPL')
73 filename
= srcfss
.as_pathname()
74 tp
, tf
= os
.path
.split(filename
)
79 dstfss
, ok
= macfs
.StandardPutFile('Save application as:', tf
)
81 dstfilename
= dstfss
.as_pathname()
82 cr
, tp
= MacOS
.GetCreatorAndType(filename
)
84 update(template
, filename
, dstfilename
)
86 process(template
, filename
, dstfilename
)
89 # Loop over all files to be processed
90 for filename
in sys
.argv
[1:]:
91 cr
, tp
= MacOS
.GetCreatorAndType(filename
)
93 update(template
, filename
, '')
95 process(template
, filename
, '')
97 def process(template
, filename
, output
):
100 progress
= EasyDialogs
.ProgressBar("Processing %s..."%os.path
.split(filename
)[1], 120)
101 progress
.label("Compiling...")
105 # Read the source and compile it
106 # (there's no point overwriting the destination if it has a syntax error)
112 code
= compile(text
, filename
, "exec")
113 except (SyntaxError, EOFError):
114 die("Syntax error in script %s" % `filename`
)
117 # Set the destination file name
119 if string
.lower(filename
[-3:]) == ".py":
120 destname
= filename
[:-3]
121 rsrcname
= destname
+ '.rsrc'
123 destname
= filename
+ ".applet"
124 rsrcname
= filename
+ '.rsrc'
129 process_common(template
, progress
, code
, rsrcname
, destname
, 0)
131 def update(template
, filename
, output
):
133 progress
= EasyDialogs
.ProgressBar("Updating %s..."%os.path
.split(filename
)[1], 120)
137 output
= filename
+ ' (updated)'
138 process_common(template
, progress
, None, filename
, output
, 1)
141 def process_common(template
, progress
, code
, rsrcname
, destname
, is_update
):
142 # Try removing the output file
149 # Create FSSpecs for the various files
151 template_fss
= macfs
.FSSpec(template
)
152 template_fss
, d1
, d2
= macfs
.ResolveAliasFile(template_fss
)
153 dest_fss
= macfs
.FSSpec(destname
)
155 # Copy data (not resources, yet) from the template
157 progress
.label("Copy data fork...")
160 tmpl
= open(template
, "rb")
161 dest
= open(destname
, "wb")
168 # Open the output resource fork
171 progress
.label("Copy resources...")
174 output
= FSpOpenResFile(dest_fss
, WRITE
)
176 CreateResFile(destname
)
177 output
= FSpOpenResFile(dest_fss
, WRITE
)
179 # Copy the resources from the target specific resource template, if any
180 typesfound
, ownertype
= [], None
182 input = FSpOpenResFile(rsrcname
, READ
)
183 except (MacOS
.Error
, ValueError):
189 skip_oldfile
= ['cfrg']
192 typesfound
, ownertype
= copyres(input, output
, skip_oldfile
, 0, progress
)
195 # Check which resource-types we should not copy from the template
197 if 'SIZE' in typesfound
: skiptypes
.append('SIZE')
198 if 'BNDL' in typesfound
: skiptypes
= skiptypes
+ ['BNDL', 'FREF', 'icl4',
199 'icl8', 'ics4', 'ics8', 'ICN#', 'ics#']
200 skipowner
= (ownertype
<> None)
202 # Copy the resources from the template
204 input = FSpOpenResFile(template_fss
, READ
)
205 dummy
, tmplowner
= copyres(input, output
, skiptypes
, skipowner
, progress
)
206 if ownertype
== None:
207 ownertype
= tmplowner
209 if ownertype
== None:
210 die("No owner resource found in either resource file or template")
212 # Now set the creator, type and bundle bit of the destination
213 dest_finfo
= dest_fss
.GetFInfo()
214 dest_finfo
.Creator
= ownertype
215 dest_finfo
.Type
= 'APPL'
216 dest_finfo
.Flags
= dest_finfo
.Flags | MACFS
.kHasBundle
217 dest_finfo
.Flags
= dest_finfo
.Flags
& ~MACFS
.kHasBeenInited
218 dest_fss
.SetFInfo(dest_finfo
)
220 # Make sure we're manipulating the output resource file now
225 # Delete any existing 'PYC ' resource named __main__
228 res
= Get1NamedResource(RESTYPE
, RESNAME
)
233 # Create the raw data for the resource from the code object
235 progress
.label("Write PYC resource...")
238 data
= marshal
.dumps(code
)
240 data
= (MAGIC
+ '\0\0\0\0') + data
242 # Create the resource and write it
246 id = Unique1ID(RESTYPE
)
248 res
.AddResource(RESTYPE
, id, RESNAME
)
250 res
.ReleaseResource()
252 # Close the output file
256 macostools
.touched(dest_fss
)
258 progress
.label("Done.")
261 # Copy resources between two resource file descriptors.
262 # skip a resource named '__main__' or (if skipowner is set) 'Owner resource'.
263 # Also skip resources with a type listed in skiptypes.
265 def copyres(input, output
, skiptypes
, skipowner
, progress
=None):
269 ntypes
= Count1Types()
270 progress_type_inc
= 50/ntypes
271 for itype
in range(1, 1+ntypes
):
272 type = Get1IndType(itype
)
273 if type in skiptypes
:
275 alltypes
.append(type)
276 nresources
= Count1Resources(type)
277 progress_cur_inc
= progress_type_inc
/nresources
278 for ires
in range(1, 1+nresources
):
279 res
= Get1IndResource(type, ires
)
280 id, type, name
= res
.GetResInfo()
281 lcname
= string
.lower(name
)
282 ## if (type, lcname) == (RESTYPE, RESNAME):
283 ## continue # Don't copy __main__ from template
284 # XXXX should look for id=0
285 if lcname
== OWNERNAME
:
287 continue # Skip this one
291 attrs
= res
.GetResAttrs()
292 if DEBUG
and progress
:
293 progress
.label("Copy %s %d %s"%(type, id, name
))
294 progress
.inc(progress_cur_inc
)
299 res2
= Get1Resource(type, id)
303 if DEBUG
and progress
:
304 progress
.label("Overwrite %s %d %s"%(type, id, name
))
305 res2
.RemoveResource()
306 res
.AddResource(type, id, name
)
308 attrs
= attrs | res
.GetResAttrs()
309 res
.SetResAttrs(attrs
)
311 return alltypes
, ctor
314 # Show a message and exit
323 def message(str, id = 256):
325 d
= GetNewDialog(id, -1)
327 print "Error:", `
str`
328 print "DLOG id =", id, "not found."
330 tp
, h
, rect
= d
.GetDialogItem(2)
331 SetDialogItemText(h
, str)
332 d
.SetDialogDefaultItem(1)
334 n
= ModalDialog(None)
339 if __name__
== '__main__':