diff options
-rw-r--r-- | src/CHANGES.txt | 8 | ||||
-rw-r--r-- | src/engine/SCons/Node/FS.py | 20 | ||||
-rw-r--r-- | src/engine/SCons/Node/FSTests.py | 10 | ||||
-rw-r--r-- | src/engine/SCons/Util.py | 63 | ||||
-rw-r--r-- | src/engine/SCons/UtilTests.py | 6 |
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", |