From: stevenknight Date: Sat, 25 Feb 2006 18:18:55 +0000 (+0000) Subject: In the error message, supply the file name that triggered on IOError or OSError,... X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=7d9324cd53acb907a8147d0ddf06af33aab7d6d5;p=scons.git In the error message, supply the file name that triggered on IOError or OSError, not just the target name. git-svn-id: http://scons.tigris.org/svn/scons/trunk@1431 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 2255a4fc..0df16969 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -135,6 +135,10 @@ RELEASE 0.97 - XXX - Fix (?) a runtest.py hang on Windows when the --xml option is used. + - Change the message when an error occurs trying to interact with the + file system to report the target(s) in square brackets (as before) and + the actual file or directory that encountered the error afterwards. + From Chen Lee: - Add x64 support for Microsoft Visual Studio 8. diff --git a/src/engine/SCons/Action.py b/src/engine/SCons/Action.py index 25c71332..4014dea9 100644 --- a/src/engine/SCons/Action.py +++ b/src/engine/SCons/Action.py @@ -645,7 +645,15 @@ class FunctionAction(_ActionAction): result = self.execfunction(target=target, source=rsources, env=env) except EnvironmentError, e: # If an IOError/OSError happens, raise a BuildError. - raise SCons.Errors.BuildError(node=target, errstr=e.strerror) + # Report the name of the file or directory that caused the + # error, which might be different from the target being built + # (for example, failure to create the directory in which the + # target file will appear). + try: filename = e.filename + except AttributeError: filename = None + raise SCons.Errors.BuildError(node=target, + errstr=e.strerror, + filename=filename) return result def get_contents(self, target, source, env): diff --git a/src/engine/SCons/Errors.py b/src/engine/SCons/Errors.py index 4dacde6f..3a3306e9 100644 --- a/src/engine/SCons/Errors.py +++ b/src/engine/SCons/Errors.py @@ -33,9 +33,10 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" class BuildError(Exception): - def __init__(self, node=None, errstr="Unknown error", *args): + def __init__(self, node=None, errstr="Unknown error", filename=None, *args): self.node = node self.errstr = errstr + self.filename = filename apply(Exception.__init__, (self,) + args) class InternalError(Exception): @@ -53,3 +54,9 @@ class ExplicitExit(Exception): self.status = status apply(Exception.__init__, (self,) + args) +class TaskmasterException(Exception): + def __init__(self, node=None, exc_info=(None, None, None), *args): + self.node = node + self.errstr = "Exception" + self.exc_info = exc_info + apply(Exception.__init__, (self,) + args) diff --git a/src/engine/SCons/ErrorsTests.py b/src/engine/SCons/ErrorsTests.py index c63d9881..93d516c8 100644 --- a/src/engine/SCons/ErrorsTests.py +++ b/src/engine/SCons/ErrorsTests.py @@ -58,6 +58,14 @@ class ErrorsTestCase(unittest.TestCase): except SCons.Errors.ExplicitExit, e: assert e.node == "node" + def test_TaskmasterException(self): + """Test the TaskmasterException exception.""" + try: + raise SCons.Errors.TaskmasterException("tm exception", (1, 2, 3)) + except SCons.Errors.TaskmasterException, e: + assert e.node == "tm exception" + assert e.exc_info == (1, 2, 3) + if __name__ == "__main__": suite = unittest.makeSuite(ErrorsTestCase, 'test_') if not unittest.TextTestRunner().run(suite).wasSuccessful(): diff --git a/src/engine/SCons/Script/Main.py b/src/engine/SCons/Script/Main.py index 60747083..73f96e2e 100644 --- a/src/engine/SCons/Script/Main.py +++ b/src/engine/SCons/Script/Main.py @@ -138,16 +138,29 @@ class BuildTask(SCons.Taskmaster.Task): # see if the sys module has one. t, e = sys.exc_info()[:2] + def nodestring(n): + if not SCons.Util.is_List(n): + n = [ n ] + return string.join(map(str, n), ', ') + + errfmt = "scons: *** [%s] %s\n" + if t == SCons.Errors.BuildError: - fname = e.node - if SCons.Util.is_List(e.node): - fname = string.join(map(str, e.node), ', ') - sys.stderr.write("scons: *** [%s] %s\n" % (fname, e.errstr)) - if e.errstr == 'Exception': - traceback.print_exception(e.args[0], e.args[1], e.args[2]) + tname = nodestring(e.node) + errstr = e.errstr + if e.filename: + errstr = e.filename + ': ' + errstr + sys.stderr.write(errfmt % (tname, errstr)) + elif t == SCons.Errors.TaskmasterException: + tname = nodestring(e.node) + sys.stderr.write(errfmt % (tname, e.errstr)) + type, value, trace = e.exc_info + traceback.print_exception(type, value, trace) elif t == SCons.Errors.ExplicitExit: status = e.status - sys.stderr.write("scons: *** [%s] Explicit exit, status %s\n" % (e.node, e.status)) + tname = nodestring(e.node) + errstr = 'Explicit exit, status %s' % status + sys.stderr.write(errfmt % (tname, errstr)) else: if e is None: e = t diff --git a/src/engine/SCons/Taskmaster.py b/src/engine/SCons/Taskmaster.py index 6d5f87cb..ecd6b07a 100644 --- a/src/engine/SCons/Taskmaster.py +++ b/src/engine/SCons/Taskmaster.py @@ -143,12 +143,8 @@ class Task: except SCons.Errors.BuildError: raise except: - exc_type, exc_value, exc_traceback = sys.exc_info() - raise SCons.Errors.BuildError(self.targets[0], - "Exception", - exc_type, - exc_value, - exc_traceback) + raise SCons.Errors.TaskmasterException(self.targets[0], + sys.exc_info()) def get_target(self): """Fetch the target being built or updated by this task. diff --git a/src/engine/SCons/TaskmasterTests.py b/src/engine/SCons/TaskmasterTests.py index f3cb5f02..7e24d2b7 100644 --- a/src/engine/SCons/TaskmasterTests.py +++ b/src/engine/SCons/TaskmasterTests.py @@ -880,14 +880,12 @@ class TaskmasterTestCase(unittest.TestCase): t = tm.next_task() try: t.execute() - except SCons.Errors.BuildError, e: + except SCons.Errors.TaskmasterException, e: assert e.node == n4, e.node assert e.errstr == "Exception", e.errstr - assert len(e.args) == 3, `e.args` - assert e.args[0] == OtherError, e.args[0] - assert isinstance(e.args[1], OtherError), type(e.args[1]) + assert len(e.exc_info) == 3, e.exc_info exc_traceback = sys.exc_info()[2] - assert type(e.args[2]) == type(exc_traceback), e.args[2] + assert type(e.exc_info[2]) == type(exc_traceback), e.exc_info[2] else: raise TestFailed, "did not catch expected BuildError" diff --git a/test/Install/Install.py b/test/Install/Install.py index 50f38207..7018466f 100644 --- a/test/Install/Install.py +++ b/test/Install/Install.py @@ -128,9 +128,14 @@ test.write(['work', 'f1.in'], "f1.in again again\n") os.chmod(test.workpath('work', 'export'), 0555) f = open(f1_out, 'rb') +expect = """\ +scons: *** [%s] %s: Permission denied +""" % (os.path.join('export', 'f1.out'), + test.workpath('work', 'export', 'f1.out')) + test.run(chdir = 'work', arguments = f1_out, - stderr="scons: *** [%s] Permission denied\n" % os.path.join('export', 'f1.out'), + stderr=expect, status=2) f.close() diff --git a/test/build-errors.py b/test/build-errors.py index 9b6443d3..e25fbd50 100644 --- a/test/build-errors.py +++ b/test/build-errors.py @@ -215,8 +215,8 @@ test.writable('test2.out', 1) test.description_set("Incorrect STDERR:\n%s" % test.stderr()) errs = [ - "scons: *** [test2.out] Permission denied\n", - "scons: *** [test2.out] permission denied\n", + "scons: *** [test2.out] test2.out: Permission denied\n", + "scons: *** [test2.out] test2.out: permission denied\n", ] test.fail_test(test.stderr() not in errs)