summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2001-08-18 20:51:21 (GMT)
committerSteven Knight <knight@baldmt.com>2001-08-18 20:51:21 (GMT)
commit2bd067fd38e6d3a636c7d46a1273f2cdc72e653c (patch)
tree73bc220e14dbf684e0b7b3efe4c52d5e734d4c39
parent7884cffaf3380a66a999ae8db12e0418f96993c0 (diff)
downloadSCons-2bd067fd38e6d3a636c7d46a1273f2cdc72e653c.zip
SCons-2bd067fd38e6d3a636c7d46a1273f2cdc72e653c.tar.gz
SCons-2bd067fd38e6d3a636c7d46a1273f2cdc72e653c.tar.bz2
Implement error framework.
-rw-r--r--src/MANIFEST1
-rw-r--r--src/scons.py200
-rw-r--r--src/scons/Errors.py18
-rw-r--r--src/scons/ErrorsTests.py28
-rw-r--r--test/errors.py54
5 files changed, 223 insertions, 78 deletions
diff --git a/src/MANIFEST b/src/MANIFEST
index 64585a1..88709ba 100644
--- a/src/MANIFEST
+++ b/src/MANIFEST
@@ -3,6 +3,7 @@ scons/__init__.py
scons/Builder.py
scons/Defaults.py
scons/Environment.py
+scons/Errors.py
scons/Job.py
scons/Node/__init__.py
scons/Node/FS.py
diff --git a/src/scons.py b/src/scons.py
index 11e1294..04292da 100644
--- a/src/scons.py
+++ b/src/scons.py
@@ -1,88 +1,19 @@
-#!/usr/bin/env python
+#! /usr/bin/env python
import getopt
import os.path
import string
import sys
-
-def PrintUsage():
- print "Usage: scons [OPTION]... TARGET..."
- print "Build TARGET or multiple TARGET(s)"
- print " "
- print ' -f CONSCRIPT execute CONSCRIPT instead of "SConstruct"'
- print " -j N execute N parallel jobs"
- print " --help print this message and exit"
-
-try:
- opts, targets = getopt.getopt(sys.argv[1:], 'f:j:', ['help'])
-except getopt.GetoptError, x:
- print x
- PrintUsage()
- sys.exit()
-
-Scripts = []
-
-num_jobs = 1
-for o, a in opts:
- if o == '-f': Scripts.append(a)
-
- if o == '-j':
- try:
- num_jobs = int(a)
- except:
- PrintUsage()
- sys.exit(1)
-
- if num_jobs <= 0:
- PrintUsage()
- sys.exit(1)
-
- if o == '--help':
- PrintUsage()
- sys.exit(0)
-
-if not Scripts:
- Scripts.append('SConstruct')
-
-
-# XXX The commented-out code here adds any "scons" subdirs in anything
-# along sys.path to sys.path. This was an attempt at setting up things
-# so we can import "node.FS" instead of "scons.Node.FS". This doesn't
-# quite fit our testing methodology, though, so save it for now until
-# the right solutions pops up.
-#
-#dirlist = []
-#for dir in sys.path:
-# scons = os.path.join(dir, 'scons')
-# if os.path.isdir(scons):
-# dirlist = dirlist + [scons]
-# dirlist = dirlist + [dir]
-#
-#sys.path = dirlist
-
+import traceback
from scons.Node.FS import init, Dir, File, lookup
from scons.Environment import Environment
import scons.Job
from scons.Builder import Builder
-
-init()
-
-
-
-def Conscript(filename):
- Scripts.append(filename)
-
-
-
-while Scripts:
- file, Scripts = Scripts[0], Scripts[1:]
- execfile(file)
-
-
+from scons.Errors import *
class Task:
- "this is here only until the build engine is implemented"
+ "XXX: this is here only until the build engine is implemented"
def __init__(self, target):
self.target = target
@@ -93,7 +24,7 @@ class Task:
class Taskmaster:
- "this is here only until the build engine is implemented"
+ "XXX: this is here only until the build engine is implemented"
def __init__(self, targets):
self.targets = targets
@@ -118,10 +49,123 @@ class Taskmaster:
pass
-taskmaster = Taskmaster(map(lambda x: lookup(File, x), targets))
+# Global variables
+
+Scripts = []
+
+# utility functions
+
+def _scons_syntax_error(e):
+ """Handle syntax errors. Print out a message and show where the error
+ occurred.
+ """
+ etype, value, tb = sys.exc_info()
+ lines = traceback.format_exception_only(etype, value)
+ for line in lines:
+ sys.stderr.write(line+'\n')
+
+def _scons_user_error(e):
+ """Handle user errors. Print out a message and a description of the
+ error, along with the line number and routine where it occured.
+ """
+ print 'user error'
+ etype, value, tb = sys.exc_info()
+ while tb.tb_next is not None:
+ tb = tb.tb_next
+ lineno = traceback.tb_lineno(tb)
+ filename = tb.tb_frame.f_code.co_filename
+ routine = tb.tb_frame.f_code.co_name
+ sys.stderr.write("\nSCons error: %s\n" % value)
+ sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine))
+
+def _scons_other_errors():
+ """Handle all errors but user errors. Print out a message telling
+ the user what to do in this case and print a normal trace.
+ """
+ print 'other errors'
+ traceback.print_exc()
+
+
+def PrintUsage():
+ print "Usage: scons [OPTION]... TARGET..."
+ print "Build TARGET or multiple TARGET(s)"
+ print " "
+ print ' -f CONSCRIPT execute CONSCRIPT instead of "SConstruct"'
+ print " -j N execute N parallel jobs"
+ print " --help print this message and exit"
+
+def Conscript(filename):
+ Scripts.append(filename)
+
+def main():
+ global Scripts
+
+ try:
+ opts, targets = getopt.getopt(sys.argv[1:], 'f:j:', ['help'])
+ except getopt.GetoptError, x:
+ print x
+ PrintUsage()
+ sys.exit(1)
+
+ num_jobs = 1
+ for o, a in opts:
+ if o == '-f': Scripts.append(a)
-jobs = scons.Job.Jobs(num_jobs, taskmaster)
-jobs.start()
-jobs.wait()
+ if o == '-j':
+ try:
+ num_jobs = int(a)
+ except:
+ PrintUsage()
+ sys.exit(1)
+ if num_jobs <= 0:
+ PrintUsage()
+ sys.exit(1)
+ if o == '--help':
+ PrintUsage()
+ sys.exit(0)
+
+ if not Scripts:
+ Scripts.append('SConstruct')
+
+
+ # XXX The commented-out code here adds any "scons" subdirs in anything
+ # along sys.path to sys.path. This was an attempt at setting up things
+ # so we can import "node.FS" instead of "scons.Node.FS". This doesn't
+ # quite fit our testing methodology, though, so save it for now until
+ # the right solutions pops up.
+ #
+ #dirlist = []
+ #for dir in sys.path:
+ # scons = os.path.join(dir, 'scons')
+ # if os.path.isdir(scons):
+ # dirlist = dirlist + [scons]
+ # dirlist = dirlist + [dir]
+ #
+ #sys.path = dirlist
+
+ # initialize node factory
+ init()
+
+ while Scripts:
+ file, Scripts = Scripts[0], Scripts[1:]
+ execfile(file)
+
+ taskmaster = Taskmaster(map(lambda x: lookup(File, x), targets))
+
+ jobs = scons.Job.Jobs(num_jobs, taskmaster)
+ jobs.start()
+ jobs.wait()
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ print "Build interrupted."
+ except SyntaxError, e:
+ _scons_syntax_error(e)
+ except UserError, e:
+ _scons_user_error(e)
+ except:
+ _scons_other_errors()
diff --git a/src/scons/Errors.py b/src/scons/Errors.py
new file mode 100644
index 0000000..2709c19
--- /dev/null
+++ b/src/scons/Errors.py
@@ -0,0 +1,18 @@
+"""scons.Errors
+
+This file contains the exception classes used to handle internal
+and user errors in scons.
+
+"""
+
+__revision__ = "Errors.py __REVISION__ __DATE__ __DEVELOPER__"
+
+
+
+class InternalError(Exception):
+ def __init__(self, args=None):
+ self.args = args
+
+class UserError(Exception):
+ def __init__(self, args=None):
+ self.args = args
diff --git a/src/scons/ErrorsTests.py b/src/scons/ErrorsTests.py
new file mode 100644
index 0000000..8d27332
--- /dev/null
+++ b/src/scons/ErrorsTests.py
@@ -0,0 +1,28 @@
+__revision__ = "ErrorsTests.py __REVISION__ __DATE__ __DEVELOPER__"
+
+import sys
+import unittest
+from scons.Errors import InternalError, UserError
+
+
+class ErrorsTestCase(unittest.TestCase):
+ def test_InternalError(self):
+ """Test the InternalError exception."""
+ try:
+ raise InternalError, "test internal error"
+ except InternalError, e:
+ assert e.args == "test internal error"
+
+ def test_UserError(self):
+ """Test the UserError exception."""
+ try:
+ raise UserError, "test user error"
+ except UserError, e:
+ assert e.args == "test user error"
+
+
+
+if __name__ == "__main__":
+ suite = unittest.makeSuite(ErrorsTestCase, 'test_')
+ if not unittest.TextTestRunner().run(suite).wasSuccessful():
+ sys.exit(1)
diff --git a/test/errors.py b/test/errors.py
new file mode 100644
index 0000000..d3b7e04
--- /dev/null
+++ b/test/errors.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+
+__revision__ = "test/t0003.py __REVISION__ __DATE__ __DEVELOPER__"
+
+from TestCmd import TestCmd
+
+test = TestCmd(program = 'scons.py',
+ workdir = '',
+ interpreter = 'python')
+
+test.write('SConstruct1', """
+a ! int(2.0)
+""")
+test.run(chdir = '.', arguments='-f SConstruct1')
+test.fail_test(test.stderr() != """ File "SConstruct1", line 2
+
+ a ! int(2.0)
+
+ ^
+
+SyntaxError: invalid syntax
+
+""")
+
+
+test.write('SConstruct2', """
+raise UserError, 'Depends() require both sources and targets.'
+""")
+test.run(chdir = '.', arguments='-f SConstruct2')
+test.fail_test(test.stderr() != """
+SCons error: Depends() require both sources and targets.
+File "SConstruct2", line 2, in ?
+""")
+
+
+import os
+sconspath = os.path.join(os.getcwd(), 'scons.py')
+
+test.write('SConstruct3', """
+raise InternalError, 'error inside'
+""")
+test.run(chdir = '.', arguments='-f SConstruct3')
+expect = r"""Traceback \((most recent call|innermost) last\):
+ File "%s", line 163, in \?
+ main\(\)
+ File "%s", line 153, in main
+ execfile\(file\)
+ File "SConstruct3", line 2, in \?
+ raise InternalError, 'error inside'
+InternalError: error inside
+""" % (sconspath, sconspath)
+test.fail_test(not test.match_re(test.stderr(), expect))
+
+test.pass_test()