3 Various utility functions go here.
8 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation
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__ = "src/engine/SCons/Util.py 3842 2008/12/20 22:59:52 scons"
40 from UserDict import UserDict
41 from UserList import UserList
42 from UserString import UserString
44 # Don't "from types import ..." these because we need to get at the
45 # types module later to look for UnicodeType.
46 DictType = types.DictType
47 InstanceType = types.InstanceType
48 ListType = types.ListType
49 StringType = types.StringType
50 TupleType = types.TupleType
52 def dictify(keys, values, result={}):
53 for k, v in zip(keys, values):
58 if _altsep is None and sys.platform == 'win32':
59 # My ActivePython 2.0.1 doesn't set os.altsep! What gives?
62 def rightmost_separator(path, sep, _altsep=_altsep):
64 return max(rfind(path, sep), rfind(path, _altsep))
66 rightmost_separator = string.rfind
68 # First two from the Python Cookbook, just for completeness.
69 # (Yeah, yeah, YAGNI...)
70 def containsAny(str, set):
71 """Check whether sequence str contains ANY of the items in set."""
76 def containsAll(str, set):
77 """Check whether sequence str contains ALL of the items in set."""
79 if c not in str: return 0
82 def containsOnly(str, set):
83 """Check whether sequence str contains ONLY items in set."""
85 if c not in set: return 0
89 "Same as os.path.splitext() but faster."
90 sep = rightmost_separator(path, os.sep)
91 dot = string.rfind(path, '.')
92 # An ext is only real if it has at least one non-digit char
93 if dot > sep and not containsOnly(path[dot:], "0123456789."):
94 return path[:dot],path[dot:]
100 Make the drive letter (if any) upper case.
101 This is useful because Windows is inconsitent on the case
102 of the drive letter, which can cause inconsistencies when
103 calculating command signatures.
105 drive, rest = os.path.splitdrive(path)
107 path = string.upper(drive) + rest
110 class CallableComposite(UserList):
111 """A simple composite callable class that, when called, will invoke all
112 of its contained callables with the same arguments."""
113 def __call__(self, *args, **kwargs):
114 retvals = map(lambda x, args=args, kwargs=kwargs: apply(x,
118 if self.data and (len(self.data) == len(filter(callable, retvals))):
119 return self.__class__(retvals)
120 return NodeList(retvals)
122 class NodeList(UserList):
123 """This class is almost exactly like a regular list of Nodes
124 (actually it can hold any object), with one important difference.
125 If you try to get an attribute from this list, it will return that
126 attribute from every item in the list. For example:
128 >>> someList = NodeList([ ' foo ', ' bar ' ])
132 def __nonzero__(self):
133 return len(self.data) != 0
136 return string.join(map(str, self.data))
138 def __getattr__(self, name):
140 # If there is nothing in the list, then we have no attributes to
141 # pass through, so raise AttributeError for everything.
142 raise AttributeError, "NodeList has no attribute: %s" % name
144 # Return a list of the attribute, gotten from every element
146 attrList = map(lambda x, n=name: getattr(x, n), self.data)
148 # Special case. If the attribute is callable, we do not want
149 # to return a list of callables. Rather, we want to return a
150 # single callable that, when called, will invoke the function on
151 # all elements of this list.
152 if self.data and (len(self.data) == len(filter(callable, attrList))):
153 return CallableComposite(attrList)
154 return self.__class__(attrList)
156 _get_env_var = re.compile(r'^\$([_a-zA-Z]\w*|{[_a-zA-Z]\w*})$')
158 def get_environment_var(varstr):
159 """Given a string, first determine if it looks like a reference
160 to a single environment variable, like "$FOO" or "${FOO}".
161 If so, return that variable with no decorations ("FOO").
162 If not, return None."""
163 mo=_get_env_var.match(to_String(varstr))
175 self.__call__ = self.print_it
177 def print_it(self, text, append_newline=1):
178 if append_newline: text = text + '\n'
180 sys.stdout.write(text)
182 # Stdout might be connected to a pipe that has been closed
183 # by now. The most likely reason for the pipe being closed
184 # is that the user has press ctrl-c. It this is the case,
185 # then SCons is currently shutdown. We therefore ignore
186 # IOError's here so that SCons can continue and shutdown
187 # properly so that the .sconsign is correctly written
188 # before SCons exits.
191 def dont_print(self, text, append_newline=1):
194 def set_mode(self, mode):
196 self.__call__ = self.print_it
198 self.__call__ = self.dont_print
200 def render_tree(root, child_func, prune=0, margin=[0], visited={}):
202 Render a tree of nodes into an ASCII tree view.
203 root - the root node of the tree
204 child_func - the function called to get the children of a node
205 prune - don't visit the same node twice
206 margin - the format of the left margin to use for children of root.
207 1 results in a pipe, and 0 results in no pipe.
208 visited - a dictionary of visited nodes in the current branch if not prune,
209 or in the whole tree if prune.
214 children = child_func(root)
216 for pipe in margin[:-1]:
218 retval = retval + "| "
220 retval = retval + " "
222 if visited.has_key(rname):
223 return retval + "+-[" + rname + "]\n"
225 retval = retval + "+-" + rname + "\n"
227 visited = copy.copy(visited)
230 for i in range(len(children)):
231 margin.append(i<len(children)-1)
232 retval = retval + render_tree(children[i], child_func, prune, margin, visited
238 IDX = lambda N: N and 1 or 0
240 def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited={}):
242 Print a tree of nodes. This is like render_tree, except it prints
243 lines directly instead of creating a string representation in memory,
244 so that huge trees can be printed.
246 root - the root node of the tree
247 child_func - the function called to get the children of a node
248 prune - don't visit the same node twice
249 showtags - print status information to the left of each node line
250 margin - the format of the left margin to use for children of root.
251 1 results in a pipe, and 0 results in no pipe.
252 visited - a dictionary of visited nodes in the current branch if not prune,
253 or in the whole tree if prune.
262 print ' R = exists in repository only'
263 print ' b = implicit builder'
264 print ' B = explicit builder'
265 print ' S = side effect'
266 print ' P = precious'
267 print ' A = always build'
269 print ' N = no clean'
270 print ' H = no cache'
274 tags.append(' E'[IDX(root.exists())])
275 tags.append(' R'[IDX(root.rexists() and not root.exists())])
276 tags.append(' BbB'[[0,1][IDX(root.has_explicit_builder())] +
277 [0,2][IDX(root.has_builder())]])
278 tags.append(' S'[IDX(root.side_effect)])
279 tags.append(' P'[IDX(root.precious)])
280 tags.append(' A'[IDX(root.always_build)])
281 tags.append(' C'[IDX(root.is_up_to_date())])
282 tags.append(' N'[IDX(root.noclean)])
283 tags.append(' H'[IDX(root.nocache)])
291 margins = map(MMM, margin[:-1])
293 children = child_func(root)
295 if prune and visited.has_key(rname) and children:
296 print string.join(tags + margins + ['+-[', rname, ']'], '')
299 print string.join(tags + margins + ['+-', rname], '')
305 map(lambda C, cf=child_func, p=prune, i=IDX(showtags), m=margin, v=visited:
306 print_tree(C, cf, p, i, m, v),
309 print_tree(children[-1], child_func, prune, IDX(showtags), margin, visited)
314 # Functions for deciding if things are like various types, mainly to
315 # handle UserDict, UserList and UserString like their underlying types.
317 # Yes, all of this manual testing breaks polymorphism, and the real
318 # Pythonic way to do all of this would be to just try it and handle the
319 # exception, but handling the exception when it's not the right type is
326 # An older Python version without new-style classes.
328 # The actual implementations here have been selected after timings
329 # coded up in in bench/is_types.py (from the SCons source tree,
330 # see the scons-src distribution), mostly against Python 1.5.2.
331 # Key results from those timings:
333 # -- Storing the type of the object in a variable (t = type(obj))
334 # slows down the case where it's a native type and the first
335 # comparison will match, but nicely speeds up the case where
336 # it's a different native type. Since that's going to be
337 # common, it's a good tradeoff.
339 # -- The data show that calling isinstance() on an object that's
340 # a native type (dict, list or string) is expensive enough
341 # that checking up front for whether the object is of type
342 # InstanceType is a pretty big win, even though it does slow
343 # down the case where it really *is* an object instance a
347 return t is DictType or \
348 (t is InstanceType and isinstance(obj, UserDict))
352 return t is ListType \
353 or (t is InstanceType and isinstance(obj, UserList))
355 def is_Sequence(obj):
357 return t is ListType \
359 or (t is InstanceType and isinstance(obj, UserList))
363 return t is TupleType
365 if hasattr(types, 'UnicodeType'):
368 return t is StringType \
369 or t is UnicodeType \
370 or (t is InstanceType and isinstance(obj, UserString))
374 return t is StringType \
375 or (t is InstanceType and isinstance(obj, UserString))
378 return is_String(obj) or not is_Sequence(obj)
380 def flatten(obj, result=None):
381 """Flatten a sequence to a non-nested list.
383 Flatten() converts either a single scalar or a nested sequence
384 to a non-nested list. Note that flatten() considers strings
385 to be scalars instead of sequences like Python would.
395 flatten_sequence(item, result)
398 def flatten_sequence(sequence, result=None):
399 """Flatten a sequence to a non-nested list.
401 Same as flatten(), but it does not handle the single scalar
402 case. This is slightly more efficient when one knows that
403 the sequence to flatten can not be a scalar.
407 for item in sequence:
411 flatten_sequence(item, result)
415 # Generic convert-to-string functions that abstract away whether or
416 # not the Python we're executing has Unicode support. The wrapper
417 # to_String_for_signature() will use a for_signature() method if the
418 # specified object has one.
420 if hasattr(types, 'UnicodeType'):
421 UnicodeType = types.UnicodeType
423 if isinstance(s, UserString):
434 def to_String_for_signature(obj):
436 f = obj.for_signature
437 except AttributeError:
438 return to_String_for_subst(obj)
442 def to_String_for_subst(s):
444 return string.join( map(to_String_for_subst, s) )
446 return to_String( s )
449 # A modern Python version with new-style classes, so we can just use
452 # We are using the following trick to speed-up these
453 # functions. Default arguments are used to take a snapshot of the
454 # the global functions and constants used by these functions. This
455 # transforms accesses to global variable into local variables
456 # accesses (i.e. LOAD_FAST instead of LOAD_GLOBAL).
458 DictTypes = (dict, UserDict)
459 ListTypes = (list, UserList)
460 SequenceTypes = (list, tuple, UserList)
462 # Empirically, Python versions with new-style classes all have
465 # Note that profiling data shows a speed-up when comparing
466 # explicitely with str and unicode instead of simply comparing
467 # with basestring. (at least on Python 2.5.1)
468 StringTypes = (str, unicode, UserString)
470 # Empirically, it is faster to check explicitely for str and
471 # unicode than for basestring.
472 BaseStringTypes = (str, unicode)
474 def is_Dict(obj, isinstance=isinstance, DictTypes=DictTypes):
475 return isinstance(obj, DictTypes)
477 def is_List(obj, isinstance=isinstance, ListTypes=ListTypes):
478 return isinstance(obj, ListTypes)
480 def is_Sequence(obj, isinstance=isinstance, SequenceTypes=SequenceTypes):
481 return isinstance(obj, SequenceTypes)
483 def is_Tuple(obj, isinstance=isinstance, tuple=tuple):
484 return isinstance(obj, tuple)
486 def is_String(obj, isinstance=isinstance, StringTypes=StringTypes):
487 return isinstance(obj, StringTypes)
489 def is_Scalar(obj, isinstance=isinstance, StringTypes=StringTypes, SequenceTypes=SequenceTypes):
490 # Profiling shows that there is an impressive speed-up of 2x
491 # when explicitely checking for strings instead of just not
492 # sequence when the argument (i.e. obj) is already a string.
493 # But, if obj is a not string than it is twice as fast to
494 # check only for 'not sequence'. The following code therefore
495 # assumes that the obj argument is a string must of the time.
496 return isinstance(obj, StringTypes) or not isinstance(obj, SequenceTypes)
498 def do_flatten(sequence, result, isinstance=isinstance,
499 StringTypes=StringTypes, SequenceTypes=SequenceTypes):
500 for item in sequence:
501 if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes):
504 do_flatten(item, result)
506 def flatten(obj, isinstance=isinstance, StringTypes=StringTypes,
507 SequenceTypes=SequenceTypes, do_flatten=do_flatten):
508 """Flatten a sequence to a non-nested list.
510 Flatten() converts either a single scalar or a nested sequence
511 to a non-nested list. Note that flatten() considers strings
512 to be scalars instead of sequences like Python would.
514 if isinstance(obj, StringTypes) or not isinstance(obj, SequenceTypes):
518 if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes):
521 do_flatten(item, result)
524 def flatten_sequence(sequence, isinstance=isinstance, StringTypes=StringTypes,
525 SequenceTypes=SequenceTypes, do_flatten=do_flatten):
526 """Flatten a sequence to a non-nested list.
528 Same as flatten(), but it does not handle the single scalar
529 case. This is slightly more efficient when one knows that
530 the sequence to flatten can not be a scalar.
533 for item in sequence:
534 if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes):
537 do_flatten(item, result)
542 # Generic convert-to-string functions that abstract away whether or
543 # not the Python we're executing has Unicode support. The wrapper
544 # to_String_for_signature() will use a for_signature() method if the
545 # specified object has one.
548 isinstance=isinstance, str=str,
549 UserString=UserString, BaseStringTypes=BaseStringTypes):
550 if isinstance(s,BaseStringTypes):
551 # Early out when already a string!
553 elif isinstance(s, UserString):
554 # s.data can only be either a unicode or a regular
555 # string. Please see the UserString initializer.
560 def to_String_for_subst(s,
561 isinstance=isinstance, join=string.join, str=str, to_String=to_String,
562 BaseStringTypes=BaseStringTypes, SequenceTypes=SequenceTypes,
563 UserString=UserString):
565 # Note that the test cases are sorted by order of probability.
566 if isinstance(s, BaseStringTypes):
568 elif isinstance(s, SequenceTypes):
571 l.append(to_String_for_subst(e))
573 elif isinstance(s, UserString):
574 # s.data can only be either a unicode or a regular
575 # string. Please see the UserString initializer.
580 def to_String_for_signature(obj, to_String_for_subst=to_String_for_subst,
581 AttributeError=AttributeError):
583 f = obj.for_signature
584 except AttributeError:
585 return to_String_for_subst(obj)
591 # The SCons "semi-deep" copy.
593 # This makes separate copies of lists (including UserList objects)
594 # dictionaries (including UserDict objects) and tuples, but just copies
595 # references to anything else it finds.
597 # A special case is any object that has a __semi_deepcopy__() method,
598 # which we invoke to create the copy, which is used by the BuilderDict
599 # class because of its extra initialization argument.
601 # The dispatch table approach used here is a direct rip-off from the
602 # normal Python copy module.
604 _semi_deepcopy_dispatch = d = {}
606 def _semi_deepcopy_dict(x):
608 for key, val in x.items():
609 # The regular Python copy.deepcopy() also deepcopies the key,
612 # copy[semi_deepcopy(key)] = semi_deepcopy(val)
614 # Doesn't seem like we need to, but we'll comment it just in case.
615 copy[key] = semi_deepcopy(val)
617 d[types.DictionaryType] = _semi_deepcopy_dict
619 def _semi_deepcopy_list(x):
620 return map(semi_deepcopy, x)
621 d[types.ListType] = _semi_deepcopy_list
623 def _semi_deepcopy_tuple(x):
624 return tuple(map(semi_deepcopy, x))
625 d[types.TupleType] = _semi_deepcopy_tuple
627 def _semi_deepcopy_inst(x):
628 if hasattr(x, '__semi_deepcopy__'):
629 return x.__semi_deepcopy__()
630 elif isinstance(x, UserDict):
631 return x.__class__(_semi_deepcopy_dict(x))
632 elif isinstance(x, UserList):
633 return x.__class__(_semi_deepcopy_list(x))
636 d[types.InstanceType] = _semi_deepcopy_inst
638 def semi_deepcopy(x):
639 copier = _semi_deepcopy_dispatch.get(type(x))
648 """A simple generic Proxy class, forwarding all calls to
649 subject. So, for the benefit of the python newbie, what does
650 this really mean? Well, it means that you can take an object, let's
651 call it 'objA', and wrap it in this Proxy class, with a statement
654 proxyObj = Proxy(objA),
656 Then, if in the future, you do something like this
660 since Proxy does not have a 'var1' attribute (but presumably objA does),
661 the request actually is equivalent to saying
665 Inherit from this class to create a Proxy."""
667 def __init__(self, subject):
668 """Wrap an object as a Proxy object"""
669 self.__subject = subject
671 def __getattr__(self, name):
672 """Retrieve an attribute from the wrapped object. If the named
673 attribute doesn't exist, AttributeError is raised"""
674 return getattr(self.__subject, name)
677 """Retrieve the entire wrapped object"""
678 return self.__subject
680 def __cmp__(self, other):
681 if issubclass(other.__class__, self.__subject.__class__):
682 return cmp(self.__subject, other)
683 return cmp(self.__dict__, other.__dict__)
685 # attempt to load the windows registry module:
693 RegOpenKeyEx = _winreg.OpenKeyEx
694 RegEnumKey = _winreg.EnumKey
695 RegEnumValue = _winreg.EnumValue
696 RegQueryValueEx = _winreg.QueryValueEx
697 RegError = _winreg.error
706 RegOpenKeyEx = win32api.RegOpenKeyEx
707 RegEnumKey = win32api.RegEnumKey
708 RegEnumValue = win32api.RegEnumValue
709 RegQueryValueEx = win32api.RegQueryValueEx
710 RegError = win32api.error
713 class _NoError(Exception):
718 HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT
719 HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE
720 HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER
721 HKEY_USERS = hkey_mod.HKEY_USERS
723 def RegGetValue(root, key):
724 """This utility function returns a value in the registry
725 without having to open the key first. Only available on
726 Windows platforms with a version of Python that can read the
727 registry. Returns the same thing as
728 SCons.Util.RegQueryValueEx, except you just specify the entire
729 path to the value, and don't have to bother opening the key
733 k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
734 r'SOFTWARE\Microsoft\Windows\CurrentVersion')
735 out = SCons.Util.RegQueryValueEx(k,
739 out = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
740 r'SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir')
742 # I would use os.path.split here, but it's not a filesystem
744 p = key.rfind('\\') + 1
747 k = RegOpenKeyEx(root, keyp)
748 return RegQueryValueEx(k,val)
750 if sys.platform == 'win32':
752 def WhereIs(file, path=None, pathext=None, reject=[]):
755 path = os.environ['PATH']
759 path = string.split(path, os.pathsep)
762 pathext = os.environ['PATHEXT']
764 pathext = '.COM;.EXE;.BAT;.CMD'
765 if is_String(pathext):
766 pathext = string.split(pathext, os.pathsep)
768 if string.lower(ext) == string.lower(file[-len(ext):]):
771 if not is_List(reject) and not is_Tuple(reject):
774 f = os.path.join(dir, file)
777 if os.path.isfile(fext):
781 return os.path.normpath(fext)
785 elif os.name == 'os2':
787 def WhereIs(file, path=None, pathext=None, reject=[]):
790 path = os.environ['PATH']
794 path = string.split(path, os.pathsep)
796 pathext = ['.exe', '.cmd']
798 if string.lower(ext) == string.lower(file[-len(ext):]):
801 if not is_List(reject) and not is_Tuple(reject):
804 f = os.path.join(dir, file)
807 if os.path.isfile(fext):
811 return os.path.normpath(fext)
817 def WhereIs(file, path=None, pathext=None, reject=[]):
821 path = os.environ['PATH']
825 path = string.split(path, os.pathsep)
826 if not is_List(reject) and not is_Tuple(reject):
829 f = os.path.join(d, file)
830 if os.path.isfile(f):
834 # os.stat() raises OSError, not IOError if the file
835 # doesn't exist, so in this case we let IOError get
836 # raised so as to not mask possibly serious disk or
839 if stat.S_IMODE(st[stat.ST_MODE]) & 0111:
843 return os.path.normpath(f)
847 def PrependPath(oldpath, newpath, sep = os.pathsep, delete_existing=1):
848 """This prepends newpath elements to the given oldpath. Will only
849 add any particular path once (leaving the first one it encounters
850 and ignoring the rest, to preserve path order), and will
851 os.path.normpath and os.path.normcase all paths to help assure
852 this. This can also handle the case where the given old path
853 variable is a list instead of a string, in which case a list will
854 be returned instead of a string.
857 Old Path: "/foo/bar:/foo"
858 New Path: "/biz/boom:/foo"
859 Result: "/biz/boom:/foo:/foo/bar"
861 If delete_existing is 0, then adding a path that exists will
862 not move it to the beginning; it will stay where it is in the
869 if not is_List(orig) and not is_Tuple(orig):
870 paths = string.split(paths, sep)
873 if is_List(newpath) or is_Tuple(newpath):
876 newpaths = string.split(newpath, sep)
878 if not delete_existing:
879 # First uniquify the old paths, making sure to
880 # preserve the first instance (in Unix/Linux,
881 # the first one wins), and remembering them in normpaths.
882 # Then insert the new paths at the head of the list
883 # if they're not already in the normpaths list.
889 normpath = os.path.normpath(os.path.normcase(path))
890 if normpath not in normpaths:
892 normpaths.append(normpath)
893 newpaths.reverse() # since we're inserting at the head
894 for path in newpaths:
897 normpath = os.path.normpath(os.path.normcase(path))
898 if normpath not in normpaths:
899 result.insert(0, path)
900 normpaths.append(normpath)
904 newpaths = newpaths + paths # prepend new paths
908 # now we add them only if they are unique
909 for path in newpaths:
910 normpath = os.path.normpath(os.path.normcase(path))
911 if path and not normpath in normpaths:
913 normpaths.append(normpath)
918 return string.join(paths, sep)
920 def AppendPath(oldpath, newpath, sep = os.pathsep, delete_existing=1):
921 """This appends new path elements to the given old path. Will
922 only add any particular path once (leaving the last one it
923 encounters and ignoring the rest, to preserve path order), and
924 will os.path.normpath and os.path.normcase all paths to help
925 assure this. This can also handle the case where the given old
926 path variable is a list instead of a string, in which case a list
927 will be returned instead of a string.
930 Old Path: "/foo/bar:/foo"
931 New Path: "/biz/boom:/foo"
932 Result: "/foo/bar:/biz/boom:/foo"
934 If delete_existing is 0, then adding a path that exists
935 will not move it to the end; it will stay where it is in the list.
941 if not is_List(orig) and not is_Tuple(orig):
942 paths = string.split(paths, sep)
945 if is_List(newpath) or is_Tuple(newpath):
948 newpaths = string.split(newpath, sep)
950 if not delete_existing:
951 # add old paths to result, then
952 # add new paths if not already present
953 # (I thought about using a dict for normpaths for speed,
954 # but it's not clear hashing the strings would be faster
955 # than linear searching these typically short lists.)
962 normpaths.append(os.path.normpath(os.path.normcase(path)))
963 for path in newpaths:
966 normpath = os.path.normpath(os.path.normcase(path))
967 if normpath not in normpaths:
969 normpaths.append(normpath)
972 # start w/ new paths, add old ones if not present,
974 newpaths = paths + newpaths # append new paths
979 # now we add them only if they are unique
980 for path in newpaths:
981 normpath = os.path.normpath(os.path.normcase(path))
982 if path and not normpath in normpaths:
984 normpaths.append(normpath)
990 return string.join(paths, sep)
992 if sys.platform == 'cygwin':
993 def get_native_path(path):
994 """Transforms an absolute path into a native path for the system. In
995 Cygwin, this converts from a Cygwin path to a Windows one."""
996 return string.replace(os.popen('cygpath -w ' + path).read(), '\n', '')
998 def get_native_path(path):
999 """Transforms an absolute path into a native path for the system.
1000 Non-Cygwin version, just leave the path alone."""
1003 display = DisplayEngine()
1006 if is_List(arg) or is_Tuple(arg):
1008 elif is_String(arg):
1009 return string.split(arg)
1013 class CLVar(UserList):
1014 """A class for command-line construction variables.
1016 This is a list that uses Split() to split an initial string along
1017 white-space arguments, and similarly to split any strings that get
1018 added. This allows us to Do the Right Thing with Append() and
1019 Prepend() (as well as straight Python foo = env['VAR'] + 'arg1
1020 arg2') regardless of whether a user adds a list or a string to a
1021 command-line construction variable.
1023 def __init__(self, seq = []):
1024 UserList.__init__(self, Split(seq))
1025 def __add__(self, other):
1026 return UserList.__add__(self, CLVar(other))
1027 def __radd__(self, other):
1028 return UserList.__radd__(self, CLVar(other))
1029 def __coerce__(self, other):
1030 return (self, CLVar(other))
1032 return string.join(self.data)
1034 # A dictionary that preserves the order in which items are added.
1035 # Submitted by David Benjamin to ActiveState's Python Cookbook web site:
1036 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/107747
1037 # Including fixes/enhancements from the follow-on discussions.
1038 class OrderedDict(UserDict):
1039 def __init__(self, dict = None):
1041 UserDict.__init__(self, dict)
1043 def __delitem__(self, key):
1044 UserDict.__delitem__(self, key)
1045 self._keys.remove(key)
1047 def __setitem__(self, key, item):
1048 UserDict.__setitem__(self, key, item)
1049 if key not in self._keys: self._keys.append(key)
1052 UserDict.clear(self)
1056 dict = OrderedDict()
1061 return zip(self._keys, self.values())
1064 return self._keys[:]
1068 key = self._keys[-1]
1070 raise KeyError('dictionary is empty')
1077 def setdefault(self, key, failobj = None):
1078 UserDict.setdefault(self, key, failobj)
1079 if key not in self._keys: self._keys.append(key)
1081 def update(self, dict):
1082 for (key, val) in dict.items():
1083 self.__setitem__(key, val)
1086 return map(self.get, self._keys)
1088 class Selector(OrderedDict):
1089 """A callable ordered dictionary that maps file suffixes to
1090 dictionary values. We preserve the order in which items are added
1091 so that get_suffix() calls always return the first suffix added."""
1092 def __call__(self, env, source):
1094 ext = source[0].suffix
1100 # Try to perform Environment substitution on the keys of
1101 # the dictionary before giving up.
1103 for (k,v) in self.items():
1106 if s_dict.has_key(s_k):
1107 # We only raise an error when variables point
1108 # to the same suffix. If one suffix is literal
1109 # and a variable suffix contains this literal,
1110 # the literal wins and we don't raise an error.
1111 raise KeyError, (s_dict[s_k][0], k, s_k)
1114 return s_dict[ext][1]
1122 if sys.platform == 'cygwin':
1123 # On Cygwin, os.path.normcase() lies, so just report back the
1124 # fact that the underlying Windows OS is case-insensitive.
1125 def case_sensitive_suffixes(s1, s2):
1128 def case_sensitive_suffixes(s1, s2):
1129 return (os.path.normcase(s1) != os.path.normcase(s2))
1131 def adjustixes(fname, pre, suf, ensure_suffix=False):
1133 path, fn = os.path.split(os.path.normpath(fname))
1134 if fn[:len(pre)] != pre:
1135 fname = os.path.join(path, pre + fn)
1136 # Only append a suffix if the suffix we're going to add isn't already
1137 # there, and if either we've been asked to ensure the specific suffix
1138 # is present or there's no suffix on it at all.
1139 if suf and fname[-len(suf):] != suf and \
1140 (ensure_suffix or not splitext(fname)[1]):
1147 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560
1148 # ASPN: Python Cookbook: Remove duplicates from a sequence
1149 # (Also in the printed Python Cookbook.)
1152 """Return a list of the elements in s, but without duplicates.
1154 For example, unique([1,2,3,1,2,3]) is some permutation of [1,2,3],
1155 unique("abcabc") some permutation of ["a", "b", "c"], and
1156 unique(([1, 2], [2, 3], [1, 2])) some permutation of
1159 For best speed, all sequence elements should be hashable. Then
1160 unique() will usually work in linear time.
1162 If not possible, the sequence elements should enjoy a total
1163 ordering, and if list(s).sort() doesn't raise TypeError it's
1164 assumed that they do enjoy a total ordering. Then unique() will
1165 usually work in O(N*log2(N)) time.
1167 If that's not possible either, the sequence elements must support
1168 equality-testing. Then unique() will usually work in quadratic
1176 # Try using a dict first, as that's the fastest and will usually
1177 # work. If it doesn't work, it will usually fail quickly, so it
1178 # usually doesn't cost much to *try* it. It requires that all the
1179 # sequence elements be hashable, and support equality comparison.
1185 pass # move on to the next method
1190 # We can't hash all the elements. Second fastest is to sort,
1191 # which brings the equal elements together; then duplicates are
1192 # easy to weed out in a single pass.
1193 # NOTE: Python's list.sort() was designed to be efficient in the
1194 # presence of many duplicate elements. This isn't true of all
1195 # sort functions in all languages or libraries, so this approach
1196 # is more effective in Python than it may be elsewhere.
1201 pass # move on to the next method
1208 t[lasti] = last = t[i]
1214 # Brute force is all that's left.
1223 # From Alex Martelli,
1224 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560
1225 # ASPN: Python Cookbook: Remove duplicates from a sequence
1226 # First comment, dated 2001/10/13.
1227 # (Also in the printed Python Cookbook.)
1229 def uniquer(seq, idfun=None):
1231 def idfun(x): return x
1235 marker = idfun(item)
1236 # in old Python versions:
1237 # if seen.has_key(marker)
1239 if marker in seen: continue
1244 # A more efficient implementation of Alex's uniquer(), this avoids the
1245 # idfun() argument and function-call overhead by assuming that all
1246 # items in the sequence are hashable.
1248 def uniquer_hashables(seq):
1252 #if not item in seen:
1253 if not seen.has_key(item):
1260 # Much of the logic here was originally based on recipe 4.9 from the
1261 # Python CookBook, but we had to dumb it way down for Python 1.5.2.
1264 def __init__(self, fileobj):
1265 self.fileobj = fileobj
1270 line = self.fileobj.readline()
1273 if line[-2:] == '\\\n':
1274 result.append(line[:-2])
1278 return string.join(result, '')
1280 def readlines(self):
1283 line = self.readline()
1291 class UniqueList(UserList):
1292 def __init__(self, seq = []):
1293 UserList.__init__(self, seq)
1295 def __make_unique(self):
1297 self.data = uniquer_hashables(self.data)
1299 def __lt__(self, other):
1300 self.__make_unique()
1301 return UserList.__lt__(self, other)
1302 def __le__(self, other):
1303 self.__make_unique()
1304 return UserList.__le__(self, other)
1305 def __eq__(self, other):
1306 self.__make_unique()
1307 return UserList.__eq__(self, other)
1308 def __ne__(self, other):
1309 self.__make_unique()
1310 return UserList.__ne__(self, other)
1311 def __gt__(self, other):
1312 self.__make_unique()
1313 return UserList.__gt__(self, other)
1314 def __ge__(self, other):
1315 self.__make_unique()
1316 return UserList.__ge__(self, other)
1317 def __cmp__(self, other):
1318 self.__make_unique()
1319 return UserList.__cmp__(self, other)
1321 self.__make_unique()
1322 return UserList.__len__(self)
1323 def __getitem__(self, i):
1324 self.__make_unique()
1325 return UserList.__getitem__(self, i)
1326 def __setitem__(self, i, item):
1327 UserList.__setitem__(self, i, item)
1329 def __getslice__(self, i, j):
1330 self.__make_unique()
1331 return UserList.__getslice__(self, i, j)
1332 def __setslice__(self, i, j, other):
1333 UserList.__setslice__(self, i, j, other)
1335 def __add__(self, other):
1336 result = UserList.__add__(self, other)
1337 result.unique = False
1339 def __radd__(self, other):
1340 result = UserList.__radd__(self, other)
1341 result.unique = False
1343 def __iadd__(self, other):
1344 result = UserList.__iadd__(self, other)
1345 result.unique = False
1347 def __mul__(self, other):
1348 result = UserList.__mul__(self, other)
1349 result.unique = False
1351 def __rmul__(self, other):
1352 result = UserList.__rmul__(self, other)
1353 result.unique = False
1355 def __imul__(self, other):
1356 result = UserList.__imul__(self, other)
1357 result.unique = False
1359 def append(self, item):
1360 UserList.append(self, item)
1362 def insert(self, i):
1363 UserList.insert(self, i)
1365 def count(self, item):
1366 self.__make_unique()
1367 return UserList.count(self, item)
1368 def index(self, item):
1369 self.__make_unique()
1370 return UserList.index(self, item)
1372 self.__make_unique()
1373 UserList.reverse(self)
1374 def sort(self, *args, **kwds):
1375 self.__make_unique()
1376 #return UserList.sort(self, *args, **kwds)
1377 return apply(UserList.sort, (self,)+args, kwds)
1378 def extend(self, other):
1379 UserList.extend(self, other)
1386 A proxy class that wraps a file object, flushing after every write,
1387 and delegating everything else to the wrapped object.
1389 def __init__(self, file):
1391 def write(self, arg):
1393 self.file.write(arg)
1396 # Stdout might be connected to a pipe that has been closed
1397 # by now. The most likely reason for the pipe being closed
1398 # is that the user has press ctrl-c. It this is the case,
1399 # then SCons is currently shutdown. We therefore ignore
1400 # IOError's here so that SCons can continue and shutdown
1401 # properly so that the .sconsign is correctly written
1402 # before SCons exits.
1404 def __getattr__(self, attr):
1405 return getattr(self.file, attr)
1407 def make_path_relative(path):
1408 """ makes an absolute path name to a relative pathname.
1410 if os.path.isabs(path):
1411 drive_s,path = os.path.splitdrive(path)
1415 path=re.compile("/*(.*)").findall(path)[0]
1419 assert( not os.path.isabs( path ) ), path
1424 # The original idea for AddMethod() and RenameFunction() come from the
1425 # following post to the ActiveState Python Cookbook:
1427 # ASPN: Python Cookbook : Install bound methods in an instance
1428 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/223613
1430 # That code was a little fragile, though, so the following changes
1431 # have been wrung on it:
1433 # * Switched the installmethod() "object" and "function" arguments,
1434 # so the order reflects that the left-hand side is the thing being
1435 # "assigned to" and the right-hand side is the value being assigned.
1437 # * Changed explicit type-checking to the "try: klass = object.__class__"
1438 # block in installmethod() below so that it still works with the
1439 # old-style classes that SCons uses.
1441 # * Replaced the by-hand creation of methods and functions with use of
1442 # the "new" module, as alluded to in Alex Martelli's response to the
1443 # following Cookbook post:
1445 # ASPN: Python Cookbook : Dynamically added methods to a class
1446 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81732
1448 def AddMethod(object, function, name = None):
1450 Adds either a bound method to an instance or an unbound method to
1451 a class. If name is ommited the name of the specified function
1457 AddMethod(f, A, "add")
1460 AddMethod(lambda self, i: self.l[i], a, "listIndex")
1461 print a.listIndex(5)
1466 name = function.func_name
1468 function = RenameFunction(function, name)
1471 klass = object.__class__
1472 except AttributeError:
1473 # "object" is really a class, so it gets an unbound method.
1474 object.__dict__[name] = new.instancemethod(function, None, object)
1476 # "object" is really an instance, so it gets a bound method.
1477 object.__dict__[name] = new.instancemethod(function, object, klass)
1479 def RenameFunction(function, name):
1481 Returns a function identical to the specified function, but with
1486 # Compatibility for Python 1.5 and 2.1. Can be removed in favor of
1487 # passing function.func_defaults directly to new.function() once
1488 # we base on Python 2.2 or later.
1489 func_defaults = function.func_defaults
1490 if func_defaults is None:
1493 return new.function(function.func_code,
1494 function.func_globals,
1500 def MD5signature(s):
1503 def MD5filesignature(fname, chunksize=65536):
1504 f = open(fname, "rb")
1514 if hasattr(hashlib, 'md5'):
1516 def MD5signature(s):
1519 return m.hexdigest()
1521 def MD5filesignature(fname, chunksize=65536):
1523 f = open(fname, "rb")
1525 blck = f.read(chunksize)
1530 return m.hexdigest()
1532 def MD5collect(signatures):
1534 Collects a list of signatures into an aggregate signature.
1536 signatures - a list of signatures
1537 returns - the aggregate signature
1539 if len(signatures) == 1:
1540 return signatures[0]
1542 return MD5signature(string.join(signatures, ', '))
1546 # From Dinu C. Gherman,
1547 # Python Cookbook, second edition, recipe 6.17, p. 277.
1549 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/68205
1550 # ASPN: Python Cookbook: Null Object Design Pattern
1553 """ Null objects always and reliably "do nothging." """
1555 def __new__(cls, *args, **kwargs):
1556 if not '_inst' in vars(cls):
1557 #cls._inst = type.__new__(cls, *args, **kwargs)
1558 cls._inst = apply(type.__new__, (cls,) + args, kwargs)
1560 def __init__(self, *args, **kwargs):
1562 def __call__(self, *args, **kwargs):
1566 def __nonzero__(self):
1568 def __getattr__(self, mname):
1570 def __setattr__(self, name, value):
1572 def __delattr__(self, name):