1 """SCons.Subst
2
3 SCons string substitution.
4
5 """
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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
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
54
62
63
64
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."""
72
75
76 - def escape(self, escape_func):
77 return escape_func(self.lstr)
78
81
84
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
106
107 - def escape(self, escape_func):
108 return escape_func(self.lstr)
109
112
115
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
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 """
134
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
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
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
181 self.list = list
182 self.func = func
186 list = self.list
187 if list is None:
188 list = []
189 elif not is_Sequence(list):
190 list = [list]
191
192
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
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 """
212 nl = self.nl._create_nodelist()
213 return getattr(nl, attr)
215 nl = self.nl._create_nodelist()
216 return nl[i]
218 nl = self.nl._create_nodelist()
219 i = max(i, 0); j = max(j, 0)
220 return nl[i:j]
222 nl = self.nl._create_nodelist()
223 return str(nl)
225 nl = self.nl._create_nodelist()
226 return repr(nl)
227
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 """
237 nl = self.nl._create_nodelist()
238 try:
239 nl0 = nl[0]
240 except IndexError:
241
242
243 raise AttributeError, "NodeList has no attribute: %s" % attr
244 return getattr(nl0, attr)
246 nl = self.nl._create_nodelist()
247 if nl:
248 return str(nl[0])
249 return ''
251 nl = self.nl._create_nodelist()
252 if nl:
253 return repr(nl[0])
254 return ''
255
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
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
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
308
309
310
311
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
320 _regex_remove = [ _rm, None, _remove ]
321
323
324 return filter(lambda l: not l in ('$(', '$)'), list)
325
337
338
339 _list_remove = [ _rm_list, None, _remove_list ]
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
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
367