summaryrefslogtreecommitdiff
path: root/engine/SCons/Util.py
diff options
context:
space:
mode:
Diffstat (limited to 'engine/SCons/Util.py')
-rw-r--r--engine/SCons/Util.py131
1 files changed, 81 insertions, 50 deletions
diff --git a/engine/SCons/Util.py b/engine/SCons/Util.py
index be86831..21ef53f 100644
--- a/engine/SCons/Util.py
+++ b/engine/SCons/Util.py
@@ -3,7 +3,7 @@
Various utility functions go here.
"""
#
-# Copyright (c) 2001 - 2015 The SCons Foundation
+# Copyright (c) 2001 - 2016 The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -24,7 +24,7 @@ Various utility functions go here.
# 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 rel_2.4.1:3453:73fefd3ea0b0 2015/11/09 03:25:05 bdbaddog"
+__revision__ = "src/engine/SCons/Util.py rel_2.5.0:3543:937e55cd78f7 2016/04/09 11:29:54 bdbaddog"
import os
import sys
@@ -92,7 +92,7 @@ def splitext(path):
def updrive(path):
"""
Make the drive letter (if any) upper case.
- This is useful because Windows is inconsitent on the case
+ This is useful because Windows is inconsistent on the case
of the drive letter, which can cause inconsistencies when
calculating command signatures.
"""
@@ -167,7 +167,7 @@ class DisplayEngine(object):
def set_mode(self, mode):
self.print_it = mode
-def render_tree(root, child_func, prune=0, margin=[0], visited={}):
+def render_tree(root, child_func, prune=0, margin=[0], visited=None):
"""
Render a tree of nodes into an ASCII tree view.
root - the root node of the tree
@@ -181,6 +181,10 @@ def render_tree(root, child_func, prune=0, margin=[0], visited={}):
rname = str(root)
+ # Initialize 'visited' dict, if required
+ if visited is None:
+ visited = {}
+
children = child_func(root)
retval = ""
for pipe in margin[:-1]:
@@ -207,7 +211,7 @@ def render_tree(root, child_func, prune=0, margin=[0], visited={}):
IDX = lambda N: N and 1 or 0
-def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited={}):
+def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited=None):
"""
Print a tree of nodes. This is like render_tree, except it prints
lines directly instead of creating a string representation in memory,
@@ -224,6 +228,10 @@ def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited={}):
"""
rname = str(root)
+
+ # Initialize 'visited' dict, if required
+ if visited is None:
+ visited = {}
if showtags:
@@ -291,7 +299,7 @@ def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited={}):
# often too slow.
# We are using the following trick to speed up these
-# functions. Default arguments are used to take a snapshot of the
+# functions. Default arguments are used to take a snapshot of
# 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).
@@ -301,11 +309,11 @@ 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
+# explicitly 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
+# Empirically, it is faster to check explicitly for str and
# unicode than for basestring.
BaseStringTypes = (str, unicode)
@@ -326,11 +334,11 @@ def is_String(obj, isinstance=isinstance, StringTypes=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
+ # when explicitly 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.
+ # assumes that the obj argument is a string most of the time.
return isinstance(obj, StringTypes) or not isinstance(obj, SequenceTypes)
def do_flatten(sequence, result, isinstance=isinstance,
@@ -431,7 +439,7 @@ def to_String_for_signature(obj, to_String_for_subst=to_String_for_subst,
#
# A special case is any object that has a __semi_deepcopy__() method,
# which we invoke to create the copy. Currently only used by
-# BuilderDict to actually prevent the copy operation (as invalid on that object)
+# BuilderDict to actually prevent the copy operation (as invalid on that object).
#
# The dispatch table approach used here is a direct rip-off from the
# normal Python copy module.
@@ -571,6 +579,19 @@ except ImportError:
pass
RegError = _NoError
+WinError = None
+# 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 PlainWindowsError(OSError):
+ pass
+try:
+ WinError = WindowsError
+except NameError:
+ WinError = PlainWindowsError
+
+
if can_read_reg:
HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT
HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE
@@ -604,30 +625,16 @@ if can_read_reg:
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
+ raise WinError
def RegOpenKeyEx(root, key):
- raise WindowsError
+ raise WinError
if sys.platform == 'win32':
@@ -889,6 +896,28 @@ def AppendPath(oldpath, newpath, sep = os.pathsep,
else:
return sep.join(paths)
+def AddPathIfNotExists(env_dict, key, path, sep=os.pathsep):
+ """This function will take 'key' out of the dictionary
+ 'env_dict', then add the path 'path' to that key if it is not
+ already there. This treats the value of env_dict[key] as if it
+ has a similar format to the PATH variable...a list of paths
+ separated by tokens. The 'path' will get added to the list if it
+ is not already there."""
+ try:
+ is_list = 1
+ paths = env_dict[key]
+ if not is_List(env_dict[key]):
+ paths = paths.split(sep)
+ is_list = 0
+ if os.path.normcase(path) not in list(map(os.path.normcase, paths)):
+ paths = [ path ] + paths
+ if is_list:
+ env_dict[key] = paths
+ else:
+ env_dict[key] = sep.join(paths)
+ except KeyError:
+ env_dict[key] = path
+
if sys.platform == 'cygwin':
def get_native_path(path):
"""Transforms an absolute path into a native path for the system. In
@@ -1156,38 +1185,40 @@ def uniquer_hashables(seq):
return result
+# Recipe 19.11 "Reading Lines with Continuation Characters",
+# by Alex Martelli, straight from the Python CookBook (2nd edition).
+def logical_lines(physical_lines, joiner=''.join):
+ logical_line = []
+ for line in physical_lines:
+ stripped = line.rstrip()
+ if stripped.endswith('\\'):
+ # a line which continues w/the next physical line
+ logical_line.append(stripped[:-1])
+ else:
+ # a line which does not continue, end of logical line
+ logical_line.append(line)
+ yield joiner(logical_line)
+ logical_line = []
+ if logical_line:
+ # end of sequence implies end of last logical line
+ yield joiner(logical_line)
-# 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):
+class LogicalLines(object):
+ """ Wrapper class for the logical_lines method.
+
+ Allows us to read all "logical" lines at once from a
+ given file 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)
+ result = [l for l in logical_lines(self.fileobj)]
return result
-
class UniqueList(UserList):
def __init__(self, seq = []):
UserList.__init__(self, seq)