From cde5ab9e4fe2675f072bf65d2deb49dd75bf7c32 Mon Sep 17 00:00:00 2001 From: stevenknight Date: Sat, 8 Oct 2005 17:25:47 +0000 Subject: [PATCH] Remove old, same-named files from a build directory if the file in the source directory does not exist. (Patrick Mezard) git-svn-id: http://scons.tigris.org/svn/scons/trunk@1364 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- src/CHANGES.txt | 4 ++ src/engine/SCons/Node/FS.py | 18 +++++- src/engine/SCons/Node/FSTests.py | 31 ++++++++++ test/BuildDir/removed-files.py | 99 ++++++++++++++++++++++++++++++++ 4 files changed, 149 insertions(+), 3 deletions(-) create mode 100644 test/BuildDir/removed-files.py diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 0d1cf5f2..902b9159 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -396,6 +396,10 @@ RELEASE 0.97 - XXX - Fix the -n option when used with -c to print all of the targets that will be removed for a multi-target Builder call. + - If there's no file in the source directory, make sure there isn't + one in the build directory, too, to avoid dangling files left + over from previous runs when a source file is removed. + From Georg Mischler: - Remove the space after the -o option when invoking the Borland diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index ffdc1eba..ceec6965 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -1866,12 +1866,24 @@ class File(Base): "__cacheable__" # Duplicate from source path if we are set up to do this. if self.duplicate and not self.is_derived() and not self.linked: - src=self.srcnode() + src = self.srcnode() if src is self: return Base.exists(self) + # At this point, src is meant to be copied in a build directory. src = src.rfile() - if src.abspath != self.abspath and src.exists(): - self.do_duplicate(src) + if src.abspath != self.abspath: + if src.exists(): + self.do_duplicate(src) + # Can't return 1 here because the duplication might + # not actually occur if the -n option is being used. + else: + # The source file does not exist. Make sure no old + # copy remains in the build directory. + if Base.exists(self) or self.islink(): + self.fs.unlink(self.path) + # Return None explicitly because the Base.exists() call + # above will have cached its value if the file existed. + return None return Base.exists(self) # diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py index 60b0197f..71fb3ef8 100644 --- a/src/engine/SCons/Node/FSTests.py +++ b/src/engine/SCons/Node/FSTests.py @@ -1836,6 +1836,37 @@ class FileTestCase(_tempdirTestCase): dirs = fff.Dirs(['d1', 'd2']) assert dirs == [d1, d2], map(str, dirs) + def test_exists(self): + """Test the File.exists() method""" + fs = self.fs + test = self.test + + src_f1 = fs.File('src/f1') + assert not src_f1.exists(), "%s apparently exists?" % src_f1 + + test.subdir('src') + test.write(['src', 'f1'], "src/f1\n") + + assert not src_f1.exists(), "%s did not cache previous exists() value" % src_f1 + src_f1.clear() + assert src_f1.exists(), "%s apparently does not exist?" % src_f1 + + test.subdir('build') + fs.BuildDir('build', 'src') + build_f1 = fs.File('build/f1') + + assert build_f1.exists(), "%s did not realize that %s exists" % (build_f1, src_f1) + assert os.path.exists(build_f1.abspath), "%s did not get duplicated on disk" % build_f1.abspath + + test.unlink(['src', 'f1']) + src_f1.clear() # so the next exists() call will look on disk again + + assert build_f1.exists(), "%s did not cache previous exists() value" % build_f1 + build_f1.clear() + build_f1.linked = None + assert not build_f1.exists(), "%s did not realize that %s disappeared" % (build_f1, src_f1) + assert not os.path.exists(build_f1.abspath), "%s did not get removed after %s was removed" % (build_f1, src_f1) + class RepositoryTestCase(_tempdirTestCase): diff --git a/test/BuildDir/removed-files.py b/test/BuildDir/removed-files.py new file mode 100644 index 00000000..7582a930 --- /dev/null +++ b/test/BuildDir/removed-files.py @@ -0,0 +1,99 @@ +#!/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 BuildDir handling of removal of source files. + +A C++ Program is created and compiled. First, a header is missing. Then +the header is added and the compilation should succeed, then the header +is removed and the compilation should fail again. + +Previous versions of SCons did not remove the header from the build +directory after the source directory's header was removed, which caused +the compilation to succeed even after the source file was removed. + +Test case supplied by Patrick Mezard--many thanks. +""" + +import TestSCons + +test = TestSCons.TestSCons() + +#------------------------------------------------------------------------------- +#1- Create dep.cpp and the SConstruct. dep.h is missing and the build is +#expected to fail with 2. +#------------------------------------------------------------------------------- + +test.subdir('src') + +test.write(['src', 'dep.cpp'], """\ +#include "dep.h" + +int main(int argc, char* argv[]) +{ + return test_dep(); +} +""") + +test.write('SConstruct', """ +env = Environment() +env.BuildDir('bin', 'src') +o = env.Object('bin/dep', 'bin/dep.cpp') +env.Program('bin/dep', o) +""") + +test.run(arguments = '.', stderr=None, status=2) + + +#------------------------------------------------------------------------------- +#2- Add dep.h and check the build is OK. +#------------------------------------------------------------------------------- + +test.write(['src', 'dep.h'], """\ +#ifndef DEP_H +#define DEP_H + +inline int test_dep() +{ + return 1; +} + +#endif //DEP_H +""") + +test.run(arguments = '.') + + +#------------------------------------------------------------------------------- +#3- Remove dep.h. The build is expected to fail again like in [1]. +#------------------------------------------------------------------------------- + +test.unlink(['src', 'dep.h']) + +test.run(arguments = '.', stderr=None, status=2) + + +test.pass_test() -- 2.26.2