Package SCons :: Module Subst
[hide private]
[frames] | no frames]

Source Code for Module SCons.Subst

  1  """SCons.Subst 
  2   
  3  SCons string substitution. 
  4   
  5  """ 
  6   
  7  # 
  8  # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation 
  9  # 
 10  # Permission is hereby granted, free of charge, to any person obtaining 
 11  # a copy of this software and associated documentation files (the 
 12  # "Software"), to deal in the Software without restriction, including 
 13  # without limitation the rights to use, copy, modify, merge, publish, 
 14  # distribute, sublicense, and/or sell copies of the Software, and to 
 15  # permit persons to whom the Software is furnished to do so, subject to 
 16  # the following conditions: 
 17  # 
 18  # The above copyright notice and this permission notice shall be included 
 19  # in all copies or substantial portions of the Software. 
 20  # 
 21  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 
 22  # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
 23  # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 24  # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
 25  # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
 26  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
 27  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
 28  # 
 29   
 30  __revision__ = "src/engine/SCons/Subst.py 3795 2008/11/25 22:04:43 scons" 
 31   
 32  import re 
 33  import string 
 34  import types 
 35  import UserList 
 36  import UserString 
 37   
 38  import SCons.Errors 
 39   
 40  from SCons.Util import is_String, is_Sequence 
 41   
 42  # Indexed by the SUBST_* constants below. 
 43  _strconv = [SCons.Util.to_String_for_subst, 
 44              SCons.Util.to_String_for_subst, 
 45              SCons.Util.to_String_for_signature] 
 46   
 47   
 48   
 49  AllowableExceptions = (IndexError, NameError) 
 50   
