1 """tools for BuildApplet and BuildApplication"""
16 BuildError
= "BuildError"
21 # .pyc file (and 'PYC ' resource magic number)
22 MAGIC
= imp
.get_magic()
24 # Template file (searched on sys.path)
25 TEMPLATE
= "PythonInterpreter"
27 # Specification of our resource
31 # A resource with this name sets the "owner" (creator) of the destination
32 # It should also have ID=0. Either of these alone is not enough.
33 OWNERNAME
= "owner resource"
35 # Default applet creator code
36 DEFAULT_APPLET_CREATOR
="Pyta"
38 # OpenResFile mode parameters
43 def findtemplate(template
=None):
44 """Locate the applet template along sys.path"""
48 file = os
.path
.join(p
, template
)
50 file, d1
, d2
= macfs
.ResolveAliasFile(file)
52 except (macfs
.error
, ValueError):
55 raise BuildError
, "Template %s not found on sys.path" % `template`
56 file = file.as_pathname()
60 def process(template
, filename
, output
, copy_codefragment
):
63 progress
= EasyDialogs
.ProgressBar("Processing %s..."%os.path
.split(filename
)[1], 120)
64 progress
.label("Compiling...")
68 # Read the source and compile it
69 # (there's no point overwriting the destination if it has a syntax error)
75 code
= compile(text
, filename
, "exec")
76 except (SyntaxError, EOFError):
77 raise BuildError
, "Syntax error in script %s" % `filename`
79 # Set the destination file name
81 if string
.lower(filename
[-3:]) == ".py":
82 destname
= filename
[:-3]
83 rsrcname
= destname
+ '.rsrc'
85 destname
= filename
+ ".applet"
86 rsrcname
= filename
+ '.rsrc'
91 # Try removing the output file
96 process_common(template
, progress
, code
, rsrcname
, destname
, 0, copy_codefragment
)
99 def update(template
, filename
, output
):
101 progress
= EasyDialogs
.ProgressBar("Updating %s..."%os.path
.split(filename
)[1], 120)
105 output
= filename
+ ' (updated)'
107 # Try removing the output file
112 process_common(template
, progress
, None, filename
, output
, 1, 1)
115 def process_common(template
, progress
, code
, rsrcname
, destname
, is_update
, copy_codefragment
):
116 # Create FSSpecs for the various files
117 template_fss
= macfs
.FSSpec(template
)
118 template_fss
, d1
, d2
= macfs
.ResolveAliasFile(template_fss
)
119 dest_fss
= macfs
.FSSpec(destname
)
121 # Copy data (not resources, yet) from the template
123 progress
.label("Copy data fork...")
126 if copy_codefragment
:
127 tmpl
= open(template
, "rb")
128 dest
= open(destname
, "wb")
137 # Open the output resource fork
140 progress
.label("Copy resources...")
143 output
= Res
.FSpOpenResFile(dest_fss
, WRITE
)
145 Res
.FSpCreateResFile(destname
, '????', 'APPL', MACFS
.smAllScripts
)
146 output
= Res
.FSpOpenResFile(dest_fss
, WRITE
)
148 # Copy the resources from the target specific resource template, if any
149 typesfound
, ownertype
= [], None
151 input = Res
.FSpOpenResFile(rsrcname
, READ
)
152 except (MacOS
.Error
, ValueError):
158 skip_oldfile
= ['cfrg']
161 typesfound
, ownertype
= copyres(input, output
, skip_oldfile
, 0, progress
)
162 Res
.CloseResFile(input)
164 # Check which resource-types we should not copy from the template
166 if 'vers' in typesfound
: skiptypes
.append('vers')
167 if 'SIZE' in typesfound
: skiptypes
.append('SIZE')
168 if 'BNDL' in typesfound
: skiptypes
= skiptypes
+ ['BNDL', 'FREF', 'icl4',
169 'icl8', 'ics4', 'ics8', 'ICN#', 'ics#']
170 if not copy_codefragment
:
171 skiptypes
.append('cfrg')
172 ## skipowner = (ownertype <> None)
174 # Copy the resources from the template
176 input = Res
.FSpOpenResFile(template_fss
, READ
)
177 dummy
, tmplowner
= copyres(input, output
, skiptypes
, 1, progress
)
179 Res
.CloseResFile(input)
180 ## if ownertype == None:
181 ## raise BuildError, "No owner resource found in either resource file or template"
182 # Make sure we're manipulating the output resource file now
184 Res
.UseResFile(output
)
186 if ownertype
== None:
187 # No owner resource in the template. We have skipped the
188 # Python owner resource, so we have to add our own. The relevant
189 # bundle stuff is already included in the interpret/applet template.
190 newres
= Res
.Resource('\0')
191 newres
.AddResource(DEFAULT_APPLET_CREATOR
, 0, "Owner resource")
192 ownertype
= DEFAULT_APPLET_CREATOR
195 # Delete any existing 'PYC ' resource named __main__
198 res
= Res
.Get1NamedResource(RESTYPE
, RESNAME
)
203 # Create the raw data for the resource from the code object
205 progress
.label("Write PYC resource...")
208 data
= marshal
.dumps(code
)
210 data
= (MAGIC
+ '\0\0\0\0') + data
212 # Create the resource and write it
216 id = Res
.Unique1ID(RESTYPE
)
217 res
= Res
.Resource(data
)
218 res
.AddResource(RESTYPE
, id, RESNAME
)
219 attrs
= res
.GetResAttrs()
220 attrs
= attrs |
0x04 # set preload
221 res
.SetResAttrs(attrs
)
223 res
.ReleaseResource()
225 # Close the output file
227 Res
.CloseResFile(output
)
229 # Now set the creator, type and bundle bit of the destination
230 dest_finfo
= dest_fss
.GetFInfo()
231 dest_finfo
.Creator
= ownertype
232 dest_finfo
.Type
= 'APPL'
233 dest_finfo
.Flags
= dest_finfo
.Flags | MACFS
.kHasBundle | MACFS
.kIsShared
234 dest_finfo
.Flags
= dest_finfo
.Flags
& ~MACFS
.kHasBeenInited
235 dest_fss
.SetFInfo(dest_finfo
)
237 macostools
.touched(dest_fss
)
239 progress
.label("Done.")
242 # Copy resources between two resource file descriptors.
243 # skip a resource named '__main__' or (if skipowner is set) with ID zero.
244 # Also skip resources with a type listed in skiptypes.
246 def copyres(input, output
, skiptypes
, skipowner
, progress
=None):
249 Res
.UseResFile(input)
250 ntypes
= Res
.Count1Types()
251 progress_type_inc
= 50/ntypes
252 for itype
in range(1, 1+ntypes
):
253 type = Res
.Get1IndType(itype
)
254 if type in skiptypes
:
256 alltypes
.append(type)
257 nresources
= Res
.Count1Resources(type)
258 progress_cur_inc
= progress_type_inc
/nresources
259 for ires
in range(1, 1+nresources
):
260 res
= Res
.Get1IndResource(type, ires
)
261 id, type, name
= res
.GetResInfo()
262 lcname
= string
.lower(name
)
264 if lcname
== OWNERNAME
and id == 0:
266 continue # Skip this one
270 attrs
= res
.GetResAttrs()
271 if DEBUG
and progress
:
272 progress
.label("Copy %s %d %s"%(type, id, name
))
273 progress
.inc(progress_cur_inc
)
276 Res
.UseResFile(output
)
278 res2
= Res
.Get1Resource(type, id)
282 if DEBUG
and progress
:
283 progress
.label("Overwrite %s %d %s"%(type, id, name
))
284 res2
.RemoveResource()
285 res
.AddResource(type, id, name
)
287 attrs
= attrs | res
.GetResAttrs()
288 res
.SetResAttrs(attrs
)
289 Res
.UseResFile(input)
290 return alltypes
, ctor