diff options
Diffstat (limited to 'couchjs/scons/scons-local-2.0.1/SCons/Util.py')
-rw-r--r-- | couchjs/scons/scons-local-2.0.1/SCons/Util.py | 1492 |
1 files changed, 0 insertions, 1492 deletions
diff --git a/couchjs/scons/scons-local-2.0.1/SCons/Util.py b/couchjs/scons/scons-local-2.0.1/SCons/Util.py deleted file mode 100644 index 1ffbd032..00000000 --- a/couchjs/scons/scons-local-2.0.1/SCons/Util.py +++ /dev/null @@ -1,1492 +0,0 @@ -"""SCons.Util - -Various utility functions go here. -""" -# -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY -# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -__revision__ = "src/engine/SCons/Util.py 5134 2010/08/16 23:02:40 bdeegan" - -import os -import sys -import copy -import re -import types - -from collections import UserDict, UserList, UserString - -# Don't "from types import ..." these because we need to get at the -# types module later to look for UnicodeType. -InstanceType = types.InstanceType -MethodType = types.MethodType -FunctionType = types.FunctionType -try: unicode -except NameError: UnicodeType = None -else: UnicodeType = unicode - -def dictify(keys, values, result={}): - for k, v in zip(keys, values): - result[k] = v - return result - -_altsep = os.altsep -if _altsep is None and sys.platform == 'win32': - # My ActivePython 2.0.1 doesn't set os.altsep! What gives? - _altsep = '/' -if _altsep: - def rightmost_separator(path, sep): - return max(path.rfind(sep), path.rfind(_altsep)) -else: - def rightmost_separator(path, sep): - return path.rfind(sep) - -# First two from the Python Cookbook, just for completeness. -# (Yeah, yeah, YAGNI...) -def containsAny(str, set): - """Check whether sequence str contains ANY of the items in set.""" - for c in set: - if c in str: return 1 - return 0 - -def containsAll(str, set): - """Check whether sequence str contains ALL of the items in set.""" - for c in set: - if c not in str: return 0 - return 1 - -def containsOnly(str, set): - """Check whether sequence str contains ONLY items in set.""" - for c in str: - if c not in set: return 0 - return 1 - -def splitext(path): - "Same as os.path.splitext() but faster." - sep = rightmost_separator(path, os.sep) - dot = path.rfind('.') - # An ext is only real if it has at least one non-digit char - if dot > sep and not containsOnly(path[dot:], "0123456789."): - return path[:dot],path[dot:] - else: - return path,"" - -def updrive(path): - """ - Make the drive letter (if any) upper case. - This is useful because Windows is inconsitent on the case - of the drive letter, which can cause inconsistencies when - calculating command signatures. - """ - drive, rest = os.path.splitdrive(path) - if drive: - path = drive.upper() + rest - return path - -class NodeList(UserList): - """This class is almost exactly like a regular list of Nodes - (actually it can hold any object), with one important difference. - If you try to get an attribute from this list, it will return that - attribute from every item in the list. For example: - - >>> someList = NodeList([ ' foo ', ' bar ' ]) - >>> someList.strip() - [ 'foo', 'bar' ] - """ - def __nonzero__(self): - return len(self.data) != 0 - - def __str__(self): - return ' '.join(map(str, self.data)) - - def __iter__(self): - return iter(self.data) - - def __call__(self, *args, **kwargs): - result = [x(*args, **kwargs) for x in self.data] - return self.__class__(result) - - def __getattr__(self, name): - result = [getattr(x, name) for x in self.data] - return self.__class__(result) - - -_get_env_var = re.compile(r'^\$([_a-zA-Z]\w*|{[_a-zA-Z]\w*})$') - -def get_environment_var(varstr): - """Given a string, first determine if it looks like a reference - to a single environment variable, like "$FOO" or "${FOO}". - If so, return that variable with no decorations ("FOO"). - If not, return None.""" - mo=_get_env_var.match(to_String(varstr)) - if mo: - var = mo.group(1) - if var[0] == '{': - return var[1:-1] - else: - return var - else: - return None - -class DisplayEngine(object): - print_it = True - def __call__(self, text, append_newline=1): - if not self.print_it: - return - if append_newline: text = text + '\n' - try: - sys.stdout.write(unicode(text)) - except IOError: - # Stdout might be connected to a pipe that has been closed - # by now. The most likely reason for the pipe being closed - # is that the user has press ctrl-c. It this is the case, - # then SCons is currently shutdown. We therefore ignore - # IOError's here so that SCons can continue and shutdown - # properly so that the .sconsign is correctly written - # before SCons exits. - pass - - def set_mode(self, mode): - self.print_it = mode - -def render_tree(root, child_func, prune=0, margin=[0], visited={}): - """ - Render a tree of nodes into an ASCII tree view. - root - the root node of the tree - child_func - the function called to get the children of a node - prune - don't visit the same node twice - margin - the format of the left margin to use for children of root. - 1 results in a pipe, and 0 results in no pipe. - visited - a dictionary of visited nodes in the current branch if not prune, - or in the whole tree if prune. - """ - - rname = str(root) - - children = child_func(root) - retval = "" - for pipe in margin[:-1]: - if pipe: - retval = retval + "| " - else: - retval = retval + " " - - if rname in visited: - return retval + "+-[" + rname + "]\n" - - retval = retval + "+-" + rname + "\n" - if not prune: - visited = copy.copy(visited) - visited[rname] = 1 - - for i in range(len(children)): - margin.append(i<len(children)-1) - retval = retval + render_tree(children[i], child_func, prune, margin, visited -) - margin.pop() - - return retval - -IDX = lambda N: N and 1 or 0 - -def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited={}): - """ - Print a tree of nodes. This is like render_tree, except it prints - lines directly instead of creating a string representation in memory, - so that huge trees can be printed. - - root - the root node of the tree - child_func - the function called to get the children of a node - prune - don't visit the same node twice - showtags - print status information to the left of each node line - margin - the format of the left margin to use for children of root. - 1 results in a pipe, and 0 results in no pipe. - visited - a dictionary of visited nodes in the current branch if not prune, - or in the whole tree if prune. - """ - - rname = str(root) - - if showtags: - - if showtags == 2: - legend = (' E = exists\n' + - ' R = exists in repository only\n' + - ' b = implicit builder\n' + - ' B = explicit builder\n' + - ' S = side effect\n' + - ' P = precious\n' + - ' A = always build\n' + - ' C = current\n' + - ' N = no clean\n' + - ' H = no cache\n' + - '\n') - sys.stdout.write(unicode(legend)) - - tags = ['['] - tags.append(' E'[IDX(root.exists())]) - tags.append(' R'[IDX(root.rexists() and not root.exists())]) - tags.append(' BbB'[[0,1][IDX(root.has_explicit_builder())] + - [0,2][IDX(root.has_builder())]]) - tags.append(' S'[IDX(root.side_effect)]) - tags.append(' P'[IDX(root.precious)]) - tags.append(' A'[IDX(root.always_build)]) - tags.append(' C'[IDX(root.is_up_to_date())]) - tags.append(' N'[IDX(root.noclean)]) - tags.append(' H'[IDX(root.nocache)]) - tags.append(']') - - else: - tags = [] - - def MMM(m): - return [" ","| "][m] - margins = list(map(MMM, margin[:-1])) - - children = child_func(root) - - if prune and rname in visited and children: - sys.stdout.write(''.join(tags + margins + ['+-[', rname, ']']) + u'\n') - return - - sys.stdout.write(''.join(tags + margins + ['+-', rname]) + u'\n') - - visited[rname] = 1 - - if children: - margin.append(1) - idx = IDX(showtags) - for C in children[:-1]: - print_tree(C, child_func, prune, idx, margin, visited) - margin[-1] = 0 - print_tree(children[-1], child_func, prune, idx, margin, visited) - margin.pop() - - - -# Functions for deciding if things are like various types, mainly to -# handle UserDict, UserList and UserString like their underlying types. -# -# Yes, all of this manual testing breaks polymorphism, and the real -# Pythonic way to do all of this would be to just try it and handle the -# exception, but handling the exception when it's not the right type is -# often too slow. - -# We are using the following trick to speed up these -# functions. Default arguments are used to take a snapshot of the -# the global functions and constants used by these functions. This -# transforms accesses to global variable into local variables -# accesses (i.e. LOAD_FAST instead of LOAD_GLOBAL). - -DictTypes = (dict, UserDict) -ListTypes = (list, UserList) -SequenceTypes = (list, tuple, UserList) - -# Note that profiling data shows a speed-up when comparing -# explicitely with str and unicode instead of simply comparing -# with basestring. (at least on Python 2.5.1) -StringTypes = (str, unicode, UserString) - -# Empirically, it is faster to check explicitely for str and -# unicode than for basestring. -BaseStringTypes = (str, unicode) - -def is_Dict(obj, isinstance=isinstance, DictTypes=DictTypes): - return isinstance(obj, DictTypes) - -def is_List(obj, isinstance=isinstance, ListTypes=ListTypes): - return isinstance(obj, ListTypes) - -def is_Sequence(obj, isinstance=isinstance, SequenceTypes=SequenceTypes): - return isinstance(obj, SequenceTypes) - -def is_Tuple(obj, isinstance=isinstance, tuple=tuple): - return isinstance(obj, tuple) - -def is_String(obj, isinstance=isinstance, StringTypes=StringTypes): - return isinstance(obj, StringTypes) - -def is_Scalar(obj, isinstance=isinstance, StringTypes=StringTypes, SequenceTypes=SequenceTypes): - # Profiling shows that there is an impressive speed-up of 2x - # when explicitely checking for strings instead of just not - # sequence when the argument (i.e. obj) is already a string. - # But, if obj is a not string then it is twice as fast to - # check only for 'not sequence'. The following code therefore - # assumes that the obj argument is a string must of the time. - return isinstance(obj, StringTypes) or not isinstance(obj, SequenceTypes) - -def do_flatten(sequence, result, isinstance=isinstance, - StringTypes=StringTypes, SequenceTypes=SequenceTypes): - for item in sequence: - if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes): - result.append(item) - else: - do_flatten(item, result) - -def flatten(obj, isinstance=isinstance, StringTypes=StringTypes, - SequenceTypes=SequenceTypes, do_flatten=do_flatten): - """Flatten a sequence to a non-nested list. - - Flatten() converts either a single scalar or a nested sequence - to a non-nested list. Note that flatten() considers strings - to be scalars instead of sequences like Python would. - """ - if isinstance(obj, StringTypes) or not isinstance(obj, SequenceTypes): - return [obj] - result = [] - for item in obj: - if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes): - result.append(item) - else: - do_flatten(item, result) - return result - -def flatten_sequence(sequence, isinstance=isinstance, StringTypes=StringTypes, - SequenceTypes=SequenceTypes, do_flatten=do_flatten): - """Flatten a sequence to a non-nested list. - - Same as flatten(), but it does not handle the single scalar - case. This is slightly more efficient when one knows that - the sequence to flatten can not be a scalar. - """ - result = [] - for item in sequence: - if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes): - result.append(item) - else: - do_flatten(item, result) - return result - -# Generic convert-to-string functions that abstract away whether or -# not the Python we're executing has Unicode support. The wrapper -# to_String_for_signature() will use a for_signature() method if the -# specified object has one. -# -def to_String(s, - isinstance=isinstance, str=str, - UserString=UserString, BaseStringTypes=BaseStringTypes): - if isinstance(s,BaseStringTypes): - # Early out when already a string! - return s - elif isinstance(s, UserString): - # s.data can only be either a unicode or a regular - # string. Please see the UserString initializer. - return s.data - else: - return str(s) - -def to_String_for_subst(s, - isinstance=isinstance, str=str, to_String=to_String, - BaseStringTypes=BaseStringTypes, SequenceTypes=SequenceTypes, - UserString=UserString): - - # Note that the test cases are sorted by order of probability. - if isinstance(s, BaseStringTypes): - return s - elif isinstance(s, SequenceTypes): - l = [] - for e in s: - l.append(to_String_for_subst(e)) - return ' '.join( s ) - elif isinstance(s, UserString): - # s.data can only be either a unicode or a regular - # string. Please see the UserString initializer. - return s.data - else: - return str(s) - -def to_String_for_signature(obj, to_String_for_subst=to_String_for_subst, - AttributeError=AttributeError): - try: - f = obj.for_signature - except AttributeError: - return to_String_for_subst(obj) - else: - return f() - - -# The SCons "semi-deep" copy. -# -# This makes separate copies of lists (including UserList objects) -# dictionaries (including UserDict objects) and tuples, but just copies -# references to anything else it finds. -# -# A special case is any object that has a __semi_deepcopy__() method, -# which we invoke to create the copy, which is used by the BuilderDict -# class because of its extra initialization argument. -# -# The dispatch table approach used here is a direct rip-off from the -# normal Python copy module. - -_semi_deepcopy_dispatch = d = {} - -def _semi_deepcopy_dict(x): - copy = {} - for key, val in x.items(): - # The regular Python copy.deepcopy() also deepcopies the key, - # as follows: - # - # copy[semi_deepcopy(key)] = semi_deepcopy(val) - # - # Doesn't seem like we need to, but we'll comment it just in case. - copy[key] = semi_deepcopy(val) - return copy -d[dict] = _semi_deepcopy_dict - -def _semi_deepcopy_list(x): - return list(map(semi_deepcopy, x)) -d[list] = _semi_deepcopy_list - -def _semi_deepcopy_tuple(x): - return tuple(map(semi_deepcopy, x)) -d[tuple] = _semi_deepcopy_tuple - -def semi_deepcopy(x): - copier = _semi_deepcopy_dispatch.get(type(x)) - if copier: - return copier(x) - else: - if hasattr(x, '__semi_deepcopy__'): - return x.__semi_deepcopy__() - elif isinstance(x, UserDict): - return x.__class__(_semi_deepcopy_dict(x)) - elif isinstance(x, UserList): - return x.__class__(_semi_deepcopy_list(x)) - - return x - - - -class Proxy(object): - """A simple generic Proxy class, forwarding all calls to - subject. So, for the benefit of the python newbie, what does - this really mean? Well, it means that you can take an object, let's - call it 'objA', and wrap it in this Proxy class, with a statement - like this - - proxyObj = Proxy(objA), - - Then, if in the future, you do something like this - - x = proxyObj.var1, - - since Proxy does not have a 'var1' attribute (but presumably objA does), - the request actually is equivalent to saying - - x = objA.var1 - - Inherit from this class to create a Proxy. - - Note that, with new-style classes, this does *not* work transparently - for Proxy subclasses that use special .__*__() method names, because - those names are now bound to the class, not the individual instances. - You now need to know in advance which .__*__() method names you want - to pass on to the underlying Proxy object, and specifically delegate - their calls like this: - - class Foo(Proxy): - __str__ = Delegate('__str__') - """ - - def __init__(self, subject): - """Wrap an object as a Proxy object""" - self._subject = subject - - def __getattr__(self, name): - """Retrieve an attribute from the wrapped object. If the named - attribute doesn't exist, AttributeError is raised""" - return getattr(self._subject, name) - - def get(self): - """Retrieve the entire wrapped object""" - return self._subject - - def __cmp__(self, other): - if issubclass(other.__class__, self._subject.__class__): - return cmp(self._subject, other) - return cmp(self.__dict__, other.__dict__) - -class Delegate(object): - """A Python Descriptor class that delegates attribute fetches - to an underlying wrapped subject of a Proxy. Typical use: - - class Foo(Proxy): - __str__ = Delegate('__str__') - """ - def __init__(self, attribute): - self.attribute = attribute - def __get__(self, obj, cls): - if isinstance(obj, cls): - return getattr(obj._subject, self.attribute) - else: - return self - -# attempt to load the windows registry module: -can_read_reg = 0 -try: - import winreg - - can_read_reg = 1 - hkey_mod = winreg - - RegOpenKeyEx = winreg.OpenKeyEx - RegEnumKey = winreg.EnumKey - RegEnumValue = winreg.EnumValue - RegQueryValueEx = winreg.QueryValueEx - RegError = winreg.error - -except ImportError: - try: - import win32api - import win32con - can_read_reg = 1 - hkey_mod = win32con - - RegOpenKeyEx = win32api.RegOpenKeyEx - RegEnumKey = win32api.RegEnumKey - RegEnumValue = win32api.RegEnumValue - RegQueryValueEx = win32api.RegQueryValueEx - RegError = win32api.error - - except ImportError: - class _NoError(Exception): - pass - RegError = _NoError - -if can_read_reg: - HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT - HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE - HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER - HKEY_USERS = hkey_mod.HKEY_USERS - - def RegGetValue(root, key): - """This utility function returns a value in the registry - without having to open the key first. Only available on - Windows platforms with a version of Python that can read the - registry. Returns the same thing as - SCons.Util.RegQueryValueEx, except you just specify the entire - path to the value, and don't have to bother opening the key - first. So: - - Instead of: - k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, - r'SOFTWARE\Microsoft\Windows\CurrentVersion') - out = SCons.Util.RegQueryValueEx(k, - 'ProgramFilesDir') - - You can write: - out = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE, - r'SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir') - """ - # I would use os.path.split here, but it's not a filesystem - # path... - p = key.rfind('\\') + 1 - keyp = key[:p-1] # -1 to omit trailing slash - val = key[p:] - k = RegOpenKeyEx(root, keyp) - return RegQueryValueEx(k,val) -else: - try: - e = WindowsError - except NameError: - # Make sure we have a definition of WindowsError so we can - # run platform-independent tests of Windows functionality on - # platforms other than Windows. (WindowsError is, in fact, an - # OSError subclass on Windows.) - class WindowsError(OSError): - pass - import builtins - builtins.WindowsError = WindowsError - else: - del e - - HKEY_CLASSES_ROOT = None - HKEY_LOCAL_MACHINE = None - HKEY_CURRENT_USER = None - HKEY_USERS = None - - def RegGetValue(root, key): - raise WindowsError - - def RegOpenKeyEx(root, key): - raise WindowsError - -if sys.platform == 'win32': - - def WhereIs(file, path=None, pathext=None, reject=[]): - if path is None: - try: - path = os.environ['PATH'] - except KeyError: - return None - if is_String(path): - path = path.split(os.pathsep) - if pathext is None: - try: - pathext = os.environ['PATHEXT'] - except KeyError: - pathext = '.COM;.EXE;.BAT;.CMD' - if is_String(pathext): - pathext = pathext.split(os.pathsep) - for ext in pathext: - if ext.lower() == file[-len(ext):].lower(): - pathext = [''] - break - if not is_List(reject) and not is_Tuple(reject): - reject = [reject] - for dir in path: - f = os.path.join(dir, file) - for ext in pathext: - fext = f + ext - if os.path.isfile(fext): - try: - reject.index(fext) - except ValueError: - return os.path.normpath(fext) - continue - return None - -elif os.name == 'os2': - - def WhereIs(file, path=None, pathext=None, reject=[]): - if path is None: - try: - path = os.environ['PATH'] - except KeyError: - return None - if is_String(path): - path = path.split(os.pathsep) - if pathext is None: - pathext = ['.exe', '.cmd'] - for ext in pathext: - if ext.lower() == file[-len(ext):].lower(): - pathext = [''] - break - if not is_List(reject) and not is_Tuple(reject): - reject = [reject] - for dir in path: - f = os.path.join(dir, file) - for ext in pathext: - fext = f + ext - if os.path.isfile(fext): - try: - reject.index(fext) - except ValueError: - return os.path.normpath(fext) - continue - return None - -else: - - def WhereIs(file, path=None, pathext=None, reject=[]): - import stat - if path is None: - try: - path = os.environ['PATH'] - except KeyError: - return None - if is_String(path): - path = path.split(os.pathsep) - if not is_List(reject) and not is_Tuple(reject): - reject = [reject] - for d in path: - f = os.path.join(d, file) - if os.path.isfile(f): - try: - st = os.stat(f) - except OSError: - # os.stat() raises OSError, not IOError if the file - # doesn't exist, so in this case we let IOError get - # raised so as to not mask possibly serious disk or - # network issues. - continue - if stat.S_IMODE(st[stat.ST_MODE]) & 0111: - try: - reject.index(f) - except ValueError: - return os.path.normpath(f) - continue - return None - -def PrependPath(oldpath, newpath, sep = os.pathsep, - delete_existing=1, canonicalize=None): - """This prepends newpath elements to the given oldpath. Will only - add any particular path once (leaving the first one it encounters - and ignoring the rest, to preserve path order), and will - os.path.normpath and os.path.normcase all paths to help assure - this. This can also handle the case where the given old path - variable is a list instead of a string, in which case a list will - be returned instead of a string. - - Example: - Old Path: "/foo/bar:/foo" - New Path: "/biz/boom:/foo" - Result: "/biz/boom:/foo:/foo/bar" - - If delete_existing is 0, then adding a path that exists will - not move it to the beginning; it will stay where it is in the - list. - - If canonicalize is not None, it is applied to each element of - newpath before use. - """ - - orig = oldpath - is_list = 1 - paths = orig - if not is_List(orig) and not is_Tuple(orig): - paths = paths.split(sep) - is_list = 0 - - if is_String(newpath): - newpaths = newpath.split(sep) - elif not is_List(newpath) and not is_Tuple(newpath): - newpaths = [ newpath ] # might be a Dir - else: - newpaths = newpath - - if canonicalize: - newpaths=list(map(canonicalize, newpaths)) - - if not delete_existing: - # First uniquify the old paths, making sure to - # preserve the first instance (in Unix/Linux, - # the first one wins), and remembering them in normpaths. - # Then insert the new paths at the head of the list - # if they're not already in the normpaths list. - result = [] - normpaths = [] - for path in paths: - if not path: - continue - normpath = os.path.normpath(os.path.normcase(path)) - if normpath not in normpaths: - result.append(path) - normpaths.append(normpath) - newpaths.reverse() # since we're inserting at the head - for path in newpaths: - if not path: - continue - normpath = os.path.normpath(os.path.normcase(path)) - if normpath not in normpaths: - result.insert(0, path) - normpaths.append(normpath) - paths = result - - else: - newpaths = newpaths + paths # prepend new paths - - normpaths = [] - paths = [] - # now we add them only if they are unique - for path in newpaths: - normpath = os.path.normpath(os.path.normcase(path)) - if path and not normpath in normpaths: - paths.append(path) - normpaths.append(normpath) - - if is_list: - return paths - else: - return sep.join(paths) - -def AppendPath(oldpath, newpath, sep = os.pathsep, - delete_existing=1, canonicalize=None): - """This appends new path elements to the given old path. Will - only add any particular path once (leaving the last one it - encounters and ignoring the rest, to preserve path order), and - will os.path.normpath and os.path.normcase all paths to help - assure this. This can also handle the case where the given old - path variable is a list instead of a string, in which case a list - will be returned instead of a string. - - Example: - Old Path: "/foo/bar:/foo" - New Path: "/biz/boom:/foo" - Result: "/foo/bar:/biz/boom:/foo" - - If delete_existing is 0, then adding a path that exists - will not move it to the end; it will stay where it is in the list. - - If canonicalize is not None, it is applied to each element of - newpath before use. - """ - - orig = oldpath - is_list = 1 - paths = orig - if not is_List(orig) and not is_Tuple(orig): - paths = paths.split(sep) - is_list = 0 - - if is_String(newpath): - newpaths = newpath.split(sep) - elif not is_List(newpath) and not is_Tuple(newpath): - newpaths = [ newpath ] # might be a Dir - else: - newpaths = newpath - - if canonicalize: - newpaths=list(map(canonicalize, newpaths)) - - if not delete_existing: - # add old paths to result, then - # add new paths if not already present - # (I thought about using a dict for normpaths for speed, - # but it's not clear hashing the strings would be faster - # than linear searching these typically short lists.) - result = [] - normpaths = [] - for path in paths: - if not path: - continue - result.append(path) - normpaths.append(os.path.normpath(os.path.normcase(path))) - for path in newpaths: - if not path: - continue - normpath = os.path.normpath(os.path.normcase(path)) - if normpath not in normpaths: - result.append(path) - normpaths.append(normpath) - paths = result - else: - # start w/ new paths, add old ones if not present, - # then reverse. - newpaths = paths + newpaths # append new paths - newpaths.reverse() - - normpaths = [] - paths = [] - # now we add them only if they are unique - for path in newpaths: - normpath = os.path.normpath(os.path.normcase(path)) - if path and not normpath in normpaths: - paths.append(path) - normpaths.append(normpath) - paths.reverse() - - if is_list: - return paths - else: - return sep.join(paths) - -if sys.platform == 'cygwin': - def get_native_path(path): - """Transforms an absolute path into a native path for the system. In - Cygwin, this converts from a Cygwin path to a Windows one.""" - return os.popen('cygpath -w ' + path).read().replace('\n', '') -else: - def get_native_path(path): - """Transforms an absolute path into a native path for the system. - Non-Cygwin version, just leave the path alone.""" - return path - -display = DisplayEngine() - -def Split(arg): - if is_List(arg) or is_Tuple(arg): - return arg - elif is_String(arg): - return arg.split() - else: - return [arg] - -class CLVar(UserList): - """A class for command-line construction variables. - - This is a list that uses Split() to split an initial string along - white-space arguments, and similarly to split any strings that get - added. This allows us to Do the Right Thing with Append() and - Prepend() (as well as straight Python foo = env['VAR'] + 'arg1 - arg2') regardless of whether a user adds a list or a string to a - command-line construction variable. - """ - def __init__(self, seq = []): - UserList.__init__(self, Split(seq)) - def __add__(self, other): - return UserList.__add__(self, CLVar(other)) - def __radd__(self, other): - return UserList.__radd__(self, CLVar(other)) - def __coerce__(self, other): - return (self, CLVar(other)) - def __str__(self): - return ' '.join(self.data) - -# A dictionary that preserves the order in which items are added. -# Submitted by David Benjamin to ActiveState's Python Cookbook web site: -# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/107747 -# Including fixes/enhancements from the follow-on discussions. -class OrderedDict(UserDict): - def __init__(self, dict = None): - self._keys = [] - UserDict.__init__(self, dict) - - def __delitem__(self, key): - UserDict.__delitem__(self, key) - self._keys.remove(key) - - def __setitem__(self, key, item): - UserDict.__setitem__(self, key, item) - if key not in self._keys: self._keys.append(key) - - def clear(self): - UserDict.clear(self) - self._keys = [] - - def copy(self): - dict = OrderedDict() - dict.update(self) - return dict - - def items(self): - return list(zip(self._keys, list(self.values()))) - - def keys(self): - return self._keys[:] - - def popitem(self): - try: - key = self._keys[-1] - except IndexError: - raise KeyError('dictionary is empty') - - val = self[key] - del self[key] - - return (key, val) - - def setdefault(self, key, failobj = None): - UserDict.setdefault(self, key, failobj) - if key not in self._keys: self._keys.append(key) - - def update(self, dict): - for (key, val) in dict.items(): - self.__setitem__(key, val) - - def values(self): - return list(map(self.get, self._keys)) - -class Selector(OrderedDict): - """A callable ordered dictionary that maps file suffixes to - dictionary values. We preserve the order in which items are added - so that get_suffix() calls always return the first suffix added.""" - def __call__(self, env, source, ext=None): - if ext is None: - try: - ext = source[0].suffix - except IndexError: - ext = "" - try: - return self[ext] - except KeyError: - # Try to perform Environment substitution on the keys of - # the dictionary before giving up. - s_dict = {} - for (k,v) in self.items(): - if k is not None: - s_k = env.subst(k) - if s_k in s_dict: - # We only raise an error when variables point - # to the same suffix. If one suffix is literal - # and a variable suffix contains this literal, - # the literal wins and we don't raise an error. - raise KeyError(s_dict[s_k][0], k, s_k) - s_dict[s_k] = (k,v) - try: - return s_dict[ext][1] - except KeyError: - try: - return self[None] - except KeyError: - return None - - -if sys.platform == 'cygwin': - # On Cygwin, os.path.normcase() lies, so just report back the - # fact that the underlying Windows OS is case-insensitive. - def case_sensitive_suffixes(s1, s2): - return 0 -else: - def case_sensitive_suffixes(s1, s2): - return (os.path.normcase(s1) != os.path.normcase(s2)) - -def adjustixes(fname, pre, suf, ensure_suffix=False): - if pre: - path, fn = os.path.split(os.path.normpath(fname)) - if fn[:len(pre)] != pre: - fname = os.path.join(path, pre + fn) - # Only append a suffix if the suffix we're going to add isn't already - # there, and if either we've been asked to ensure the specific suffix - # is present or there's no suffix on it at all. - if suf and fname[-len(suf):] != suf and \ - (ensure_suffix or not splitext(fname)[1]): - fname = fname + suf - return fname - - - -# From Tim Peters, -# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560 -# ASPN: Python Cookbook: Remove duplicates from a sequence -# (Also in the printed Python Cookbook.) - -def unique(s): - """Return a list of the elements in s, but without duplicates. - - For example, unique([1,2,3,1,2,3]) is some permutation of [1,2,3], - unique("abcabc") some permutation of ["a", "b", "c"], and - unique(([1, 2], [2, 3], [1, 2])) some permutation of - [[2, 3], [1, 2]]. - - For best speed, all sequence elements should be hashable. Then - unique() will usually work in linear time. - - If not possible, the sequence elements should enjoy a total - ordering, and if list(s).sort() doesn't raise TypeError it's - assumed that they do enjoy a total ordering. Then unique() will - usually work in O(N*log2(N)) time. - - If that's not possible either, the sequence elements must support - equality-testing. Then unique() will usually work in quadratic - time. - """ - - n = len(s) - if n == 0: - return [] - - # Try using a dict first, as that's the fastest and will usually - # work. If it doesn't work, it will usually fail quickly, so it - # usually doesn't cost much to *try* it. It requires that all the - # sequence elements be hashable, and support equality comparison. - u = {} - try: - for x in s: - u[x] = 1 - except TypeError: - pass # move on to the next method - else: - return list(u.keys()) - del u - - # We can't hash all the elements. Second fastest is to sort, - # which brings the equal elements together; then duplicates are - # easy to weed out in a single pass. - # NOTE: Python's list.sort() was designed to be efficient in the - # presence of many duplicate elements. This isn't true of all - # sort functions in all languages or libraries, so this approach - # is more effective in Python than it may be elsewhere. - try: - t = sorted(s) - except TypeError: - pass # move on to the next method - else: - assert n > 0 - last = t[0] - lasti = i = 1 - while i < n: - if t[i] != last: - t[lasti] = last = t[i] - lasti = lasti + 1 - i = i + 1 - return t[:lasti] - del t - - # Brute force is all that's left. - u = [] - for x in s: - if x not in u: - u.append(x) - return u - - - -# From Alex Martelli, -# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560 -# ASPN: Python Cookbook: Remove duplicates from a sequence -# First comment, dated 2001/10/13. -# (Also in the printed Python Cookbook.) - -def uniquer(seq, idfun=None): - if idfun is None: - def idfun(x): return x - seen = {} - result = [] - for item in seq: - marker = idfun(item) - # in old Python versions: - # if seen.has_key(marker) - # but in new ones: - if marker in seen: continue - seen[marker] = 1 - result.append(item) - return result - -# A more efficient implementation of Alex's uniquer(), this avoids the -# idfun() argument and function-call overhead by assuming that all -# items in the sequence are hashable. - -def uniquer_hashables(seq): - seen = {} - result = [] - for item in seq: - #if not item in seen: - if item not in seen: - seen[item] = 1 - result.append(item) - return result - - - -# Much of the logic here was originally based on recipe 4.9 from the -# Python CookBook, but we had to dumb it way down for Python 1.5.2. -class LogicalLines(object): - - def __init__(self, fileobj): - self.fileobj = fileobj - - def readline(self): - result = [] - while True: - line = self.fileobj.readline() - if not line: - break - if line[-2:] == '\\\n': - result.append(line[:-2]) - else: - result.append(line) - break - return ''.join(result) - - def readlines(self): - result = [] - while True: - line = self.readline() - if not line: - break - result.append(line) - return result - - - -class UniqueList(UserList): - def __init__(self, seq = []): - UserList.__init__(self, seq) - self.unique = True - def __make_unique(self): - if not self.unique: - self.data = uniquer_hashables(self.data) - self.unique = True - def __lt__(self, other): - self.__make_unique() - return UserList.__lt__(self, other) - def __le__(self, other): - self.__make_unique() - return UserList.__le__(self, other) - def __eq__(self, other): - self.__make_unique() - return UserList.__eq__(self, other) - def __ne__(self, other): - self.__make_unique() - return UserList.__ne__(self, other) - def __gt__(self, other): - self.__make_unique() - return UserList.__gt__(self, other) - def __ge__(self, other): - self.__make_unique() - return UserList.__ge__(self, other) - def __cmp__(self, other): - self.__make_unique() - return UserList.__cmp__(self, other) - def __len__(self): - self.__make_unique() - return UserList.__len__(self) - def __getitem__(self, i): - self.__make_unique() - return UserList.__getitem__(self, i) - def __setitem__(self, i, item): - UserList.__setitem__(self, i, item) - self.unique = False - def __getslice__(self, i, j): - self.__make_unique() - return UserList.__getslice__(self, i, j) - def __setslice__(self, i, j, other): - UserList.__setslice__(self, i, j, other) - self.unique = False - def __add__(self, other): - result = UserList.__add__(self, other) - result.unique = False - return result - def __radd__(self, other): - result = UserList.__radd__(self, other) - result.unique = False - return result - def __iadd__(self, other): - result = UserList.__iadd__(self, other) - result.unique = False - return result - def __mul__(self, other): - result = UserList.__mul__(self, other) - result.unique = False - return result - def __rmul__(self, other): - result = UserList.__rmul__(self, other) - result.unique = False - return result - def __imul__(self, other): - result = UserList.__imul__(self, other) - result.unique = False - return result - def append(self, item): - UserList.append(self, item) - self.unique = False - def insert(self, i): - UserList.insert(self, i) - self.unique = False - def count(self, item): - self.__make_unique() - return UserList.count(self, item) - def index(self, item): - self.__make_unique() - return UserList.index(self, item) - def reverse(self): - self.__make_unique() - UserList.reverse(self) - def sort(self, *args, **kwds): - self.__make_unique() - return UserList.sort(self, *args, **kwds) - def extend(self, other): - UserList.extend(self, other) - self.unique = False - - -class Unbuffered(object): - """ - A proxy class that wraps a file object, flushing after every write, - and delegating everything else to the wrapped object. - """ - def __init__(self, file): - self.file = file - self.softspace = 0 ## backward compatibility; not supported in Py3k - def write(self, arg): - try: - self.file.write(arg) - self.file.flush() - except IOError: - # Stdout might be connected to a pipe that has been closed - # by now. The most likely reason for the pipe being closed - # is that the user has press ctrl-c. It this is the case, - # then SCons is currently shutdown. We therefore ignore - # IOError's here so that SCons can continue and shutdown - # properly so that the .sconsign is correctly written - # before SCons exits. - pass - def __getattr__(self, attr): - return getattr(self.file, attr) - -def make_path_relative(path): - """ makes an absolute path name to a relative pathname. - """ - if os.path.isabs(path): - drive_s,path = os.path.splitdrive(path) - - import re - if not drive_s: - path=re.compile("/*(.*)").findall(path)[0] - else: - path=path[1:] - - assert( not os.path.isabs( path ) ), path - return path - - - -# The original idea for AddMethod() and RenameFunction() come from the -# following post to the ActiveState Python Cookbook: -# -# ASPN: Python Cookbook : Install bound methods in an instance -# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/223613 -# -# That code was a little fragile, though, so the following changes -# have been wrung on it: -# -# * Switched the installmethod() "object" and "function" arguments, -# so the order reflects that the left-hand side is the thing being -# "assigned to" and the right-hand side is the value being assigned. -# -# * Changed explicit type-checking to the "try: klass = object.__class__" -# block in installmethod() below so that it still works with the -# old-style classes that SCons uses. -# -# * Replaced the by-hand creation of methods and functions with use of -# the "new" module, as alluded to in Alex Martelli's response to the -# following Cookbook post: -# -# ASPN: Python Cookbook : Dynamically added methods to a class -# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81732 - -def AddMethod(obj, function, name=None): - """ - Adds either a bound method to an instance or an unbound method to - a class. If name is ommited the name of the specified function - is used by default. - Example: - a = A() - def f(self, x, y): - self.z = x + y - AddMethod(f, A, "add") - a.add(2, 4) - print a.z - AddMethod(lambda self, i: self.l[i], a, "listIndex") - print a.listIndex(5) - """ - if name is None: - name = function.func_name - else: - function = RenameFunction(function, name) - - if hasattr(obj, '__class__') and obj.__class__ is not type: - # "obj" is an instance, so it gets a bound method. - setattr(obj, name, MethodType(function, obj, obj.__class__)) - else: - # "obj" is a class, so it gets an unbound method. - setattr(obj, name, MethodType(function, None, obj)) - -def RenameFunction(function, name): - """ - Returns a function identical to the specified function, but with - the specified name. - """ - return FunctionType(function.func_code, - function.func_globals, - name, - function.func_defaults) - - -md5 = False -def MD5signature(s): - return str(s) - -def MD5filesignature(fname, chunksize=65536): - f = open(fname, "rb") - result = f.read() - f.close() - return result - -try: - import hashlib -except ImportError: - pass -else: - if hasattr(hashlib, 'md5'): - md5 = True - def MD5signature(s): - m = hashlib.md5() - m.update(str(s)) - return m.hexdigest() - - def MD5filesignature(fname, chunksize=65536): - m = hashlib.md5() - f = open(fname, "rb") - while True: - blck = f.read(chunksize) - if not blck: - break - m.update(str(blck)) - f.close() - return m.hexdigest() - -def MD5collect(signatures): - """ - Collects a list of signatures into an aggregate signature. - - signatures - a list of signatures - returns - the aggregate signature - """ - if len(signatures) == 1: - return signatures[0] - else: - return MD5signature(', '.join(signatures)) - - - -def silent_intern(x): - """ - Perform sys.intern() on the passed argument and return the result. - If the input is ineligible (e.g. a unicode string) the original argument is - returned and no exception is thrown. - """ - try: - return sys.intern(x) - except TypeError: - return x - - - -# From Dinu C. Gherman, -# Python Cookbook, second edition, recipe 6.17, p. 277. -# Also: -# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/68205 -# ASPN: Python Cookbook: Null Object Design Pattern - -#TODO??? class Null(object): -class Null(object): - """ Null objects always and reliably "do nothing." """ - def __new__(cls, *args, **kwargs): - if not '_instance' in vars(cls): - cls._instance = super(Null, cls).__new__(cls, *args, **kwargs) - return cls._instance - def __init__(self, *args, **kwargs): - pass - def __call__(self, *args, **kwargs): - return self - def __repr__(self): - return "Null(0x%08X)" % id(self) - def __nonzero__(self): - return False - def __getattr__(self, name): - return self - def __setattr__(self, name, value): - return self - def __delattr__(self, name): - return self - -class NullSeq(Null): - def __len__(self): - return 0 - def __iter__(self): - return iter(()) - def __getitem__(self, i): - return self - def __delitem__(self, i): - return self - def __setitem__(self, i, v): - return self - - -del __revision__ - -# Local Variables: -# tab-width:4 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=4 shiftwidth=4: |