/[escript]/trunk/site_scons/site_init.py
ViewVC logotype

Diff of /trunk/site_scons/site_init.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

trunk/scons/scons_extensions.py revision 1133 by gross, Tue May 8 07:19:33 2007 UTC temp_trunk_copy/scons/scons_extensions.py revision 1384 by phornby, Fri Jan 11 02:29:38 2008 UTC
# Line 1  Line 1 
1    
 #          Copyright 2006 by ACcESS MNRF                    
 #                                                            
 #              http://www.access.edu.au                      
 #       Primary Business: Queensland, Australia              
 #  Licensed under the Open Software License version 3.0      
 #     http://www.opensource.org/licenses/osl-3.0.php        
 #                                                            
   
2    
3  # Extensions to Scons  # Extensions to Scons
4    
# Line 14  import py_compile Line 6  import py_compile
6  import sys  import sys
7  import os  import os
8  import time  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  # Code to build .pyc from .py
164  def build_py(target, source, env):  def build_py(target, source, env):
165    py_compile.compile(str(source[0]), str(target[0]))      py_compile.compile(str(source[0]), str(target[0]))
166    return None      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  # Code to run unit_test executables
180  def runUnitTest(target, source, env):  def runUnitTest(target, source, env):
181    time_start = time.time()    time_start = time.time()
   print "Executing test: " + str(source[0].abspath)  
182    app = str(source[0].abspath)    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):    if not env.Execute(app):
186      open(str(target[0]),'w').write("PASSED\n")      open(str(target[0]),'w').write("PASSED\n")
187    else:    else:
# Line 34  def runUnitTest(target, source, env): Line 191  def runUnitTest(target, source, env):
191    
192  def runPyUnitTest(target, source, env):  def runPyUnitTest(target, source, env):
193     time_start = time.time()     time_start = time.time()
194     print "Executing test: " + str(source[0].abspath)     app = str(source[0].abspath)
195     app = 'python '+'"'+str(source[0].abspath)+'"'     if env['useMPI']:
196     if not env.Execute(app):       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")        open(str(target[0]),'w').write("PASSED\n")
202     else:     else:
203       return 1       return 1
204     print "Test execution time: ", round(time.time() - time_start, 1), " seconds wall time for " + str(source[0].abspath)     print "Test execution time: ", round(time.time() - time_start, 1), " seconds wall time for " + str(source[0].abspath)
205     return None     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

Legend:
Removed from v.1133  
changed lines
  Added in v.1384

  ViewVC Help
Powered by ViewVC 1.1.26