diff options
-rw-r--r-- | doc/man/scons.1 | 17 | ||||
-rw-r--r-- | src/CHANGES.txt | 7 | ||||
-rw-r--r-- | src/engine/SCons/Node/FS.py | 27 | ||||
-rw-r--r-- | src/engine/SCons/Node/FSTests.py | 139 | ||||
-rw-r--r-- | src/engine/SCons/Tool/m4.py | 2 | ||||
-rw-r--r-- | test/Repository/M4.py | 103 |
6 files changed, 243 insertions, 52 deletions
diff --git a/doc/man/scons.1 b/doc/man/scons.1 index efa59ba..f5c0a70 100644 --- a/doc/man/scons.1 +++ b/doc/man/scons.1 @@ -6475,6 +6475,18 @@ The directory containing the source file linked to this file through BuildDir. If this file isn't linked, it just returns the directory part of the filename. +.IP rsrcpath +The directory and file name to the source file linked to this file +through BuildDir. If the file does not exist locally but exists in +a Repository, the path in the Repository is returned. +If this file isn't linked, it just returns the +directory and filename unchanged. + +.IP rsrcdir +The Repository directory containing the source file linked to this file +through BuildDir. If this file isn't linked, it just returns the +directory part of the filename. + .LP For example, the specified target will expand as follows for the corresponding modifiers: @@ -6492,6 +6504,11 @@ BuildDir('sub/dir','src') $SOURCE => sub/dir/file.x ${SOURCE.srcpath} => src/file.x ${SOURCE.srcdir} => src + +Repository('/usr/repository') +$SOURCE => sub/dir/file.x +${SOURCE.rsrcpath} => /usr/repository/src/file.x +${SOURCE.rsrcdir} => /usr/repository/src .EE Lastly, a variable name diff --git a/src/CHANGES.txt b/src/CHANGES.txt index f7d0a22..f93a78a 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -163,6 +163,13 @@ RELEASE 0.95 - XXX - Always use the Builder overrides in substitutions, not just if there isn't a target-specific environment. + - Add new "rsrcpath" and "rsrcdir" and attributes to $TARGET/$SOURCE, + so Builder command lines can find things in Repository source + directories when using BuildDir. + + - Fix the M4 Builder so that it chdirs to the Repository directory + when the input file is in the source directory of a BuildDir. + From Vincent Risi: - Add support for the bcc32, ilink32 and tlib Borland tools. diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index e1aeda3..438cd7f 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -276,18 +276,29 @@ class EntryProxy(SCons.Util.Proxy): node via BuildDir(), or the directory of this node if not linked.""" return EntryProxy(self.get().srcnode().dir) + def __get_rsrcnode(self): + return EntryProxy(self.get().srcnode().rfile()) + + def __get_rsrcdir(self): + """Returns the directory containing the source node linked to this + node via BuildDir(), or the directory of this node if not linked.""" + return EntryProxy(self.get().srcnode().rfile().dir) + def __get_dir(self): return EntryProxy(self.get().dir) - dictSpecialAttrs = { "base" : __get_base_path, - "posix" : __get_posix_path, - "srcpath" : __get_srcnode, - "srcdir" : __get_srcdir, - "dir" : __get_dir, - "abspath" : __get_abspath, + dictSpecialAttrs = { "base" : __get_base_path, + "posix" : __get_posix_path, + "srcpath" : __get_srcnode, + "srcdir" : __get_srcdir, + "dir" : __get_dir, + "abspath" : __get_abspath, "filebase" : __get_filebase, - "suffix" : __get_suffix, - "file" : __get_file } + "suffix" : __get_suffix, + "file" : __get_file, + "rsrcpath" : __get_rsrcnode, + "rsrcdir" : __get_rsrcdir, + } def __getattr__(self, name): # This is how we implement the "special" attributes diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py index ef1f52a..a84a993 100644 --- a/src/engine/SCons/Node/FSTests.py +++ b/src/engine/SCons/Node/FSTests.py @@ -1721,43 +1721,111 @@ class SpecialAttrTestCase(unittest.TestCase): def runTest(self): """Test special attributes of file nodes.""" test=TestCmd(workdir='') - fs = SCons.Node.FS.FS(test.workpath('')) + fs = SCons.Node.FS.FS(test.workpath('work')) + + f = fs.Entry('foo/bar/baz.blat').get_subst_proxy() - f=fs.Entry('foo/bar/baz.blat').get_subst_proxy() - assert str(f.dir) == os.path.normpath('foo/bar'), str(f.dir) + s = str(f.dir) + assert s == os.path.normpath('foo/bar'), s assert f.dir.is_literal(), f.dir - assert f.dir.for_signature() == 'bar', f.dir.for_signature() - - assert str(f.file) == 'baz.blat', str(f.file) + for_sig = f.dir.for_signature() + assert for_sig == 'bar', for_sig + + s = str(f.file) + assert s == 'baz.blat', s assert f.file.is_literal(), f.file - assert f.file.for_signature() == 'baz.blat_file', \ - f.file.for_signature() - - assert str(f.base) == os.path.normpath('foo/bar/baz'), str(f.base) + for_sig = f.file.for_signature() + assert for_sig == 'baz.blat_file', for_sig + + s = str(f.base) + assert s == os.path.normpath('foo/bar/baz'), s assert f.base.is_literal(), f.base - assert f.base.for_signature() == 'baz.blat_base', \ - f.base.for_signature() - - assert str(f.filebase) == 'baz', str(f.filebase) + for_sig = f.base.for_signature() + assert for_sig == 'baz.blat_base', for_sig + + s = str(f.filebase) + assert s == 'baz', s assert f.filebase.is_literal(), f.filebase - assert f.filebase.for_signature() == 'baz.blat_filebase', \ - f.filebase.for_signature() - - assert str(f.suffix) == '.blat', str(f.suffix) + for_sig = f.filebase.for_signature() + assert for_sig == 'baz.blat_filebase', for_sig + + s = str(f.suffix) + assert s == '.blat', s assert f.suffix.is_literal(), f.suffix - assert f.suffix.for_signature() == 'baz.blat_suffix', \ - f.suffix.for_signature() - - assert str(f.abspath) == test.workpath('foo', 'bar', 'baz.blat'), str(f.abspath) + for_sig = f.suffix.for_signature() + assert for_sig == 'baz.blat_suffix', for_sig + + s = str(f.abspath) + assert s == test.workpath('work', 'foo', 'bar', 'baz.blat'), s assert f.abspath.is_literal(), f.abspath - assert f.abspath.for_signature() == 'baz.blat_abspath', \ - f.abspath.for_signature() - - assert str(f.posix) == 'foo/bar/baz.blat', str(f.posix) + for_sig = f.abspath.for_signature() + assert for_sig == 'baz.blat_abspath', for_sig + + s = str(f.posix) + assert s == 'foo/bar/baz.blat', s assert f.posix.is_literal(), f.posix if f.posix != f: - assert f.posix.for_signature() == 'baz.blat_posix', \ - f.posix.for_signature() + for_sig = f.posix.for_signature() + assert for_sig == 'baz.blat_posix', for_sig + + # And now, combinations!!! + s = str(f.srcpath.base) + assert s == os.path.normpath('foo/bar/baz'), s + s = str(f.srcpath.dir) + assert s == str(f.srcdir), s + s = str(f.srcpath.posix) + assert s == 'foo/bar/baz.blat', s + + # Test what happens with BuildDir() + fs.BuildDir('foo', 'baz') + + s = str(f.srcpath) + assert s == os.path.normpath('baz/bar/baz.blat'), s + assert f.srcpath.is_literal(), f.srcpath + g = f.srcpath.get() + assert isinstance(g, SCons.Node.FS.Entry), g.__class__ + + s = str(f.srcdir) + assert s == os.path.normpath('baz/bar'), s + assert f.srcdir.is_literal(), f.srcdir + g = f.srcdir.get() + assert isinstance(g, SCons.Node.FS.Dir), g.__class__ + + # And now what happens with BuildDir() + Repository() + fs.Repository(test.workpath('repository')) + + f = fs.Entry('foo/sub/file.suffix').get_subst_proxy() + test.subdir('repository', + ['repository', 'baz'], + ['repository', 'baz', 'sub']) + + rd = test.workpath('repository', 'baz', 'sub') + rf = test.workpath('repository', 'baz', 'sub', 'file.suffix') + test.write(rf, "\n") + + s = str(f.srcpath) + assert s == os.path.normpath('baz/sub/file.suffix'), s + assert f.srcpath.is_literal(), f.srcpath + g = f.srcpath.get() + assert isinstance(g, SCons.Node.FS.Entry), g.__class__ + + s = str(f.srcdir) + assert s == os.path.normpath('baz/sub'), s + assert f.srcdir.is_literal(), f.srcdir + g = f.srcdir.get() + assert isinstance(g, SCons.Node.FS.Dir), g.__class__ + + s = str(f.rsrcpath) + assert s == rf, s + assert f.rsrcpath.is_literal(), f.rsrcpath + g = f.rsrcpath.get() + assert isinstance(g, SCons.Node.FS.File), g.__class__ + + s = str(f.rsrcdir) + assert s == rd, s + assert f.rsrcdir.is_literal(), f.rsrcdir + g = f.rsrcdir.get() + assert isinstance(g, SCons.Node.FS.Dir), g.__class__ # Check that attempts to access non-existent attributes of the # subst proxy generate the right exceptions and messages. @@ -1785,22 +1853,7 @@ class SpecialAttrTestCase(unittest.TestCase): caught = 1 assert caught, "did not catch expected AttributeError" - fs.BuildDir('foo', 'baz') - assert str(f.srcpath) == os.path.normpath('baz/bar/baz.blat'), str(f.srcpath) - assert f.srcpath.is_literal(), f.srcpath - assert isinstance(f.srcpath.get(), SCons.Node.FS.Entry) - - assert str(f.srcdir) == os.path.normpath('baz/bar'), str(f.srcdir) - assert f.srcdir.is_literal(), f.srcdir - assert isinstance(f.srcdir.get(), SCons.Node.FS.Dir) - - # And now, combinations!!! - assert str(f.srcpath.base) == os.path.normpath('baz/bar/baz'), str(f.srcpath.base) - assert str(f.srcpath.dir) == str(f.srcdir), str(f.srcpath.dir) - assert str(f.srcpath.posix) == 'baz/bar/baz.blat', str(f.srcpath.posix) - - if __name__ == "__main__": suite = unittest.TestSuite() diff --git a/src/engine/SCons/Tool/m4.py b/src/engine/SCons/Tool/m4.py index 35f323c..0c83c66 100644 --- a/src/engine/SCons/Tool/m4.py +++ b/src/engine/SCons/Tool/m4.py @@ -48,7 +48,7 @@ def generate(env): # file.cpp.m4 -> file.cpp etc. env['M4'] = 'm4' env['M4FLAGS'] = '-E' - env['M4COM'] = 'cd ${SOURCE.srcdir} && $M4 $M4FLAGS < ${SOURCE.file} > ${TARGET.abspath}' + env['M4COM'] = 'cd ${SOURCE.rsrcdir} && $M4 $M4FLAGS < ${SOURCE.file} > ${TARGET.abspath}' def exists(env): return env.Detect('m4') diff --git a/test/Repository/M4.py b/test/Repository/M4.py new file mode 100644 index 0000000..75fa0de --- /dev/null +++ b/test/Repository/M4.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python +# +# __COPYRIGHT__ +# +# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +""" +Test that $M4 and $M4FLAGS work with repositories. +""" + +import os +import os.path +import string +import sys +import TestSCons + +python = TestSCons.python + +test = TestSCons.TestSCons() + +test.subdir('work', 'repository', ['repository', 'src']) + +test.write('mym4.py', """ +import string +import sys +contents = sys.stdin.read() +sys.stdout.write(string.replace(contents, 'M4', 'mym4.py')) +sys.exit(0) +""") + + + + +opts = "-Y " + test.workpath('repository') + +test.write(['repository', 'SConstruct'], """\ +env = Environment(M4 = r'%s %s', tools=['default', 'm4']) +env.M4(target = 'aaa.x', source = 'aaa.x.m4') +SConscript('src/SConscript', "env", build_dir="build") +""" % (python, test.workpath('mym4.py'))) + +test.write(['repository', 'aaa.x.m4'], """\ +line 1 +M4 +line 3 +""") + +test.write(['repository', 'src', 'SConscript'], """ +Import("env") +env.M4('bbb.y', 'bbb.y.m4') +""") + +test.write(['repository', 'src', 'bbb.y.m4'], """\ +line 1 M4 +line 2 +line 3 M4 +""") + +# +# Make the repository non-writable, +# so we'll detect if we try to write into it accidentally. +test.writable('repository', 0) + +# +test.run(chdir = 'work', options = opts, arguments = ".") + +expect_aaa_x = """\ +line 1 +mym4.py +line 3 +""" + +expect_bbb_y = """\ +line 1 mym4.py +line 2 +line 3 mym4.py +""" + +test.fail_test(test.read(test.workpath('work', 'aaa.x'), 'r') != expect_aaa_x) +test.fail_test(test.read(test.workpath('work', 'build', 'bbb.y'), 'r') != expect_bbb_y) + +# +test.pass_test() |