Lumiera  0.pre.03
»edit your freedom«
Buildhelper.py
1 # -*- python -*-
2 
5 
6 # Copyright (C) Lumiera.org
7 # 2008, Hermann Vosseler <Ichthyostega@web.de>
8 #
9 # This program is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU General Public License as
11 # published by the Free Software Foundation; either version 2 of
12 # the License, or (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with this program; if not, write to the Free Software
21 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 
23 
24 import os
25 import sys
26 import glob
27 import fnmatch
28 
29 from SCons import Util
30 
31 
32 
33 #
34 # Common Helper Functions
35 #
36 def isCleanupOperation(env):
37  return env.GetOption('clean')
38 
39 def isHelpRequest():
40  """ this is a hack: SCons does all configure tests even if only
41  the help message is requested. SCons doesn't export the
42  help option for retrieval by env.GetOption(),
43  so we scan the commandline directly.
44  """
45  return '-h' in sys.argv or '--help' in sys.argv
46 
47 
48 
49 def srcSubtree(tree, **args):
50  """ convenience wrapper: scan the given subtree, which is relative
51  to the current SConscript, and find all source files.
52  """
53  return list(scanSubtree(tree, **args))
54 
55 
56 
57 SRCPATTERNS = ['*.c','*.cpp','*.cc']
58 
59 def scanSubtree(roots, patterns=SRCPATTERNS):
60  """ first expand (possible) wildcards and filter out non-dirs.
61  Then scan the given subtree for source filenames
62  (python generator function)
63  """
64  for root in globRootdirs(roots):
65  for (d,_,files) in os.walk(root):
66  d = stripPrefix(d, './')
67  for p in patterns:
68  for f in fnmatch.filter(files, p):
69  yield os.path.join(d,f)
70 
71 
72 
73 def globRootdirs(roots):
74  """ helper: expand shell wildcards and filter the resulting list,
75  so that it only contains existing directories
76  """
77  isDirectory = lambda f: os.path.isdir(f) and os.path.exists(f)
78  roots = glob.glob(roots)
79  return (d for d in roots if isDirectory(d) )
80 
81 
82 
83 def findSrcTrees(location, patterns=SRCPATTERNS):
84  """ find possible source tree roots, starting with the given location.
85  When delving down from the initial location(s), a source tree is defined
86  as a directory containing source files and possibly further sub directories.
87  After having initially expanded the given location with #globRootdirs, each
88  directory is examined depth first, until encountering a directory containing
89  source files, which then yields a result. Especially, this can be used to traverse
90  an organisational directory structure and find out all possible source trees
91  to be built into packages, plugins, individual tool executables etc.
92  @return: the relative path names of all source root dirs found (generator function).
93  """
94  for directory in globRootdirs(location):
95  if isSrcDir (directory,patterns):
96  yield directory
97  else:
98  for result in findSrcTrees (str(directory)+'/*'):
99  yield result
100 
101 
102 def isSrcDir(path, patterns=SRCPATTERNS):
103  """ helper: investigate the given (relative) path
104  @param patterns: list of wildcards to define what counts as "source file"
105  @return: True if it's a directory containing any source file
106  """
107  if not os.path.isdir(path):
108  return False
109  else:
110  for p in patterns:
111  if glob.glob(path+'/'+p):
112  return True
113 
114 
115 
116 def filterNodes(nlist, removeName=None):
117  """ filter out scons build nodes using the given criteria.
118  removeName: if set, remove all nodes with this srcname
119  """
120  if removeName:
121  predicate = lambda n : not fnmatch.fnmatch(os.path.basename(str(n[0])), removeName)
122  else:
123  predicate = lambda n : True
124 
125  return filter(predicate, nlist)
126 
127 
128 
129 def getDirname (d, basePrefix=None):
130  """ extract directory name without leading path,
131  or without the explicitly given basePrefix
132  """
133  d = os.path.realpath(d)
134  if not os.path.isdir(d):
135  d,_ = os.path.split(d)
136  if basePrefix:
137  basePrefix = os.path.realpath(basePrefix)
138  name = stripPrefix(str(d), basePrefix)
139  else:
140  _, name = os.path.split(d)
141  return name
142 
143 
144 
145 def stripPrefix(path, prefix):
146  if path.startswith(prefix):
147  path = path[len(prefix):]
148  return path
149 
150 
151 
152 def createPlugins(env, directory, **kw):
153  """ investigate the given source directory to identify all contained source trees.
154  @return: a list of build nodes defining a plugin for each of these source trees.
155  """
156  return [env.LumieraPlugin( getDirname(tree)
157  , srcSubtree(tree)
158  , **kw
159  )
160  for tree in findSrcTrees(directory)
161  ]
162 
163 
164 
165 def checkCommandOption(env, optID, val=None, cmdName=None):
166  """ evaluate and verify an option, which may point at a command.
167  besides specifying a path, the option may read True, yes or 1,
168  denoting that the system default for this command should be used.
169  @return: True, if the key has been expanded and validated,
170  False, if this failed and the key was removed
171  """
172  if not val:
173  if not env.get(optID): return False
174  else:
175  val = env.get(optID)
176 
177  if val=='True' or val=='true' or val=='yes' or val=='1' or val == 1 :
178  if not cmdName:
179  print "WARNING: no default for %s, please specify a full path." % optID
180  del env[optID]
181  return False
182  else:
183  val = env.WhereIs(cmdName)
184  if not val:
185  print "WARNING: %s not found, please specify a full path" % cmdName
186  del env[optID]
187  return False
188 
189  if not os.path.isfile(val):
190  val = env.WhereIs(val)
191 
192  if val and os.path.isfile(val):
193  env[optID] = val
194  return True
195  else:
196  del env[optID]
197  return False
198 
199 
200 
201 
202 class Record(dict):
203  """ a set of properties with record style access.
204  Record is a dictionary, but the elements can be accessed
205  conveniently as if they where object fields
206  """
207  def __init__(self, defaults=None, **props):
208  if defaults:
209  defaults.update(props)
210  props = defaults
211  dict.__init__(self,props)
212 
213  def __getattr__(self,key):
214  if key=='__get__' or key=='__set__':
215  raise AttributeError
216  return self.setdefault(key)
217 
218  def __setattr__(self,key,val):
219  self[key] = val
220 
221 
222 def extract_localPathDefs (localDefs):
223  """ extracts the directory configuration values.
224  For sake of simplicity, paths and directories are defined
225  immediately as global variables in the SConstruct. This helper
226  extracts from the given dict the variables matching some magical
227  pattern and returns them wrapped into a Record for convenient access
228  """
229  def relevantPathDefs (mapping):
230  for (k,v) in mapping.items():
231  if (k.startswith('src') or k.startswith('build') or k.startswith('install')) and Util.is_String(v):
232  v = v.strip()
233  if not v.endswith('/'): v += '/'
234  yield (k,v)
235 
236  return dict(relevantPathDefs(localDefs))
bool filter(Placement< DummyMO > const &candidate)
a filter predicate to pick some objects from a resultset.