3 Various utility functions go here.
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 UserDict import UserDict
43 from UserList import UserList
45 # Don't "from types import ..." these because we need to get at the
46 # types module later to look for UnicodeType.
47 DictType = types.DictType
48 InstanceType = types.InstanceType
49 ListType = types.ListType
50 StringType = types.StringType
51 TupleType = types.TupleType
54 from UserString import UserString
56 # "Borrowed" from the Python 2.2 UserString module
57 # and modified slightly for use with SCons.
59 def __init__(self, seq):
62 elif isinstance(seq, UserString):
63 self.data = seq.data[:]
66 def __str__(self): return str(self.data)
67 def __repr__(self): return repr(self.data)
68 def __int__(self): return int(self.data)
69 def __long__(self): return long(self.data)
70 def __float__(self): return float(self.data)
71 def __complex__(self): return complex(self.data)
72 def __hash__(self): return hash(self.data)
74 def __cmp__(self, string):
75 if isinstance(string, UserString):
76 return cmp(self.data, string.data)
78 return cmp(self.data, string)
79 def __contains__(self, char):
80 return char in self.data
82 def __len__(self): return len(self.data)
83 def __getitem__(self, index): return self.__class__(self.data[index])
84 def __getslice__(self, start, end):
85 start = max(start, 0); end = max(end, 0)
86 return self.__class__(self.data[start:end])
88 def __add__(self, other):
89 if isinstance(other, UserString):
90 return self.__class__(self.data + other.data)
91 elif is_String(other):
92 return self.__class__(self.data + other)
94 return self.__class__(self.data + str(other))
95 def __radd__(self, other):
97 return self.__class__(other + self.data)
99 return self.__class__(str(other) + self.data)
100 def __mul__(self, n):
101 return self.__class__(self.data*n)
107 except AttributeError:
110 for i in xrange(len(lists[0])):
111 result.append(tuple(map(lambda l, i=i: l[i], lists)))
113 __builtin__.zip = zip
116 if _altsep is None and sys.platform == 'win32':
117 # My ActivePython 2.0.1 doesn't set os.altsep! What gives?
120 def rightmost_separator(path, sep, _altsep=_altsep):
122 return max(rfind(path, sep), rfind(path, _altsep))
124 rightmost_separator = string.rfind
126 # First two from the Python Cookbook, just for completeness.
127 # (Yeah, yeah, YAGNI...)
128 def containsAny(str, set):
129 """Check whether sequence str contains ANY of the items in set."""
131 if c in str: return 1
134 def containsAll(str, set):
135 """Check whether sequence str contains ALL of the items in set."""
137 if c not in str: return 0
140 def containsOnly(str, set):
141 """Check whether sequence str contains ONLY items in set."""
143 if c not in set: return 0
147 "Same as os.path.splitext() but faster."
148 sep = rightmost_separator(path, os.sep)
149 dot = string.rfind(path, '.')
150 # An ext is only real if it has at least one non-digit char
151 if dot > sep and not containsOnly(path[dot:], "0123456789."):
152 return path[:dot],path[dot:]
158 Make the drive letter (if any) upper case.
159 This is useful because Windows is inconsitent on the case
160 of the drive letter, which can cause inconsistencies when
161 calculating command signatures.
163 drive, rest = os.path.splitdrive(path)
165 path = string.upper(drive) + rest
169 # Generic convert-to-string functions that abstract away whether or
170 # not the Python we're executing has Unicode support. The wrapper
171 # to_String_for_signature() will use a for_signature() method if the
172 # specified object has one.
174 if hasattr(types, 'UnicodeType'):
175 UnicodeType = types.UnicodeType
177 if isinstance(s, UserString):
188 def to_String_for_signature(obj):
190 f = obj.for_signature
191 except AttributeError:
192 return to_String(obj)
196 class CallableComposite(UserList):
197 """A simple composite callable class that, when called, will invoke all
198 of its contained callables with the same arguments."""
199 def __call__(self, *args, **kwargs):
200 retvals = map(lambda x, args=args, kwargs=kwargs: apply(x,
204 if self.data and (len(self.data) == len(filter(callable, retvals))):
205 return self.__class__(retvals)
206 return NodeList(retvals)
208 class NodeList(UserList):
209 """This class is almost exactly like a regular list of Nodes
210 (actually it can hold any object), with one important difference.
211 If you try to get an attribute from this list, it will return that
212 attribute from every item in the list. For example:
214 >>> someList = NodeList([ ' foo ', ' bar ' ])
218 def __nonzero__(self):
219 return len(self.data) != 0
222 return string.join(map(str, self.data))
224 def __getattr__(self, name):
226 # If there is nothing in the list, then we have no attributes to
227 # pass through, so raise AttributeError for everything.
228 raise AttributeError, "NodeList has no attribute: %s" % name
230 # Return a list of the attribute, gotten from every element
232 attrList = map(lambda x, n=name: getattr(x, n), self.data)
234 # Special case. If the attribute is callable, we do not want
235 # to return a list of callables. Rather, we want to return a
236 # single callable that, when called, will invoke the function on
237 # all elements of this list.
238 if self.data and (len(self.data) == len(filter(callable, attrList))):
239 return CallableComposite(attrList)
240 return self.__class__(attrList)
242 _valid_var = re.compile(r'[_a-zA-Z]\w*$')
243 _get_env_var = re.compile(r'^\$([_a-zA-Z]\w*|{[_a-zA-Z]\w*})$')
245 def is_valid_construction_var(varstr):
246 """Return if the specified string is a legitimate construction
249 return _valid_var.match(varstr)
251 def get_environment_var(varstr):
252 """Given a string, first determine if it looks like a reference
253 to a single environment variable, like "$FOO" or "${FOO}".
254 If so, return that variable with no decorations ("FOO").
255 If not, return None."""
256 mo=_get_env_var.match(to_String(varstr))
268 self.__call__ = self.print_it
270 def print_it(self, text, append_newline=1):
271 if append_newline: text = text + '\n'
272 sys.stdout.write(text)
274 def dont_print(self, text, append_newline=1):
277 def set_mode(self, mode):
279 self.__call__ = self.print_it
281 self.__call__ = self.dont_print
283 def render_tree(root, child_func, prune=0, margin=[0], visited={}):
285 Render a tree of nodes into an ASCII tree view.
286 root - the root node of the tree
287 child_func - the function called to get the children of a node
288 prune - don't visit the same node twice
289 margin - the format of the left margin to use for children of root.
290 1 results in a pipe, and 0 results in no pipe.
291 visited - a dictionary of visited nodes in the current branch if not prune,
292 or in the whole tree if prune.
297 if visited.has_key(rname):
300 children = child_func(root)
302 for pipe in margin[:-1]:
304 retval = retval + "| "
306 retval = retval + " "
308 retval = retval + "+-" + rname + "\n"
310 visited = copy.copy(visited)
313 for i in range(len(children)):
314 margin.append(i<len(children)-1)
315 retval = retval + render_tree(children[i], child_func, prune, margin, visited
321 IDX = lambda N: N and 1 or 0
323 def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited={}):
325 Print a tree of nodes. This is like render_tree, except it prints
326 lines directly instead of creating a string representation in memory,
327 so that huge trees can be printed.
329 root - the root node of the tree
330 child_func - the function called to get the children of a node
331 prune - don't visit the same node twice
332 showtags - print status information to the left of each node line
333 margin - the format of the left margin to use for children of root.
334 1 results in a pipe, and 0 results in no pipe.
335 visited - a dictionary of visited nodes in the current branch if not prune,
336 or in the whole tree if prune.
341 if visited.has_key(rname):
348 print ' R = exists in repository only'
349 print ' b = implicit builder'
350 print ' B = explicit builder'
351 print ' S = side effect'
352 print ' P = precious'
353 print ' A = always build'
355 print ' N = no clean'
359 tags.append(' E'[IDX(root.exists())])
360 tags.append(' R'[IDX(root.rexists() and not root.exists())])
361 tags.append(' BbB'[[0,1][IDX(root.has_explicit_builder())] +
362 [0,2][IDX(root.has_builder())]])
363 tags.append(' S'[IDX(root.side_effect)])
364 tags.append(' P'[IDX(root.precious)])
365 tags.append(' A'[IDX(root.always_build)])
366 tags.append(' C'[IDX(root.current())])
367 tags.append(' N'[IDX(root.noclean)])
375 margins = map(MMM, margin[:-1])
377 print string.join(tags + margins + ['+-', rname], '')
382 children = child_func(root)
385 map(lambda C, cf=child_func, p=prune, i=IDX(showtags), m=margin, v=visited:
386 print_tree(C, cf, p, i, m, v),
389 print_tree(children[-1], child_func, prune, IDX(showtags), margin, visited)
394 # Functions for deciding if things are like various types, mainly to
395 # handle UserDict, UserList and UserString like their underlying types.
397 # Yes, all of this manual testing breaks polymorphism, and the real
398 # Pythonic way to do all of this would be to just try it and handle the
399 # exception, but handling the exception when it's not the right type is
402 # The actual implementations here have been selected after timings
403 # coded up in in bench/is_types.py (from the SCons source tree, see the
404 # scons-src distribution). Key results from those timings:
406 # -- Storing the type of the object in a variable (t = type(obj))
407 # slows down the case where it's a native type and the first
408 # comparison will match, but nicely speeds up the case where
409 # it's a different native type. Since that's going to be common,
410 # it's a good tradeoff.
412 # -- The data show that calling isinstance() on an object that's
413 # a native type (dict, list or string) is expensive enough that
414 # checking up front for whether the object is of type InstanceType
415 # is a pretty big win, even though it does slow down the case
416 # where it really *is* an object instance a little bit.
420 return t is DictType or \
421 (t is InstanceType and isinstance(obj, UserDict))
425 return t is ListType \
426 or (t is InstanceType and isinstance(obj, UserList))
430 return t is TupleType
432 if hasattr(types, 'UnicodeType'):
435 return t is StringType \
436 or t is UnicodeType \
437 or (t is InstanceType and isinstance(obj, UserString))
441 return t is StringType \
442 or (t is InstanceType and isinstance(obj, UserString))
447 return is_String(e) or (not is_List(e) and not is_Tuple(e))
449 def flatten(sequence, scalarp=is_Scalar, result=None):
452 for item in sequence:
456 flatten(item, scalarp, result)
460 """A simple generic Proxy class, forwarding all calls to
461 subject. So, for the benefit of the python newbie, what does
462 this really mean? Well, it means that you can take an object, let's
463 call it 'objA', and wrap it in this Proxy class, with a statement
466 proxyObj = Proxy(objA),
468 Then, if in the future, you do something like this
472 since Proxy does not have a 'var1' attribute (but presumably objA does),
473 the request actually is equivalent to saying
477 Inherit from this class to create a Proxy."""
479 def __init__(self, subject):
480 """Wrap an object as a Proxy object"""
481 self.__subject = subject
483 def __getattr__(self, name):
484 """Retrieve an attribute from the wrapped object. If the named
485 attribute doesn't exist, AttributeError is raised"""
486 return getattr(self.__subject, name)
489 """Retrieve the entire wrapped object"""
490 return self.__subject
492 def __cmp__(self, other):
493 if issubclass(other.__class__, self.__subject.__class__):
494 return cmp(self.__subject, other)
495 return cmp(self.__dict__, other.__dict__)
497 # attempt to load the windows registry module:
505 RegOpenKeyEx = _winreg.OpenKeyEx
506 RegEnumKey = _winreg.EnumKey
507 RegEnumValue = _winreg.EnumValue
508 RegQueryValueEx = _winreg.QueryValueEx
509 RegError = _winreg.error
518 RegOpenKeyEx = win32api.RegOpenKeyEx
519 RegEnumKey = win32api.RegEnumKey
520 RegEnumValue = win32api.RegEnumValue
521 RegQueryValueEx = win32api.RegQueryValueEx
522 RegError = win32api.error
525 class _NoError(Exception):
530 HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT
531 HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE
532 HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER
533 HKEY_USERS = hkey_mod.HKEY_USERS
535 def RegGetValue(root, key):
536 """This utility function returns a value in the registry
537 without having to open the key first. Only available on
538 Windows platforms with a version of Python that can read the
539 registry. Returns the same thing as
540 SCons.Util.RegQueryValueEx, except you just specify the entire
541 path to the value, and don't have to bother opening the key
545 k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
546 r'SOFTWARE\Microsoft\Windows\CurrentVersion')
547 out = SCons.Util.RegQueryValueEx(k,
551 out = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
552 r'SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir')
554 # I would use os.path.split here, but it's not a filesystem
556 p = key.rfind('\\') + 1
559 k = RegOpenKeyEx(root, keyp)
560 return RegQueryValueEx(k,val)
562 if sys.platform == 'win32':
564 def WhereIs(file, path=None, pathext=None, reject=[]):
567 path = os.environ['PATH']
571 path = string.split(path, os.pathsep)
574 pathext = os.environ['PATHEXT']
576 pathext = '.COM;.EXE;.BAT;.CMD'
577 if is_String(pathext):
578 pathext = string.split(pathext, os.pathsep)
580 if string.lower(ext) == string.lower(file[-len(ext):]):
583 if not is_List(reject) and not is_Tuple(reject):
586 f = os.path.join(dir, file)
589 if os.path.isfile(fext):
593 return os.path.normpath(fext)
597 elif os.name == 'os2':
599 def WhereIs(file, path=None, pathext=None, reject=[]):
602 path = os.environ['PATH']
606 path = string.split(path, os.pathsep)
608 pathext = ['.exe', '.cmd']
610 if string.lower(ext) == string.lower(file[-len(ext):]):
613 if not is_List(reject) and not is_Tuple(reject):
616 f = os.path.join(dir, file)
619 if os.path.isfile(fext):
623 return os.path.normpath(fext)
629 def WhereIs(file, path=None, pathext=None, reject=[]):
632 path = os.environ['PATH']
636 path = string.split(path, os.pathsep)
637 if not is_List(reject) and not is_Tuple(reject):
640 f = os.path.join(d, file)
641 if os.path.isfile(f):
645 # os.stat() raises OSError, not IOError if the file
646 # doesn't exist, so in this case we let IOError get
647 # raised so as to not mask possibly serious disk or
650 if stat.S_IMODE(st[stat.ST_MODE]) & 0111:
654 return os.path.normpath(f)
658 def PrependPath(oldpath, newpath, sep = os.pathsep):
659 """This prepends newpath elements to the given oldpath. Will only
660 add any particular path once (leaving the first one it encounters
661 and ignoring the rest, to preserve path order), and will
662 os.path.normpath and os.path.normcase all paths to help assure
663 this. This can also handle the case where the given old path
664 variable is a list instead of a string, in which case a list will
665 be returned instead of a string.
668 Old Path: "/foo/bar:/foo"
669 New Path: "/biz/boom:/foo"
670 Result: "/biz/boom:/foo:/foo/bar"
676 if not is_List(orig) and not is_Tuple(orig):
677 paths = string.split(paths, sep)
680 if is_List(newpath) or is_Tuple(newpath):
683 newpaths = string.split(newpath, sep)
685 newpaths = newpaths + paths # prepend new paths
689 # now we add them only if they are unique
690 for path in newpaths:
691 normpath = os.path.normpath(os.path.normcase(path))
692 if path and not normpath in normpaths:
694 normpaths.append(normpath)
699 return string.join(paths, sep)
701 def AppendPath(oldpath, newpath, sep = os.pathsep):
702 """This appends new path elements to the given old path. Will
703 only add any particular path once (leaving the last one it
704 encounters and ignoring the rest, to preserve path order), and
705 will os.path.normpath and os.path.normcase all paths to help
706 assure this. This can also handle the case where the given old
707 path variable is a list instead of a string, in which case a list
708 will be returned instead of a string.
711 Old Path: "/foo/bar:/foo"
712 New Path: "/biz/boom:/foo"
713 Result: "/foo/bar:/biz/boom:/foo"
719 if not is_List(orig) and not is_Tuple(orig):
720 paths = string.split(paths, sep)
723 if is_List(newpath) or is_Tuple(newpath):
726 newpaths = string.split(newpath, sep)
728 newpaths = paths + newpaths # append new paths
733 # now we add them only of they are unique
734 for path in newpaths:
735 normpath = os.path.normpath(os.path.normcase(path))
736 if path and not normpath in normpaths:
738 normpaths.append(normpath)
745 return string.join(paths, sep)
747 if sys.platform == 'cygwin':
748 def get_native_path(path):
749 """Transforms an absolute path into a native path for the system. In
750 Cygwin, this converts from a Cygwin path to a Windows one."""
751 return string.replace(os.popen('cygpath -w ' + path).read(), '\n', '')
753 def get_native_path(path):
754 """Transforms an absolute path into a native path for the system.
755 Non-Cygwin version, just leave the path alone."""
758 display = DisplayEngine()
761 if is_List(arg) or is_Tuple(arg):
764 return string.split(arg)
768 class CLVar(UserList):
769 """A class for command-line construction variables.
771 This is a list that uses Split() to split an initial string along
772 white-space arguments, and similarly to split any strings that get
773 added. This allows us to Do the Right Thing with Append() and
774 Prepend() (as well as straight Python foo = env['VAR'] + 'arg1
775 arg2') regardless of whether a user adds a list or a string to a
776 command-line construction variable.
778 def __init__(self, seq = []):
779 UserList.__init__(self, Split(seq))
780 def __coerce__(self, other):
781 return (self, CLVar(other))
783 return string.join(self.data)
785 # A dictionary that preserves the order in which items are added.
786 # Submitted by David Benjamin to ActiveState's Python Cookbook web site:
787 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/107747
788 # Including fixes/enhancements from the follow-on discussions.
789 class OrderedDict(UserDict):
790 def __init__(self, dict = None):
792 UserDict.__init__(self, dict)
794 def __delitem__(self, key):
795 UserDict.__delitem__(self, key)
796 self._keys.remove(key)
798 def __setitem__(self, key, item):
799 UserDict.__setitem__(self, key, item)
800 if key not in self._keys: self._keys.append(key)
812 return zip(self._keys, self.values())
821 raise KeyError('dictionary is empty')
828 def setdefault(self, key, failobj = None):
829 UserDict.setdefault(self, key, failobj)
830 if key not in self._keys: self._keys.append(key)
832 def update(self, dict):
833 for (key, val) in dict.items():
834 self.__setitem__(key, val)
837 return map(self.get, self._keys)
839 class Selector(OrderedDict):
840 """A callable ordered dictionary that maps file suffixes to
841 dictionary values. We preserve the order in which items are added
842 so that get_suffix() calls always return the first suffix added."""
843 def __call__(self, env, source):
845 ext = splitext(str(source[0]))[1]
851 # Try to perform Environment substitution on the keys of
852 # the dictionary before giving up.
854 for (k,v) in self.items():
857 if s_dict.has_key(s_k):
858 # We only raise an error when variables point
859 # to the same suffix. If one suffix is literal
860 # and a variable suffix contains this literal,
861 # the literal wins and we don't raise an error.
862 raise KeyError, (s_dict[s_k][0], k, s_k)
865 return s_dict[ext][1]
873 if sys.platform == 'cygwin':
874 # On Cygwin, os.path.normcase() lies, so just report back the
875 # fact that the underlying Windows OS is case-insensitive.
876 def case_sensitive_suffixes(s1, s2):
879 def case_sensitive_suffixes(s1, s2):
880 return (os.path.normcase(s1) != os.path.normcase(s2))
882 def adjustixes(fname, pre, suf):
884 path, fn = os.path.split(os.path.normpath(fname))
885 if fn[:len(pre)] != pre:
886 fname = os.path.join(path, pre + fn)
887 # Only append a suffix if the file does not have one.
888 if suf and not splitext(fname)[1] and fname[-len(suf):] != suf:
894 """Return a list of the elements in s, but without duplicates.
896 For example, unique([1,2,3,1,2,3]) is some permutation of [1,2,3],
897 unique("abcabc") some permutation of ["a", "b", "c"], and
898 unique(([1, 2], [2, 3], [1, 2])) some permutation of
901 For best speed, all sequence elements should be hashable. Then
902 unique() will usually work in linear time.
904 If not possible, the sequence elements should enjoy a total
905 ordering, and if list(s).sort() doesn't raise TypeError it's
906 assumed that they do enjoy a total ordering. Then unique() will
907 usually work in O(N*log2(N)) time.
909 If that's not possible either, the sequence elements must support
910 equality-testing. Then unique() will usually work in quadratic
918 # Try using a dict first, as that's the fastest and will usually
919 # work. If it doesn't work, it will usually fail quickly, so it
920 # usually doesn't cost much to *try* it. It requires that all the
921 # sequence elements be hashable, and support equality comparison.
927 del u # move on to the next method
931 # We can't hash all the elements. Second fastest is to sort,
932 # which brings the equal elements together; then duplicates are
933 # easy to weed out in a single pass.
934 # NOTE: Python's list.sort() was designed to be efficient in the
935 # presence of many duplicate elements. This isn't true of all
936 # sort functions in all languages or libraries, so this approach
937 # is more effective in Python than it may be elsewhere.
942 del t # move on to the next method
949 t[lasti] = last = t[i]
954 # Brute force is all that's left.
961 # Much of the logic here was originally based on recipe 4.9 from the
962 # Python CookBook, but we had to dumb it way down for Python 1.5.2.
965 def __init__(self, fileobj):
966 self.fileobj = fileobj
971 line = self.fileobj.readline()
974 if line[-2:] == '\\\n':
975 result.append(line[:-2])
979 return string.join(result, '')
984 line = self.readline()