summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/CHANGES.txt8
-rw-r--r--src/engine/SCons/Node/FS.py20
-rw-r--r--src/engine/SCons/Node/FSTests.py10
-rw-r--r--src/engine/SCons/Util.py63
-rw-r--r--src/engine/SCons/UtilTests.py6
5 files changed, 91 insertions, 16 deletions
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index ab32cef..73c7047 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -139,6 +139,14 @@ RELEASE 0.96 - XXX
arguments when creating Builder objects. Enhance Dir Nodes so that
they can be created with user-specified Builder objects.
+ From Chris Murray:
+
+ - Add a .win32 attribute to force file names to expand with
+ Windows backslash path separators.
+
+ - Fix escaping file names on command lines when the expansion is
+ concatenated with another string.
+
From Gary Oberbrunner:
- Add a --debug=presub option to print actions prior to substitution.
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index 72ed154..1cb7779 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -348,15 +348,24 @@ class EntryProxy(SCons.Util.Proxy):
entry.name + "_base")
def __get_posix_path(self):
- """Return the path with / as the path separator, regardless
- of platform."""
+ """Return the path with / as the path separator,
+ regardless of platform."""
if os.sep == '/':
return self
else:
entry = self.get()
- return SCons.Util.SpecialAttrWrapper(string.replace(entry.get_path(),
- os.sep, '/'),
- entry.name + "_posix")
+ r = string.replace(entry.get_path(), os.sep, '/')
+ return SCons.Util.SpecialAttrWrapper(r, entry.name + "_posix")
+
+ def __get_win32_path(self):
+ """Return the path with \ as the path separator,
+ regardless of platform."""
+ if os.sep == '\\':
+ return self
+ else:
+ entry = self.get()
+ r = string.replace(entry.get_path(), os.sep, '\\')
+ return SCons.Util.SpecialAttrWrapper(r, entry.name + "_win32")
def __get_srcnode(self):
return EntryProxy(self.get().srcnode())
@@ -379,6 +388,7 @@ class EntryProxy(SCons.Util.Proxy):
dictSpecialAttrs = { "base" : __get_base_path,
"posix" : __get_posix_path,
+ "win32" : __get_win32_path,
"srcpath" : __get_srcnode,
"srcdir" : __get_srcdir,
"dir" : __get_dir,
diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py
index 231d736..4a868b9 100644
--- a/src/engine/SCons/Node/FSTests.py
+++ b/src/engine/SCons/Node/FSTests.py
@@ -1522,7 +1522,6 @@ class prepareTestCase(unittest.TestCase):
assert dir_made == [], dir_made
xyz.set_state(0)
xyz.prepare()
- print "dir_made[0] =", dir_made[0]
assert dir_made[0].path == "new_dir", dir_made[0]
dir = fs.Dir("dir")
@@ -1836,6 +1835,13 @@ class SpecialAttrTestCase(unittest.TestCase):
for_sig = f.posix.for_signature()
assert for_sig == 'baz.blat_posix', for_sig
+ s = str(f.win32)
+ assert s == 'foo\\bar\\baz.blat', repr(s)
+ assert f.win32.is_literal(), f.win32
+ if f.win32 != f:
+ for_sig = f.win32.for_signature()
+ assert for_sig == 'baz.blat_win32', for_sig
+
# And now, combinations!!!
s = str(f.srcpath.base)
assert s == os.path.normpath('foo/bar/baz'), s
@@ -1843,6 +1849,8 @@ class SpecialAttrTestCase(unittest.TestCase):
assert s == str(f.srcdir), s
s = str(f.srcpath.posix)
assert s == 'foo/bar/baz.blat', s
+ s = str(f.srcpath.win32)
+ assert s == 'foo\\bar\\baz.blat', s
# Test what happens with BuildDir()
fs.BuildDir('foo', 'baz')
diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py
index 636a74f..49e52ff 100644
--- a/src/engine/SCons/Util.py
+++ b/src/engine/SCons/Util.py
@@ -638,8 +638,8 @@ def scons_subst_list(strSubst, env, mode=SUBST_RAW, target=None, source=None, di
class ListSubber(UserList.UserList):
"""A class to construct the results of a scons_subst_list() call.
- Like StringSubber, this class binds a specific binds a specific
- construction environment, mode, target and source with two methods
+ Like StringSubber, this class binds a specific construction
+ environment, mode, target and source with two methods
(substitute() and expand()) that handle the expansion.
In addition, however, this class is used to track the state of
@@ -677,6 +677,7 @@ def scons_subst_list(strSubst, env, mode=SUBST_RAW, target=None, source=None, di
the results of expansions of side-by-side strings still get
re-evaluated separately, not smushed together.
"""
+
if is_String(s):
try:
s0, s1 = s[:2]
@@ -737,6 +738,7 @@ def scons_subst_list(strSubst, env, mode=SUBST_RAW, target=None, source=None, di
This serves as a wrapper for splitting up a string into
separate tokens.
"""
+
if is_String(args) and not isinstance(args, CmdStringHolder):
args = _separate_args.findall(args)
for a in args:
@@ -758,38 +760,58 @@ def scons_subst_list(strSubst, env, mode=SUBST_RAW, target=None, source=None, di
another line to the result."""
UserList.UserList.append(self, [])
self.next_word()
+
def this_word(self):
"""Arrange for the next word to append to the end of the
current last word in the result."""
self.append = self.add_to_current_word
+
def next_word(self):
"""Arrange for the next word to start a new word."""
self.append = self.add_new_word
def add_to_current_word(self, x):
+ """Append the string x to the end of the current last word
+ in the result. If that is not possible, then just add
+ it as a new word. Make sure the entire concatenated string
+ inherits the object attributes of x (in particular, the
+ escape function) by wrapping it as CmdStringHolder."""
+
if not self.in_strip or self.mode != SUBST_SIG:
try:
- self[-1][-1] = self[-1][-1] + x
+ y = self[-1][-1] + x
except IndexError:
self.add_new_word(x)
+ else:
+ literal1 = self.literal(self[-1][-1])
+ literal2 = self.literal(x)
+ y = self.conv(y)
+ if is_String(y):
+ y = CmdStringHolder(y, literal1 or literal2)
+ self[-1][-1] = y
+
def add_new_word(self, x):
if not self.in_strip or self.mode != SUBST_SIG:
- try:
- l = x.is_literal
- except AttributeError:
- literal = None
- else:
- literal = l()
+ literal = self.literal(x)
x = self.conv(x)
if is_String(x):
x = CmdStringHolder(x, literal)
self[-1].append(x)
self.append = self.add_to_current_word
+ def literal(self, x):
+ try:
+ l = x.is_literal
+ except AttributeError:
+ return None
+ else:
+ return l()
+
def open_strip(self, x):
"""Handle the "open strip" $( token."""
self.add_strip(x)
self.in_strip = 1
+
def close_strip(self, x):
"""Handle the "close strip" $) token."""
self.add_strip(x)
@@ -909,14 +931,35 @@ else:
class Proxy:
"""A simple generic Proxy class, forwarding all calls to
- subject. Inherit from this class to create a Proxy."""
+ 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."""
+
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
# attempt to load the windows registry module:
diff --git a/src/engine/SCons/UtilTests.py b/src/engine/SCons/UtilTests.py
index 846aaaa..713f522 100644
--- a/src/engine/SCons/UtilTests.py
+++ b/src/engine/SCons/UtilTests.py
@@ -706,6 +706,12 @@ class UtilTestCase(unittest.TestCase):
c = cmd_list[0][3].escape(escape_func)
assert c == 'xyz', c
+ cmd_list = scons_subst_list("abc${LITERALS}xyz", env)
+ c = cmd_list[0][0].escape(escape_func)
+ assert c == '**abcfoo\nwith\nnewlines**', c
+ c = cmd_list[0][1].escape(escape_func)
+ assert c == '**bar\nwith\nnewlinesxyz**', c
+
# Tests of the various SUBST_* modes of substitution.
subst_list_cases = [
"test $xxx",