/[escript]/trunk/scons/scons_extensions.py
ViewVC logotype

Contents of /trunk/scons/scons_extensions.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1240 - (show annotations)
Mon Aug 13 06:39:29 2007 UTC (12 years ago) by phornby
File MIME type: text/x-python
File size: 14430 byte(s)
query python_cmd in env to get the python command.
1
2
3 # Extensions to Scons
4
5 import py_compile
6 import sys
7 import os
8 import glob
9 import fnmatch
10 import types
11
12 from SCons.Script.SConscript import SConsEnvironment
13
14 ###############################################################################
15 def matchingFiles(env,directory,includes='*',excludes=None) :
16
17 # Pre-process for more convenient arguments
18
19 if isinstance(includes,str) :
20 includes = env.Split(includes)
21
22 if isinstance(excludes,str) :
23 excludes = env.Split(excludes)
24
25 def fn_filter(node):
26 fn = os.path.basename(str(node))
27 match = False
28 for include in includes:
29 if fnmatch.fnmatchcase( fn, include ):
30 match = True
31 break
32
33 if match and not excludes is None:
34 for exclude in excludes:
35 if fnmatch.fnmatchcase( fn, exclude ):
36 match = False
37 break
38
39 return match
40
41 def filter_nodes(where):
42 contents = glob.glob( os.path.join(str(where),"*") )
43 children = [ x for x in contents if fn_filter(x) ]
44 nodes = []
45 for f in children:
46 nodes.append(gen_node(f))
47 return nodes
48
49 def gen_node(n):
50 """Checks first to see if the node is a file or a dir, then
51 creates the appropriate node. [code seems redundant, if the node
52 is a node, then shouldn't it just be left as is?
53 """
54 if type(n) in (type(''), type(u'')):
55 path = n
56 else:
57 path = n.abspath
58
59 if os.path.isdir(path):
60 return env.Dir(n)
61
62 return env.File(n)
63
64 here = env.Dir(directory)
65 nodes = filter_nodes(here)
66
67 node_srcs = [n.srcnode() for n in nodes]
68
69 src = here.srcnode()
70 if src is not here:
71 for s in filter_nodes(src):
72 if s not in node_srcs:
73 # Probably need to check if this node is a directory
74 nodes.append(
75 gen_node(os.path.join(str(directory),
76 os.path.basename(str(s)))))
77
78 return nodes
79 #==============================================================================
80 SConsEnvironment.matchingFiles = matchingFiles
81 ###############################################################################
82
83
84
85 ###############################################################################
86 def InstallPyModule(env,target_dir,source,shlib=None,excludes=None) :
87
88 # put the .so/.dll over in <target_dir>
89 if shlib :
90 shtarg = env.Install(target_dir, shlib)
91
92 # Gather the python sources
93 python_src = env.matchingFiles(source, "*.py",excludes=excludes)
94
95 # Here is a hack to deal with the (possibly not yet generated)
96 # __init__.py. The problem is that the python_src list is built before
97 # __init__.py is updated from __init__.in. The AlwaysBuild call
98 # ensures that this does not cause a problem, except on the first
99 # build after a clean checkout, in which case there is no old
100 # __init__.py in src, and hence it does not make it into python_src!
101
102 init_input = env.matchingFiles(source, "__init__.in")
103 if init_input :
104 if python_src :
105 names = [x.name for x in python_src]
106 if "__init__.py" not in names :
107 python_src.append(env.File(os.path.join(str(source),
108 "__init__.py")))
109 else:
110 python_src = [env.File(os.path.join(str(source),"__init__.py"))]
111
112 # decide if we're doing py or pyc distribn and install.
113
114 if env['distrib_py_src'] :
115 pytarg = env.Install(target_dir, python_src)
116 else:
117 pyc = env.PyCompile(python_src)
118 pytarg = env.Install(target_dir, pyc)
119
120 if shlib :
121 targ_ret = env.Flatten([pytarg] + [shtarg])
122 else:
123 targ_ret = pytarg
124
125 return targ_ret
126 #==============================================================================
127 SConsEnvironment.InstallPyModule = InstallPyModule
128 ###############################################################################
129
130 ###############################################################################
131 def installDirectory(env,target,source,includes="*", excludes=None,
132 recursive=False):
133
134
135 if os.path.isfile(str(target)) :
136 raise UserError("target must be a directory")
137
138 if os.path.isfile(str(source)) :
139 raise UserError("source must be a directory")
140
141 source_files = env.matchingFiles(source,includes,excludes)
142
143 ret_targ = []
144
145 for f in source_files :
146 if f.isfile() :
147 targ = env.Install(target,f)
148 ret_targ.append(targ)
149
150 if f.isdir() and recursive :
151 x = os.path.basename(str(f))
152 t = env.Dir(os.path.join(str(target),x))
153 targ = env.installDirectory(t,f,includes,excludes,recursive)
154 ret_targ += targ
155
156 return ret_targ
157 #==============================================================================
158 SConsEnvironment.installDirectory = installDirectory
159 ###############################################################################
160
161 ###############################################################################
162 # Code to build .pyc from .py
163 def build_py(target, source, env):
164 py_compile.compile(str(source[0]), str(target[0]))
165 return 0
166
167 def doSubstitution(target,source,env) :
168 import product_info as PI
169 data = source[0].get_contents()
170 data = data.replace('$ProductName$',PI.PRODUCT_NAME)
171 data = data.replace('$LowerProductName$',PI.product_name)
172 data = data.replace('$ProductVersion$',PI.product_version)
173 data = data.replace('$VersionString$',PI.pkg_version_string)
174 data = data.replace('$SVNRevision$',PI.svn_revision)
175 open(str(target[0]),'w').write(data)
176 return 0
177
178 # Code to run unit_test executables
179 def runUnitTest(target, source, env):
180 app = str(source[0].abspath)
181
182 olddir = os.getcwd()
183 newdir = os.path.dirname(str(source[0]))
184 os.chdir(newdir)
185
186 if env.Execute(app) != 0:
187 os.chdir(olddir)
188 return 1
189
190 os.chdir(olddir)
191 open(str(target[0]),'w').write("PASSED\n")
192 return 0
193
194 def runPyUnitTest(target, source, env):
195 app = env['python_cmd'] + ' "' + str(source[0].abspath) + '"'
196
197 olddir = os.getcwd()
198 newdir = os.path.dirname(str(source[0]))
199 os.chdir(newdir)
200
201 if env.Execute(app) != 0:
202 os.chdir(olddir)
203 return 1
204
205 os.chdir(olddir)
206 open(str(target[0]),'w').write("PASSED\n")
207 return 0
208
209
210 def addBuilders(env) :
211 py_builder = env.Builder(action = build_py,
212 suffix = '.pyc',
213 src_suffix = '.py',
214 single_source=True)
215
216 env.Append(BUILDERS = {'PyCompile' : py_builder});
217
218 substituter = env.Builder(action = doSubstitution,
219 suffix = '',
220 src_suffix = '.in',
221 single_source=True )
222
223 env.Append(BUILDERS = {'VariableSubstitution' : substituter});
224
225 runUnitTest_builder = env.Builder(action = runUnitTest,
226 suffix = '.passed',
227 src_suffix=env.get('PROGSUFFIX',''),
228 single_source=True)
229
230 env.Append(BUILDERS = {'RunUnitTest' : runUnitTest_builder});
231
232 runPyUnitTest_builder = env.Builder(action = runPyUnitTest,
233 suffix = '.passed',
234 src_suffix='.py',
235 single_source=True)
236
237 env.Append(BUILDERS = {'RunPyUnitTest' : runPyUnitTest_builder});
238 return
239 #==============================================================================
240 SConsEnvironment.addBuilders = addBuilders
241 ###############################################################################
242
243 ###############################################################################
244 def epydocAction(target, source, env):
245
246 doc_dir = os.path.dirname(str(target[0].abspath))
247
248 cmd = [
249 [env['epydoc_path'], "-qqqq", "-o", doc_dir, str(source[0].tpath)]
250 ]
251 print 'executing epydoc...'
252 return env.Execute(cmd,"Build epydoc documentation")
253
254
255 def epydocDepend(env, target, source,
256 src_pattern="*.py",
257 file_names=['index.html','epydoc.css'],
258 subdirs=['private','public']) :
259 """
260 \brief add a dependency between the directory containing the doco and that
261 containing the source
262 \param target - the directory containing index.html for the doco,
263 and the private and public sub-directories.
264 \param source - the python module source directory
265 """
266 the_subdirs = [os.path.join(target.abspath,sub) for sub in subdirs]
267 the_targets = [os.path.join(target.abspath,file) for file in file_names]
268
269
270 ret_target = target
271
272 # if absolutely anything goes wrong, turn this on.
273 force_build = False
274
275 dst_time = 0
276 src_time = 1
277
278 try:
279
280 # have a shot at digging out all the source file times.
281 src_time = max(
282 [os.path.getmtime(str(x))
283 for x in env.matchingFiles(source,src_pattern) +
284 [source.abspath]]
285 )
286
287 # now try to find the target files and their mod time.
288 a = [os.path.getmtime(os.path.join(target.abspath,str(x)))
289 for x in file_names ]
290
291 for directory in the_subdirs :
292 # include the mod time of the directory
293 a += [os.path.getmtime(str(directory))]
294
295 # now go for the mod times of all files below the subdirs.
296 if os.path.isdir(str(directory)) :
297 a += [os.path.getmtime(str(x))
298 for x in env.matchingFiles(directory,"*")]
299
300 else:
301 # if it is not a directory, and we expected it to be
302 # do something nasty.
303 # we're in a try anyway.
304 force_build = True
305 os.unlink(directory)
306
307 dst_time = max(a)
308
309 except:
310 # Force an unlink and re-build.
311 force_build = True
312
313 if src_time > dst_time or force_build :
314 for x in the_targets :
315 try:
316 os.unlink(x)
317 except OSError:
318 pass
319
320 ret_target = env.Command(the_targets,source,epydocAction)
321
322
323 env.Clean(target, the_subdirs + file_names)
324
325 return ret_target
326 #==============================================================================
327 SConsEnvironment.epydocDepend = epydocDepend
328 ###############################################################################
329
330
331 ###############################################################################
332 def genSConscriptCalls(env,dir_list):
333
334 for d in dir_list :
335 print 'calling SConscript in "./%s"' %(d)
336 env.SConscript(dirs = [d],
337 build_dir='build/$PLATFORM/' + str(d),
338 duplicate=0)
339
340
341 return
342 #==============================================================================
343 SConsEnvironment.genSConscriptCalls = genSConscriptCalls
344 ###############################################################################
345
346
347 ###############################################################################
348 def print_all_nodes(env,dirnode, level=0):
349 """Print all the scons nodes that are children of this node, recursively."""
350 if type(dirnode)==type(''):
351 dirnode=env.Dir(dirnode)
352 dt = type(env.Dir('.'))
353 for f in dirnode.all_children():
354 if type(f) == dt:
355 print "%s%s: .............."%(level * ' ', str(f))
356 env.print_all_nodes(f, level+2)
357 print "%s%s"%(level * ' ', str(f))
358
359 #==============================================================================
360 SConsEnvironment.print_all_nodes = print_all_nodes
361 ###############################################################################
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383 ###############################################################################
384 def Glob(env,dir='.',includes="*",excludes=None, scan_dir=True):
385
386 """Similar to glob.glob, except globs SCons nodes, and thus sees
387 generated files and files from build directories. Basically, it sees
388 anything SCons knows about. A key subtlety is that since this function
389 operates on generated nodes as well as source nodes on the filesystem,
390 it needs to be called after builders that generate files you want to
391 include.
392
393 It will return both Dir entries and File entries
394 """
395
396 # Pre-process for more convenient arguments
397
398 if isinstance(includes,str) :
399 includes = env.Split(includes)
400
401 if isinstance(excludes,str) :
402 excludes = env.Split(excludes)
403
404 def fn_filter(node):
405 fn = os.path.basename(str(node))
406 match = 0
407 for include in includes:
408 if fnmatch.fnmatchcase( fn, include ):
409 match = 1
410 break
411
412 if match == 1 and not excludes is None:
413 for exclude in excludes:
414 if fnmatch.fnmatchcase( fn, exclude ):
415 match = 0
416 break
417
418 return match
419
420 def filter_nodes(where):
421 contents = where.all_children(scan=scan_dir)
422 children = [ x for x in contents if fn_filter(x) ]
423 nodes = []
424 for f in children:
425 nodes.append(gen_node(f))
426 return nodes
427
428 def gen_node(n):
429 """Checks first to see if the node is a file or a dir, then
430 creates the appropriate node. [code seems redundant, if the node
431 is a node, then shouldn't it just be left as is?
432 """
433 if type(n) in (type(''), type(u'')):
434 path = n
435 else:
436 path = n.abspath
437 if os.path.isdir(path):
438 return env.Dir(n)
439 else:
440 return env.File(n)
441
442 here = env.Dir(dir)
443 nodes = filter_nodes(here)
444
445 node_srcs = [n.srcnode() for n in nodes]
446
447 src = here.srcnode()
448 if src is not here:
449 for s in filter_nodes(src):
450 if s not in node_srcs:
451 # Probably need to check if this node is a directory
452 nodes.append(
453 gen_node(os.path.join(dir,os.path.basename(str(s)))))
454
455 return nodes

  ViewVC Help
Powered by ViewVC 1.1.26