summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2002-11-27 02:02:36 (GMT)
committerSteven Knight <knight@baldmt.com>2002-11-27 02:02:36 (GMT)
commit814029abd36603a70bc402826c79a5fdefe3c2a1 (patch)
tree4edf62d6b0b5114ef5baf54a802a7f1c648172e0
parentdd30a312b7c59abd25d41c3d332df57801abf66b (diff)
downloadSCons-814029abd36603a70bc402826c79a5fdefe3c2a1.zip
SCons-814029abd36603a70bc402826c79a5fdefe3c2a1.tar.gz
SCons-814029abd36603a70bc402826c79a5fdefe3c2a1.tar.bz2
Provide graceful failures when a source file doesn't exist and can't be build, and when a nonexistent drive letter is used on Win32.
-rw-r--r--doc/python10/main.sgml1
-rw-r--r--src/CHANGES.txt4
-rw-r--r--src/RELEASE.txt10
-rw-r--r--src/engine/SCons/Errors.py4
-rw-r--r--src/engine/SCons/Node/FS.py20
-rw-r--r--src/engine/SCons/Node/FSTests.py1
-rw-r--r--src/engine/SCons/Script/__init__.py6
-rw-r--r--test/Environment.py2
-rw-r--r--test/nonexistent.py75
-rw-r--r--test/overrides.py2
-rw-r--r--test/scan-once.py6
11 files changed, 113 insertions, 18 deletions
diff --git a/doc/python10/main.sgml b/doc/python10/main.sgml
index 889ef4d..26fcffb 100644
--- a/doc/python10/main.sgml
+++ b/doc/python10/main.sgml
@@ -37,7 +37,6 @@
<!ENTITY install SYSTEM "install.sgml">
<!ENTITY intro SYSTEM "intro.sgml">
<!ENTITY process SYSTEM "process.sgml">
- <!ENTITY references SYSTEM "references.sgml">
]>
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index 825d657..626db72 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -54,7 +54,9 @@ RELEASE 0.09 -
- Add separate $SHOBJPREFIX and $SHOBJSUFFIX construction variables
(by default, the same as $OBJPREFIX and $OBJSUFFIX).
- - Add a Make-like message when asked to build a source file.
+ - Add Make-like error messages when asked to build a source file,
+ and before trying to build a file that doesn't have all its source
+ files (including when an invalid drive letter is used on WIN32).
From Steven Knight and Anthony Roach:
diff --git a/src/RELEASE.txt b/src/RELEASE.txt
index 5f8c89a..d35168c 100644
--- a/src/RELEASE.txt
+++ b/src/RELEASE.txt
@@ -20,9 +20,9 @@ more effectively, please sign up for the scons-users mailing list at:
-RELEASE 0.08 - Mon, 15 Jul 2002 12:08:51 -0500
+RELEASE 0.09 - XXX
- This is the eighth alpha release of SCons. Please consult the
+ This is the ninth alpha release of SCons. Please consult the
CHANGES.txt file for a list of specific changes since last release.
Please note the following important changes since release 0.08:
@@ -30,7 +30,11 @@ RELEASE 0.08 - Mon, 15 Jul 2002 12:08:51 -0500
- The SetCommandHandler() function has been superceded
by the SPAWN, SHELL and ESCAPE construction variables.
- XXX
+ - SCons now exits with an error message if any source files or
+ implicit dependency files for a target do not exist and have
+ no Builder. SCons used to ignore these files, so builds that
+ formally succeeded despite the absence of a scanned file will now
+ fail unless the -k (keep going on error) flag is used.
Please note the following important changes since release 0.07:
diff --git a/src/engine/SCons/Errors.py b/src/engine/SCons/Errors.py
index 2640220..112a4c9 100644
--- a/src/engine/SCons/Errors.py
+++ b/src/engine/SCons/Errors.py
@@ -45,3 +45,7 @@ class InternalError(Exception):
class UserError(Exception):
def __init__(self, args=None):
self.args = args
+
+class StopError(Exception):
+ def __init__(self, args=None):
+ self.args = args
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index 59b8e63..d5247f7 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -43,7 +43,7 @@ import types
import SCons.Node
from UserDict import UserDict
import sys
-from SCons.Errors import UserError
+import SCons.Errors
import SCons.Warnings
try:
@@ -296,7 +296,7 @@ class FS:
directory = self.Root[drive]
except KeyError:
if not create:
- raise UserError
+ raise SCons.Errors.UserError
dir = Dir(drive, ParentOfRoot(), self)
dir.path = dir.path + os.sep
dir.abspath = dir.abspath + os.sep
@@ -314,7 +314,7 @@ class FS:
Dir)
except KeyError:
if not create:
- raise UserError
+ raise SCons.Errors.UserError
# look at the actual filesystem and make sure there isn't
# a file already there
@@ -332,7 +332,7 @@ class FS:
ret = self.__checkClass(directory.entries[file_name], fsclass)
except KeyError:
if not create:
- raise UserError
+ raise SCons.Errors.UserError
# make sure we don't create File nodes when there is actually
# a directory at that path on the disk, and vice versa
@@ -436,9 +436,9 @@ class FS:
if not isinstance(build_dir, SCons.Node.Node):
build_dir = self.Dir(build_dir)
if not src_dir.is_under(self.Top):
- raise UserError, "Source directory must be under top of build tree."
+ raise SCons.Errors.UserError, "Source directory must be under top of build tree."
if src_dir.is_under(build_dir):
- raise UserError, "Source directory cannot be under build directory."
+ raise SCons.Errors.UserError, "Source directory cannot be under build directory."
build_dir.link(src_dir, duplicate)
def Repository(self, *dirs):
@@ -848,6 +848,14 @@ class File(Entry):
def prepare(self):
"""Prepare for this file to be created."""
+
+ def missing(node):
+ return not node.builder and not node.rexists()
+ missing_sources = filter(missing, self.children())
+ if missing_sources:
+ desc = "No Builder for target `%s', needed by `%s'." % (missing_sources[0], self)
+ raise SCons.Errors.StopError, desc
+
if self.exists():
if self.builder and not self.precious:
os.unlink(self.path)
diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py
index c817408..5d32873 100644
--- a/src/engine/SCons/Node/FSTests.py
+++ b/src/engine/SCons/Node/FSTests.py
@@ -628,6 +628,7 @@ class FSTestCase(unittest.TestCase):
assert os.path.exists(test.workpath("remove_me"))
f1 = fs.File(test.workpath("remove_me"))
f1.builder = 1
+ f1.env_set(Environment())
f1.prepare()
assert not os.path.exists(test.workpath("remove_me"))
diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py
index 814d147..dd44621 100644
--- a/src/engine/SCons/Script/__init__.py
+++ b/src/engine/SCons/Script/__init__.py
@@ -99,6 +99,12 @@ class BuildTask(SCons.Taskmaster.Task):
# don't try to walk the stack, just print the error.
sys.stderr.write("\nSCons error: %s\n" % e)
raise
+ except StopError, e:
+ s = str(e)
+ if not keep_going_on_error:
+ s = s + ' Stop.'
+ sys.stderr.write("scons: *** %s\n" % s)
+ raise
except:
sys.stderr.write("scons: *** %s\n" % sys.exc_value)
raise
diff --git a/test/Environment.py b/test/Environment.py
index ea42e5d..0f3ab8a 100644
--- a/test/Environment.py
+++ b/test/Environment.py
@@ -48,6 +48,8 @@ assert sys.argv[3] == 'bar.in', sys.argv[3]
assert sys.argv[4] == 'blat blat', sys.argv[4]
""")
+test.write('foo.in', "foo.in\n")
+
test.run(arguments='foo.out')
test.pass_test()
diff --git a/test/nonexistent.py b/test/nonexistent.py
index 8f2c63e..3604a29 100644
--- a/test/nonexistent.py
+++ b/test/nonexistent.py
@@ -22,14 +22,29 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
+"""
+This test verifies that we fail gracefully and provide informative
+messages if someone tries to build a target that hasn't been defined
+or uses a nonexistent source file. On Windows systems, it checks
+to make sure that this applies to invalid drive letters as well.
+"""
+
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+import os
+import os.path
+import string
import sys
+
import TestSCons
test = TestSCons.TestSCons()
-test.write('SConstruct', "")
+test.write('SConstruct', """
+env = Environment()
+env.Command("aaa.out", "aaa.in", "should never get executed")
+env.Command("bbb.out", "bbb.in", "should never get executed")
+""")
test.run(arguments = 'foo',
stderr = "scons: *** Do not know how to make target `foo'. Stop.\n",
@@ -41,4 +56,62 @@ scons: *** Do not know how to make target `foo'.
""",
status = 2)
+test.run(arguments = "aaa.out",
+ stderr = "scons: *** No Builder for target `aaa.in', needed by `aaa.out'. Stop.\n",
+ status = 2)
+
+test.run(arguments = "-k bbb.out aaa.out",
+ stderr = """scons: *** No Builder for target `bbb.in', needed by `bbb.out'.
+scons: *** No Builder for target `aaa.in', needed by `aaa.out'.
+""",
+ status = 2)
+
+if sys.platform == 'win32':
+ bad_drive = None
+ for i in range(len(string.uppercase)-1, -1, -1):
+ d = string.uppercase[i]
+ if not os.path.isdir(d + ':' + os.sep):
+ bad_drive = d + ':' + '\\' + os.sep
+ break
+
+ if bad_drive is None:
+ print "All drive letters appear to be in use."
+ print "Cannot test SCons handling of invalid Win32 drive letters."
+ test.no_result(1);
+
+ test.write('SConstruct', """
+def cat(env, source, target):
+ target = str(target[0])
+ source = map(str, source)
+ print 'cat(%%s) > %%s' %% (source, target)
+ f = open(target, "wb")
+ for src in source:
+ f.write(open(src, "rb").read())
+ f.close()
+
+bad_drive = '%s'
+env = Environment(BUILDERS={'Build':Builder(action=cat)})
+env.Build('aaa.out', 'aaa.in')
+env.Build(bad_drive + 'no_target', 'bbb.in')
+env.Build('ccc.out', bad_drive + 'no_source')
+""" % bad_drive)
+
+ test.write("aaa.in", "aaa.in\n")
+
+ test.write("no_target", "no_target\n")
+
+ test.write("no_source", "no_source\n")
+
+ test.run(arguments = 'aaa.out')
+
+ test.fail_test(test.read('aaa.out') != "aaa.in\n")
+
+ test.run(arguments = bad_drive + 'no_target',
+ stderr = "scons: *** Do not know how to make target `%sno_target'. Stop.\n" % bad_drive,
+ status = 2)
+
+ test.run(arguments = 'ccc.out',
+ stderr = "scons: *** No Builder for target `%sno_source', needed by `ccc.out'. Stop.\n" % bad_drive,
+ status = 2)
+
test.pass_test()
diff --git a/test/overrides.py b/test/overrides.py
index 0ec3874..f535c97 100644
--- a/test/overrides.py
+++ b/test/overrides.py
@@ -44,6 +44,8 @@ env['BUILDERS']['Build'] = builder
Default(env.Build('foo', 'bar', CC='mycc', LIBS = env['LIBS']+['b']))
""")
+test.write('bar', "bar\n")
+
test.run()
test.write('SConstruct', """
diff --git a/test/scan-once.py b/test/scan-once.py
index 7ddf9c9..19cb495 100644
--- a/test/scan-once.py
+++ b/test/scan-once.py
@@ -60,12 +60,6 @@ f3 = env.Echo(source=['file3'], target=['file4'])
Default(f3)
""")
-test.run(arguments = '.',
- stdout = test.wrap_stdout("""create file2.s from file1.s
-create file3.s from file2.s
-create file4.s from file3.s
-"""))
-
test.write('file1.s', 'file1.s\n')
test.run(arguments = '.',