51 -def SetAllowableExceptions(*excepts):
52 global AllowableExceptions 53 AllowableExceptions = filter(None, excepts)
54
55 -def raise_exception(exception, target, s):
56 name = exception.__class__.__name__ 57 msg = "%s `%s' trying to evaluate `%s'" % (name, exception, s) 58 if target: 59 raise SCons.Errors.BuildError, (target[0], msg) 60 else: 61 raise SCons.Errors.UserError, msg
62 63 64
65 -class Literal:
66 """A wrapper for a string. If you use this object wrapped 67 around a string, then it will be interpreted as literal. 68 When passed to the command interpreter, all special 69 characters will be escaped."""
70 - def __init__(self, lstr):
71 self.lstr = lstr
72
73 - def __str__(self):
74 return self.lstr
75
76 - def escape(self, escape_func):
77 return escape_func(self.lstr)
78
79 - def for_signature(self):
80 return self.lstr
81
82 - def is_literal(self):
83 return 1
84
85 -class SpecialAttrWrapper:
86 """This is a wrapper for what we call a 'Node special attribute.' 87 This is any of the attributes of a Node that we can reference from 88 Environment variable substitution, such as $TARGET.abspath or 89 $SOURCES[1].filebase. We implement the same methods as Literal 90 so we can handle special characters, plus a for_signature method, 91 such that we can return some canonical string during signature 92 calculation to avoid unnecessary rebuilds.""" 93
94 - def __init__(self, lstr, for_signature=None):
95 """The for_signature parameter, if supplied, will be the 96 canonical string we return from for_signature(). Else 97 we will simply return lstr.""" 98 self.lstr = lstr 99 if for_signature: 100 self.forsig = for_signature 101 else: 102 self.forsig = lstr
103
104 - def __str__(self):
105 return self.lstr
106
107 - def escape(self, escape_func):
108 return escape_func(self.lstr)
109
110 - def for_signature(self):
111 return self.forsig
112
113 - def is_literal(self):
114 return 1
115
116 -def quote_spaces(arg):
117 """Generic function for putting double quotes around any string that 118 has white space in it.""" 119 if ' ' in arg or '\t' in arg: 120 return '"%s"' % arg 121 else: 122 return str(arg)
123
124 -class CmdStringHolder(UserString.UserString):
125 """This is a special class used to hold strings generated by 126 scons_subst() and scons_subst_list(). It defines a special method 127 escape(). When passed a function with an escape algorithm for a 128 particular platform, it will return the contained string with the 129 proper escape sequences inserted. 130 """
131 - def __init__(self, cmd, literal=None):
132 UserString.UserString.__init__(self, cmd) 133 self.literal = literal
134
135 - def is_literal(self):
136 return self.literal
137
138 - def escape(self, escape_func, quote_func=quote_spaces):
139 """Escape the string with the supplied function. The 140 function is expected to take an arbitrary string, then 141 return it with all special characters escaped and ready 142 for passing to the command interpreter. 143 144 After calling this function, the next call to str() will 145 return the escaped string. 146 """ 147 148 if self.is_literal(): 149 return escape_func(self.data) 150 elif ' ' in self.data or '\t' in self.data: 151 return quote_func(self.data) 152 else: 153 return self.data
154
155 -def escape_list(list, escape_func):
156 """Escape a list of arguments by running the specified escape_func 157 on every object in the list that has an escape() method.""" 158 def escape(obj, escape_func=escape_func): 159 try: 160 e = obj.escape 161 except AttributeError: 162 return obj 163 else: 164 return e(escape_func)
165 return map(escape, list) 166
167 -class NLWrapper:
168 """A wrapper class that delays turning a list of sources or targets 169 into a NodeList until it's needed. The specified function supplied 170 when the object is initialized is responsible for turning raw nodes 171 into proxies that implement the special attributes like .abspath, 172 .source, etc. This way, we avoid creating those proxies just 173 "in case" someone is going to use $TARGET or the like, and only 174 go through the trouble if we really have to. 175 176 In practice, this might be a wash performance-wise, but it's a little 177 cleaner conceptually... 178 """ 179
180 - def __init__(self, list, func):
181 self.list = list 182 self.func = func
183 - def _return_nodelist(self):
184 return self.nodelist
185 - def _gen_nodelist(self):
186 list = self.list 187 if list is None: 188 list = [] 189 elif not is_Sequence(list): 190 list = [list] 191 # The map(self.func) call is what actually turns 192 # a list into appropriate proxies. 193 self.nodelist = SCons.Util.NodeList(map(self.func, list)) 194 self._create_nodelist = self._return_nodelist 195 return self.nodelist
196 _create_nodelist = _gen_nodelist
197 198
199 -class Targets_or_Sources(UserList.UserList):
200 """A class that implements $TARGETS or $SOURCES expansions by in turn 201 wrapping a NLWrapper. This class handles the different methods used 202 to access the list, calling the NLWrapper to create proxies on demand. 203 204 Note that we subclass UserList.UserList purely so that the 205 is_Sequence() function will identify an object of this class as 206 a list during variable expansion. We're not really using any 207 UserList.UserList methods in practice. 208 """
209 - def __init__(self, nl):
210 self.nl = nl
211 - def __getattr__(self, attr):
212 nl = self.nl._create_nodelist() 213 return getattr(nl, attr)
214 - def __getitem__(self, i):
215 nl = self.nl._create_nodelist() 216 return nl[i]
217 - def __getslice__(self, i, j):
218 nl = self.nl._create_nodelist() 219 i = max(i, 0); j = max(j, 0) 220 return nl[i:j]
221 - def __str__(self):
222 nl = self.nl._create_nodelist() 223 return str(nl)
224 - def __repr__(self):
225 nl = self.nl._create_nodelist() 226 return repr(nl)
227
228 -class Target_or_Source:
229 """A class that implements $TARGET or $SOURCE expansions by in turn 230 wrapping a NLWrapper. This class handles the different methods used 231 to access an individual proxy Node, calling the NLWrapper to create 232 a proxy on demand. 233 """
234 - def __init__(self, nl):
235 self.nl = nl
236 - def __getattr__(self, attr):
237 nl = self.nl._create_nodelist() 238 try: 239 nl0 = nl[0] 240 except IndexError: 241 # If there is nothing in the list, then we have no attributes to 242 # pass through, so raise AttributeError for everything. 243 raise AttributeError, "NodeList has no attribute: %s" % attr 244 return getattr(nl0, attr)
245 - def __str__(self):
246 nl = self.nl._create_nodelist() 247 if nl: 248 return str(nl[0]) 249 return ''
250 - def __repr__(self):
251 nl = self.nl._create_nodelist() 252 if nl: 253 return repr(nl[0]) 254 return ''
255
256 -def subst_dict(target, source):
257 """Create a dictionary for substitution of special 258 construction variables. 259 260 This translates the following special arguments: 261 262 target - the target (object or array of objects), 263 used to generate the TARGET and TARGETS 264 construction variables 265 266 source - the source (object or array of objects), 267 used to generate the SOURCES and SOURCE 268 construction variables 269 """ 270 dict = {} 271 272 if target: 273 def get_tgt_subst_proxy(thing): 274 try: 275 subst_proxy = thing.get_subst_proxy() 276 except AttributeError: 277 subst_proxy = thing # probably a string, just return it 278 return subst_proxy
279 tnl = NLWrapper(target, get_tgt_subst_proxy) 280 dict['TARGETS'] = Targets_or_Sources(tnl) 281 dict['TARGET'] = Target_or_Source(tnl) 282 else: 283 dict['TARGETS'] = None 284 dict['TARGET'] = None 285 286 if source: 287 def get_src_subst_proxy(node): 288 try: 289 rfile = node.rfile 290 except AttributeError: 291 pass 292 else: 293 node = rfile() 294 try: 295 return node.get_subst_proxy() 296 except AttributeError: 297 return node # probably a String, just return it 298 snl = NLWrapper(source, get_src_subst_proxy) 299 dict['SOURCES'] = Targets_or_Sources(snl) 300 dict['SOURCE'] = Target_or_Source(snl) 301 else: 302 dict['SOURCES'] = None 303 dict['SOURCE'] = None 304 305 return dict 306 307 # Constants for the "mode" parameter to scons_subst_list() and 308 # scons_subst(). SUBST_RAW gives the raw command line. SUBST_CMD 309 # gives a command line suitable for passing to a shell. SUBST_SIG 310 # gives a command line appropriate for calculating the signature 311 # of a command line...if this changes, we should rebuild. 312 SUBST_CMD = 0 313 SUBST_RAW = 1 314 SUBST_SIG = 2 315 316 _rm = re.compile(r'\$[()]') 317 _remove = re.compile(r'\$\([^\$]*(\$[^\)][^\$]*)*\$\)') 318 319 # Indexed by the SUBST_* constants above. 320 _regex_remove = [ _rm, None, _remove ] 321
322 -def _rm_list(list):
323 #return [ l for l in list if not l in ('$(', '$)') ] 324 return filter(lambda l: not l in ('$(', '$)'), list)
325
326 -def _remove_list(list):
327 result = [] 328 do_append = result.append 329 for l in list: 330 if l == '$(': 331 do_append = lambda x: None 332 elif l == '$)': 333 do_append = result.append 334 else: 335 do_append(l) 336 return result
337 338 # Indexed by the SUBST_* constants above. 339 _list_remove = [ _rm_list, None, _remove_list ] 340 341 # Regular expressions for splitting strings and handling substitutions, 342 # for use by the scons_subst() and scons_subst_list() functions: 343 # 344 # The first expression compiled matches all of the $-introduced tokens 345 # that we need to process in some way, and is used for substitutions. 346 # The expressions it matches are: 347 # 348 # "$$" 349 # "$(" 350 # "$)" 351 # "$variable" [must begin with alphabetic or underscore] 352 # "${any stuff}" 353 # 354 # The second expression compiled is used for splitting strings into tokens 355 # to be processed, and it matches all of the tokens listed above, plus 356 # the following that affect how arguments do or don't get joined together: 357 # 358 # " " [white space] 359 # "non-white-space" [without any dollar signs] 360 # "$" [single dollar sign] 361 # 362 _dollar_exps_str = r'\$[\$\(\)]|\$[_a-zA-Z][\.\w]*|\${[^}]*}' 363 _dollar_exps = re.compile(r'(%s)' % _dollar_exps_str) 364 _separate_args = re.compile(r'(%s|\s+|[^\s\$]+|\$)' % _dollar_exps_str) 365 366 # This regular expression is used to replace strings of multiple white 367 # space characters in the string result from the scons_subst() function.