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
= "PythonApplet"
27 # Specification of our resource
31 # A resource with this name sets the "owner" (creator) of the destination
32 # XXXX Should look for id=0
33 OWNERNAME
= "owner resource"
35 # OpenResFile mode parameters
41 """Locate the applet template along sys.path"""
43 template
= os
.path
.join(p
, TEMPLATE
)
45 template
, d1
, d2
= macfs
.ResolveAliasFile(template
)
47 except (macfs
.error
, ValueError):
50 raise BuildError
, "Template %s not found on sys.path" % `TEMPLATE`
51 template
= template
.as_pathname()
55 def process(template
, filename
, output
, copy_codefragment
):
58 progress
= EasyDialogs
.ProgressBar("Processing %s..."%os.path
.split(filename
)[1], 120)
59 progress
.label("Compiling...")
63 # Read the source and compile it
64 # (there's no point overwriting the destination if it has a syntax error)
70 code
= compile(text
, filename
, "exec")
71 except (SyntaxError, EOFError):
72 raise BuildError
, "Syntax error in script %s" % `filename`
74 # Set the destination file name
76 if string
.lower(filename
[-3:]) == ".py":
77 destname
= filename
[:-3]
78 rsrcname
= destname
+ '.rsrc'
80 destname
= filename
+ ".applet"
81 rsrcname
= filename
+ '.rsrc'
86 # Try removing the output file
91 process_common(template
, progress
, code
, rsrcname
, destname
, 0, copy_codefragment
)
94 def update(template
, filename
, output
):
96 progress
= EasyDialogs
.ProgressBar("Updating %s..."%os.path
.split(filename
)[1], 120)
100 output
= filename
+ ' (updated)'
102 # Try removing the output file
107 process_common(template
, progress
, None, filename
, output
, 1, 1)
110 def process_common(template
, progress
, code
, rsrcname
, destname
, is_update
, copy_codefragment
):
111 # Create FSSpecs for the various files
112 template_fss
= macfs
.FSSpec(template
)
113 template_fss
, d1
, d2
= macfs
.ResolveAliasFile(template_fss
)
114 dest_fss
= macfs
.FSSpec(destname
)
116 # Copy data (not resources, yet) from the template
118 progress
.label("Copy data fork...")
121 if copy_codefragment
:
122 tmpl
= open(template
, "rb")
123 dest
= open(destname
, "wb")
132 # Open the output resource fork
135 progress
.label("Copy resources...")
138 output
= Res
.FSpOpenResFile(dest_fss
, WRITE
)
140 Res
.CreateResFile(destname
)
141 output
= Res
.FSpOpenResFile(dest_fss
, WRITE
)
143 # Copy the resources from the target specific resource template, if any
144 typesfound
, ownertype
= [], None
146 input = Res
.FSpOpenResFile(rsrcname
, READ
)
147 except (MacOS
.Error
, ValueError):
153 skip_oldfile
= ['cfrg']
156 typesfound
, ownertype
= copyres(input, output
, skip_oldfile
, 0, progress
)
157 Res
.CloseResFile(input)
159 # Check which resource-types we should not copy from the template
161 if 'SIZE' in typesfound
: skiptypes
.append('SIZE')
162 if 'BNDL' in typesfound
: skiptypes
= skiptypes
+ ['BNDL', 'FREF', 'icl4',
163 'icl8', 'ics4', 'ics8', 'ICN#', 'ics#']
164 if not copy_codefragment
:
165 skiptypes
.append('cfrg')
166 skipowner
= (ownertype
<> None)
168 # Copy the resources from the template
170 input = Res
.FSpOpenResFile(template_fss
, READ
)
171 dummy
, tmplowner
= copyres(input, output
, skiptypes
, skipowner
, progress
)
172 if ownertype
== None:
173 ownertype
= tmplowner
174 Res
.CloseResFile(input)
175 if ownertype
== None:
176 raise BuildError
, "No owner resource found in either resource file or template"
178 # Make sure we're manipulating the output resource file now
180 Res
.UseResFile(output
)
183 # Delete any existing 'PYC ' resource named __main__
186 res
= Res
.Get1NamedResource(RESTYPE
, RESNAME
)
191 # Create the raw data for the resource from the code object
193 progress
.label("Write PYC resource...")
196 data
= marshal
.dumps(code
)
198 data
= (MAGIC
+ '\0\0\0\0') + data
200 # Create the resource and write it
204 id = Res
.Unique1ID(RESTYPE
)
205 res
= Res
.Resource(data
)
206 res
.AddResource(RESTYPE
, id, RESNAME
)
208 res
.ReleaseResource()
210 # Close the output file
212 Res
.CloseResFile(output
)
214 # Now set the creator, type and bundle bit of the destination
215 dest_finfo
= dest_fss
.GetFInfo()
216 dest_finfo
.Creator
= ownertype
217 dest_finfo
.Type
= 'APPL'
218 dest_finfo
.Flags
= dest_finfo
.Flags | MACFS
.kHasBundle
219 dest_finfo
.Flags
= dest_finfo
.Flags
& ~MACFS
.kHasBeenInited
220 dest_fss
.SetFInfo(dest_finfo
)
222 macostools
.touched(dest_fss
)
224 progress
.label("Done.")
227 # Copy resources between two resource file descriptors.
228 # skip a resource named '__main__' or (if skipowner is set) 'Owner resource'.
229 # Also skip resources with a type listed in skiptypes.
231 def copyres(input, output
, skiptypes
, skipowner
, progress
=None):
234 Res
.UseResFile(input)
235 ntypes
= Res
.Count1Types()
236 progress_type_inc
= 50/ntypes
237 for itype
in range(1, 1+ntypes
):
238 type = Res
.Get1IndType(itype
)
239 if type in skiptypes
:
241 alltypes
.append(type)
242 nresources
= Res
.Count1Resources(type)
243 progress_cur_inc
= progress_type_inc
/nresources
244 for ires
in range(1, 1+nresources
):
245 res
= Res
.Get1IndResource(type, ires
)
246 id, type, name
= res
.GetResInfo()
247 lcname
= string
.lower(name
)
248 ## if (type, lcname) == (RESTYPE, RESNAME):
249 ## continue # Don't copy __main__ from template
250 # XXXX should look for id=0
251 if lcname
== OWNERNAME
:
253 continue # Skip this one
257 attrs
= res
.GetResAttrs()
258 if DEBUG
and progress
:
259 progress
.label("Copy %s %d %s"%(type, id, name
))
260 progress
.inc(progress_cur_inc
)
263 Res
.UseResFile(output
)
265 res2
= Res
.Get1Resource(type, id)
269 if DEBUG
and progress
:
270 progress
.label("Overwrite %s %d %s"%(type, id, name
))
271 res2
.RemoveResource()
272 res
.AddResource(type, id, name
)
274 attrs
= attrs | res
.GetResAttrs()
275 res
.SetResAttrs(attrs
)
276 Res
.UseResFile(input)
277 return alltypes
, ctor