summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/man/scons.117
-rw-r--r--src/CHANGES.txt7
-rw-r--r--src/engine/SCons/Node/FS.py27
-rw-r--r--src/engine/SCons/Node/FSTests.py139
-rw-r--r--src/engine/SCons/Tool/m4.py2
-rw-r--r--test/Repository/M4.py103
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()