3 Various utility functions go here.
8 # Copyright (c) 2001, 2002 Steven Knight
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:
18 # The above copyright notice and this permission notice shall be included
19 # in all copies or substantial portions of the Software.
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.
30 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
42 from UserString import UserString
50 def scons_str2nodes(arg, node_factory=SCons.Node.FS.default_fs.File):
51 """This function converts a string or list into a list of Node instances.
52 It follows the rules outlined in the SCons design document by accepting
53 any of the following inputs:
54 - A single string containing names separated by spaces. These will be
55 split apart at the spaces.
56 - A single Node instance,
57 - A list containingg either strings or Node instances. Any strings
58 in the list are not split at spaces.
59 In all cases, the function returns a list of Node instances."""
63 narg = string.split(arg)
64 elif not is_List(arg):
70 nodes.append(node_factory(v))
71 # Do we enforce the following restriction? Maybe, but it
72 # also restricts what we can do for allowing people to
73 # use the engine with alternate Node implementations...
74 # Perhaps this should be split in two, with the SCons.Node
75 # logic in a wrapper somewhere under SCons.Node, and the
76 # string-parsing logic here...?
77 #elif not issubclass(v.__class__, SCons.Node.Node):
85 class PathList(UserList.UserList):
86 """This class emulates the behavior of a list, but also implements
87 the special "path dissection" attributes we can use to find
88 suffixes, base names, etc. of the paths in the list.
90 One other special attribute of this class is that, by
91 overriding the __str__ and __repr__ methods, this class
92 represents itself as a space-concatenated string of
93 the list elements, as in:
95 >>> pl=PathList(["/foo/bar.txt", "/baz/foo.txt"])
97 '/foo/bar.txt /baz/foo.txt'
101 def __init__(self, seq = []):
102 UserList.UserList.__init__(self, seq)
104 def __getattr__(self, name):
105 # This is how we implement the "special" attributes
106 # such as base, suffix, basepath, etc.
108 return self.dictSpecialAttrs[name](self)
110 raise AttributeError, 'PathList has no attribute: %s' % name
112 def __splitPath(self, split_func=os.path.split):
113 """This method calls the supplied split_func on each element
114 in the contained list. We expect split_func to return a
115 2-tuple, usually representing two elements of a split file path,
116 such as those returned by os.path.split().
118 We return a 2-tuple of lists, each equal in length to the contained
119 list. The first list represents all the elements from the
120 first part of the split operation, the second represents
121 all elements from the second part."""
124 for strPath in self.data:
125 first_part, second_part = split_func(strPath)
126 list1.append(first_part)
127 list2.append(second_part)
128 return (self.__class__(list1),
129 self.__class__(list2))
131 def __getBasePath(self):
132 """Return the file's directory and file name, with the
134 return self.__splitPath(os.path.splitext)[0]
136 def __getSuffix(self):
137 """Return the file's suffix."""
138 return self.__splitPath(os.path.splitext)[1]
140 def __getFileName(self):
141 """Return the file's name without the path."""
142 return self.__splitPath()[1]
145 """Return the file's path."""
146 return self.__splitPath()[0]
149 """Return the file name with path and suffix stripped."""
150 return self.__getFileName().__splitPath(os.path.splitext)[0]
152 dictSpecialAttrs = { "file" : __getFileName,
153 "base" : __getBasePath,
154 "filebase" : __getBase,
156 "suffix" : __getSuffix }
159 return string.join(self.data)
162 return repr(string.join(self.data))
164 def __getitem__(self, item):
165 # We must do this to ensure that single items returned
166 # by index access have the special attributes such as
167 # suffix and basepath.
168 return self.__class__([ UserList.UserList.__getitem__(self, item), ])
170 _cv = re.compile(r'\$([_a-zA-Z]\w*|{[^}]*})')
171 _space_sep = re.compile(r'[\t ]+(?![^{]*})')
173 def scons_subst_list(strSubst, globals, locals, remove=None):
175 This function is similar to scons_subst(), but with
176 one important difference. Instead of returning a single
177 string, this function returns a list of lists.
178 The first (outer) list is a list of lines, where the
179 substituted stirng has been broken along newline characters.
180 The inner lists are lists of command line arguments, i.e.,
181 the argv array that should be passed to a spawn or exec
184 One important thing this guy does is preserve environment
185 variables that are lists. For instance, if you have
186 an environment variable that is a Python list (or UserList-
187 derived class) that contains path names with spaces in them,
188 then the entire path will be returned as a single argument.
189 This is the only way to know where the 'split' between arguments
190 is for executing a command line."""
192 def repl(m, globals=globals, locals=locals):
194 if key[:1] == '{' and key[-1:] == '}':
197 e = eval(key, globals, locals)
201 s = string.join(map(str, e), '\0')
203 s = _space_sep.sub('\0', str(e))
209 # Tokenize the original string...
210 strSubst = _space_sep.sub('\0', str(strSubst))
212 # Now, do the substitution
214 strSubst, n = _cv.subn(repl, strSubst)
215 # Now parse the whole list into tokens.
216 listLines = string.split(strSubst, '\n')
218 listLines = map(lambda x,re=remove: re.sub('', x), listLines)
219 return map(lambda x: filter(lambda y: y, string.split(x, '\0')),
222 def scons_subst(strSubst, globals, locals, remove=None):
223 """Recursively interpolates dictionary variables into
224 the specified string, returning the expanded result.
225 Variables are specified by a $ prefix in the string and
226 begin with an initial underscore or alphabetic character
227 followed by any number of underscores or alphanumeric
228 characters. The construction variable names may be
229 surrounded by curly braces to separate the name from
232 cmd_list = scons_subst_list(strSubst, globals, locals, remove)
233 return string.join(map(string.join, cmd_list), '\n')
235 class VarInterpolator:
236 def __init__(self, dest, src, prefix, suffix):
242 def prepareSrc(self, dict):
245 src = string.split(src)
246 elif not is_List(src):
249 def prepare(x, dict=dict):
250 if isinstance(x, SCons.Node.Node):
253 return scons_subst(x, {}, dict)
255 return map(prepare, src)
257 def generate(self, dict):
258 if not dict.has_key(self.src):
262 src = filter(lambda x: not x is None, self.prepareSrc(dict))
269 prefix = str(dict[self.prefix])
274 suffix = str(dict[self.suffix])
278 def autogenFunc(x, suff=suffix, pref=prefix):
279 """Generate the interpolated variable. If the prefix
280 ends in a space, or the suffix begins in a space,
281 leave it as a separate element of the list."""
283 if pref and pref[-1] == ' ':
284 ret.insert(0, pref[:-1])
286 ret[0] = pref + ret[0]
287 if suff and suff[0] == ' ':
290 ret[-1] = ret[-1] + suff
292 dict[self.dest] = reduce(lambda x, y: x+y,
296 def instance(self, dir, fs):
299 class DirVarInterp(VarInterpolator):
300 def __init__(self, dest, src, prefix, suffix):
301 VarInterpolator.__init__(self, dest, src, prefix, suffix)
304 self.dictInstCache = {}
306 def prepareSrc(self, dict):
307 src = VarInterpolator.prepareSrc(self, dict)
309 def prepare(x, self=self):
310 if isinstance(x, SCons.Node.Node):
313 return self.fs.Dir(str(x), directory=self.dir)
317 return map(prepare, src)
319 def instance(self, dir, fs):
321 ret = self.dictInstCache[(dir, fs)]
323 ret = copy.copy(self)
326 self.dictInstCache[(dir, fs)] = ret
329 def generate(self, dict):
330 VarInterpolator.generate(self, dict)
332 dict[self.dest] = ['$('] + dict[self.dest] + ['$)']
334 AUTO_GEN_VARS = ( VarInterpolator('_LIBFLAGS',
338 DirVarInterp('_LIBDIRFLAGS',
342 DirVarInterp('_INCFLAGS',
347 def autogenerate(dict, fs = SCons.Node.FS.default_fs, dir = None):
348 """Autogenerate the "interpolated" environment variables.
349 We read a static structure that tells us how. AUTO_GEN_VARS
350 is a tuple of tuples. Each inner tuple has four elements,
351 each strings referring to an environment variable, and describing
352 how to autogenerate a particular variable. The elements are:
354 0 - The variable to generate
355 1 - The "source" variable, usually a list
356 2 - The "prefix" variable
357 3 - The "suffix" variable
359 The autogenerated variable is a list, consisting of every
360 element of the source list, or a single element if the source
361 is a string, with the prefix and suffix
364 for interp in AUTO_GEN_VARS:
365 interp.instance(dir, fs).generate(dict)
367 def render_tree(root, child_func, margin=[0], visited={}):
369 Render a tree of nodes into an ASCII tree view.
370 root - the root node of the tree
371 child_func - the function called to get the children of a node
372 margin - the format of the left margin to use for children of root.
373 1 results in a pipe, and 0 results in no pipe.
374 visited - a dictionart of visited nodes in the current branch
377 if visited.has_key(root):
380 children = child_func(root)
382 for pipe in margin[:-1]:
384 retval = retval + "| "
386 retval = retval + " "
388 retval = retval + "+-" + str(root) + "\n"
389 visited = copy.copy(visited)
392 for i in range(len(children)):
393 margin.append(i<len(children)-1)
394 retval = retval + render_tree(children[i], child_func, margin, visited
401 return type(e) is types.DictType or isinstance(e, UserDict.UserDict)
404 return type(e) is types.ListType or isinstance(e, UserList.UserList)
406 if hasattr(types, 'UnicodeType'):
408 return type(e) is types.StringType \
409 or type(e) is types.UnicodeType \
410 or isinstance(e, UserString)
413 return type(e) is types.StringType or isinstance(e, UserString)
415 # attempt to load the windows registry module:
423 RegOpenKeyEx = _winreg.OpenKeyEx
424 RegEnumKey = _winreg.EnumKey
425 RegEnumValue = _winreg.EnumValue
426 RegQueryValueEx = _winreg.QueryValueEx
427 RegError = _winreg.error
436 RegOpenKeyEx = win32api.RegOpenKeyEx
437 RegEnumKey = win32api.RegEnumKey
438 RegEnumValue = win32api.RegEnumValue
439 RegQueryValueEx = win32api.RegQueryValueEx
440 RegError = win32api.error
446 HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT
447 HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE
448 HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER
449 HKEY_USERS = hkey_mod.HKEY_USERS