/[escript]/branches/domexper/scons/scons_extensions.py
ViewVC logotype

Contents of /branches/domexper/scons/scons_extensions.py

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26