summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2002-12-28 05:31:39 (GMT)
committerSteven Knight <knight@baldmt.com>2002-12-28 05:31:39 (GMT)
commit474383d6f14d1594ad394c22afd837d1522175e9 (patch)
treed19629c2db3846ac88b80467547d5e89c15dcb37
parent38d41c10db89f34f72a62d6ada1a4122d4a1cc3f (diff)
downloadSCons-474383d6f14d1594ad394c22afd837d1522175e9.zip
SCons-474383d6f14d1594ad394c22afd837d1522175e9.tar.gz
SCons-474383d6f14d1594ad394c22afd837d1522175e9.tar.bz2
Refactor FunctionAction objects to support -n and -s.
-rw-r--r--SConstruct1
-rw-r--r--doc/man/scons.128
-rw-r--r--src/CHANGES.txt6
-rw-r--r--src/RELEASE.txt3
-rw-r--r--src/engine/SCons/Action.py88
-rw-r--r--src/engine/SCons/ActionTests.py51
-rw-r--r--src/engine/SCons/BuilderTests.py8
-rw-r--r--src/engine/SCons/Environment.py41
-rw-r--r--src/engine/SCons/Node/FS.py69
-rw-r--r--src/engine/SCons/Node/FSTests.py23
-rw-r--r--src/engine/SCons/Script/__init__.py26
-rw-r--r--test/SetBuildSignatureType.py23
-rw-r--r--test/SetContentSignatureType.py28
-rw-r--r--test/SideEffect.py22
-rw-r--r--test/chained-build.py10
-rw-r--r--test/option-n.py19
-rw-r--r--test/scan-once.py6
-rw-r--r--test/sconsign.py3
-rw-r--r--test/timestamp-fallback.py14
19 files changed, 302 insertions, 167 deletions
diff --git a/SConstruct b/SConstruct
index ba3399a..be5d372 100644
--- a/SConstruct
+++ b/SConstruct
@@ -228,7 +228,6 @@ def SCons_revision(target, source, env):
# this routine will change when the version number changes
# and things will get rebuilt properly.
global version
- print "SCons_revision() < %s > %s" % (s, t)
inf = open(s, 'rb')
outf = open(t, 'wb')
for line in inf.readlines():
diff --git a/doc/man/scons.1 b/doc/man/scons.1
index 26215ad..33718bd 100644
--- a/doc/man/scons.1
+++ b/doc/man/scons.1
@@ -2867,16 +2867,16 @@ Builder objects,
rather than let each separate Builder object
create a separate Action.
-The Action method takes a single argument
+The Action method takes one or two arguments
and returns an appropriate object for the action
-represented by the type of the argument:
+represented by the type of the first argument:
.IP Action
-If the argument is already an Action object,
+If the first argument is already an Action object,
the object is simply returned.
.IP String
-If the argument is a string,
+If the first argument is a string,
a command-line Action is returned.
.ES
@@ -2894,7 +2894,7 @@ Action('$CC -c -o $TARGET $SOURCES')
.IP List
-If the argument is a list,
+If the first argument is a list,
then a list of Action objects is returned.
An Action object is created as necessary
for each element in the list.
@@ -2912,7 +2912,7 @@ Action([['cc', '-c', '-DWHITE SPACE', '-o', '$TARGET', '$SOURCES']])
.EE
.IP Function
-If the argument is a Python function,
+If the first argument is a Python function,
a function Action is returned.
The Python function takes three keyword arguments,
.B target
@@ -2953,6 +2953,22 @@ def build_it(target = None, source = None, env = None):
a = Action(build_it)
.EE
+
+The second, optional argument
+is a Python function that returns
+a string to be printed describing the action being executed.
+This function takes two arguments,
+an array of targets to be created by the function action,
+and an array of sources used to create the target(s):
+
+def build_it(target, source, env):
+ # build the target from the source
+ return 0
+
+def string_it(target, source):
+ return "building '%s' from '%s'" % (target[0], source[0])
+
+a = Action(build_it, string_it)
.PP
If the action argument is not one of the above,
None is returned.
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index f719883..eebe766 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -19,6 +19,12 @@ RELEASE 0.10 - XXX
- Remove Python bytecode (*.pyc) files from the scons-local packages.
+ - Have FunctionActions print a description of what they're doing
+ (a representation of the Python call).
+
+ - Fix the Install() method so that, like other actions, it prints
+ what would have happened when the -n option is used.
+
From Steve Leblanc:
- Add a Clean() method to support removing user-specified targets
diff --git a/src/RELEASE.txt b/src/RELEASE.txt
index 60594de..0280fed 100644
--- a/src/RELEASE.txt
+++ b/src/RELEASE.txt
@@ -42,6 +42,9 @@ RELEASE 0.10 - XXX
consistent. All error messages now begin with "scons: ***"
and all warning messages now begin with "scons: warning:".
+ - SCons now prints a description of Python functions that are
+ invoked to build a target.
+
Please note the following important changes since release 0.08:
- The SetCommandHandler() function has been superceded
diff --git a/src/engine/SCons/Action.py b/src/engine/SCons/Action.py
index 8732bd7..d36c860 100644
--- a/src/engine/SCons/Action.py
+++ b/src/engine/SCons/Action.py
@@ -37,9 +37,13 @@ import string
import sys
import UserDict
-import SCons.Util
import SCons.Errors
+import SCons.Util
+
+class _Null:
+ pass
+_null = _Null
print_actions = 1;
execute_actions = 1;
@@ -71,7 +75,7 @@ class CommandGenerator:
def __init__(self, generator):
self.generator = generator
-def _do_create_action(act):
+def _do_create_action(act, strfunction=_null):
"""This is the actual "implementation" for the
Action factory method, below. This handles the
fact that passing lists to Action() itself has
@@ -89,7 +93,7 @@ def _do_create_action(act):
elif isinstance(act, CommandGenerator):
return CommandGeneratorAction(act.generator)
elif callable(act):
- return FunctionAction(act)
+ return FunctionAction(act, strfunction=strfunction)
elif SCons.Util.is_String(act):
var=SCons.Util.get_environment_var(act)
if var:
@@ -109,17 +113,17 @@ def _do_create_action(act):
else:
return None
-def Action(act):
+def Action(act, strfunction=_null):
"""A factory for action objects."""
if SCons.Util.is_List(act):
- acts = filter(lambda x: not x is None,
- map(_do_create_action, act))
+ acts = map(lambda x, s=strfunction: _do_create_action(x, s), act)
+ acts = filter(lambda x: not x is None, acts)
if len(acts) == 1:
return acts[0]
else:
return ListAction(acts)
else:
- return _do_create_action(act)
+ return _do_create_action(act, strfunction=strfunction)
class ActionBase:
"""Base class for actions that create output objects."""
@@ -202,10 +206,10 @@ class CommandAction(ActionBase):
handle lists of commands, even though that's not how we use it
externally.
"""
+ import SCons.Util
+
escape = env.get('ESCAPE', lambda x: x)
- import SCons.Errors
-
if env.has_key('SHELL'):
shell = env['SHELL']
else:
@@ -271,8 +275,6 @@ class CommandGeneratorAction(ActionBase):
self.generator = generator
def __generate(self, target, source, env, for_signature):
- import SCons.Util
-
# ensure that target is a list, to make it easier to write
# generator functions:
if not SCons.Util.is_List(target):
@@ -315,21 +317,45 @@ class LazyCmdGenerator:
class FunctionAction(ActionBase):
"""Class for Python function actions."""
- def __init__(self, function):
- self.function = function
+
+ def __init__(self, execfunction, strfunction=_null):
+ self.execfunction = execfunction
+ if strfunction is _null:
+ def strfunction(target, source, execfunction=execfunction):
+ def quote(s):
+ return '"' + str(s) + '"'
+ try:
+ name = execfunction.__name__
+ except AttributeError:
+ try:
+ name = execfunction.__class__.__name__
+ except AttributeError:
+ name = "unknown_python_function"
+ if len(target) == 1:
+ tstr = quote(target[0])
+ else:
+ tstr = str(map(lambda x, q=quote: q(x), target))
+ if len(source) == 1:
+ sstr = quote(source[0])
+ else:
+ sstr = str(map(lambda x, q=quote: q(x), source))
+ return "%s(%s, %s)" % (name, tstr, sstr)
+ self.strfunction = strfunction
def execute(self, target, source, env):
- # if print_actions:
- # XXX: WHAT SHOULD WE PRINT HERE?
+ r = 0
+ if not SCons.Util.is_List(target):
+ target = [target]
+ if not SCons.Util.is_List(source):
+ source = [source]
+ if print_actions and self.strfunction:
+ s = self.strfunction(target, source)
+ if s:
+ self.show(s)
if execute_actions:
- if not SCons.Util.is_List(target):
- target = [target]
-
- if not SCons.Util.is_List(source):
- source = [source]
rsources = map(rfile, source)
-
- return self.function(target=target, source=rsources, env=env)
+ r = self.execfunction(target=target, source=rsources, env=env)
+ return r
def get_contents(self, target, source, env):
"""Return the signature contents of this callable action.
@@ -340,11 +366,11 @@ class FunctionAction(ActionBase):
#XXX DOES NOT ACCOUNT FOR CHANGES IN ENVIRONMENT VARIABLES
#THE FUNCTION MAY USE
try:
- # "self.function" is a function.
- code = self.function.func_code.co_code
+ # "self.execfunction" is a function.
+ code = self.execfunction.func_code.co_code
except:
- # "self.function" is a callable object.
- code = self.function.__call__.im_func.func_code.co_code
+ # "self.execfunction" is a callable object.
+ code = self.execfunction.__call__.im_func.func_code.co_code
return str(code)
class ListAction(ActionBase):
@@ -367,9 +393,7 @@ class ListAction(ActionBase):
Simple concatenation of the signatures of the elements.
"""
-
- ret = ""
- for a in self.list:
- ret = ret + a.get_contents(target, source, env)
- return ret
-
+ return string.join(map(lambda x, t=target, s=source, e=env:
+ x.get_contents(t, s, e),
+ self.list),
+ "")
diff --git a/src/engine/SCons/ActionTests.py b/src/engine/SCons/ActionTests.py
index 2f262bf..6c3f779 100644
--- a/src/engine/SCons/ActionTests.py
+++ b/src/engine/SCons/ActionTests.py
@@ -105,9 +105,11 @@ class ActionTestCase(unittest.TestCase):
"""
def foo():
pass
+ def bar():
+ pass
a1 = SCons.Action.Action(foo)
assert isinstance(a1, SCons.Action.FunctionAction), a1
- assert a1.function == foo, a1.function
+ assert a1.execfunction == foo, a1.execfunction
a2 = SCons.Action.Action("string")
assert isinstance(a2, SCons.Action.CommandAction), a2
@@ -156,10 +158,15 @@ class ActionTestCase(unittest.TestCase):
assert isinstance(a10.list[0], SCons.Action.CommandAction), a10.list[0]
assert a10.list[0].cmd_list == ["x"], a10.list[0].cmd_list
assert isinstance(a10.list[1], SCons.Action.FunctionAction), a10.list[1]
- assert a10.list[1].function == foo, a10.list[1].function
+ assert a10.list[1].execfunction == foo, a10.list[1].execfunction
assert isinstance(a10.list[2], SCons.Action.CommandAction), a10.list[2]
assert a10.list[2].cmd_list == ["z"], a10.list[2].cmd_list
+ a11 = SCons.Action.Action(foo, strfunction=bar)
+ assert isinstance(a11, SCons.Action.FunctionAction), a11
+ assert a11.execfunction == foo, a11.execfunction
+ assert a11.strfunction == bar, a11.strfunction
+
class ActionBaseTestCase(unittest.TestCase):
def test_cmp(self):
@@ -487,10 +494,30 @@ class FunctionActionTestCase(unittest.TestCase):
def test_init(self):
"""Test creation of a function Action
"""
- def func():
+ def func1():
+ pass
+ def func2():
pass
- a = SCons.Action.FunctionAction(func)
- assert a.function == func
+ def func3():
+ pass
+ def func4():
+ pass
+
+ a = SCons.Action.FunctionAction(func1)
+ assert a.execfunction == func1, a.execfunction
+ assert isinstance(a.strfunction, types.FunctionType)
+
+ a = SCons.Action.FunctionAction(func2, strfunction=func3)
+ assert a.execfunction == func2, a.execfunction
+ assert a.strfunction == func3, a.strfunction
+
+ a = SCons.Action.FunctionAction(func3, func4)
+ assert a.execfunction == func3, a.execfunction
+ assert a.strfunction == func4, a.strfunction
+
+ a = SCons.Action.FunctionAction(func4, None)
+ assert a.execfunction == func4, a.execfunction
+ assert a.strfunction is None, a.strfunction
def test_execute(self):
"""Test executing a function Action
@@ -555,6 +582,18 @@ class FunctionActionTestCase(unittest.TestCase):
c = test.read(outfile, 'r')
assert c == "class1b\n", c
+ def build_it(target, source, env, self=self):
+ self.build_it = 1
+ return 0
+ def string_it(target, source, self=self):
+ self.string_it = 1
+ return None
+ act = SCons.Action.FunctionAction(build_it, string_it)
+ r = act.execute([], [], Environment())
+ assert r == 0, r
+ assert self.build_it
+ assert self.string_it
+
def test_get_contents(self):
"""Test fetching the contents of a function Action
"""
@@ -677,7 +716,7 @@ if __name__ == "__main__":
CommandGeneratorActionTestCase,
FunctionActionTestCase,
ListActionTestCase,
- LazyActionTestCase]
+ LazyActionTestCase ]
for tclass in tclasses:
names = unittest.getTestCaseNames(tclass, 'test_')
suite.addTests(map(tclass, names))
diff --git a/src/engine/SCons/BuilderTests.py b/src/engine/SCons/BuilderTests.py
index a2369b9..5906314 100644
--- a/src/engine/SCons/BuilderTests.py
+++ b/src/engine/SCons/BuilderTests.py
@@ -36,6 +36,8 @@ import types
import unittest
import TestCmd
+
+import SCons.Action
import SCons.Builder
import SCons.Errors
import SCons.Node.FS
@@ -188,7 +190,11 @@ class BuilderTestCase(unittest.TestCase):
def func():
pass
builder = SCons.Builder.Builder(name="builder", action=func)
- assert builder.action.function == func
+ assert isinstance(builder.action, SCons.Action.FunctionAction)
+ # Preserve the following so that the baseline test will fail.
+ # Remove it in favor of the previous test at some convenient
+ # point in the future.
+ assert builder.action.execfunction == func
def test_generator(self):
"""Test Builder creation given a generator function."""
diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py
index ec8f1eb..480169e 100644
--- a/src/engine/SCons/Environment.py
+++ b/src/engine/SCons/Environment.py
@@ -38,40 +38,25 @@ import shutil
import string
import sys
import types
+from UserDict import UserDict
+import SCons.Action
import SCons.Builder
import SCons.Defaults
-from SCons.Errors import UserError
+import SCons.Errors
import SCons.Node
import SCons.Node.FS
-import SCons.Util
-import SCons.Warnings
-from UserDict import UserDict
import SCons.Platform
import SCons.Tool
+import SCons.Util
+import SCons.Warnings
+
+def installString(target, source):
+ return 'Install file: "%s" as "%s"' % (source[0], target[0])
+
+installAction = SCons.Action.Action(SCons.Node.FS.LinkFunc, installString)
-def installFunc(target, source, env):
- try:
- map(lambda t: os.unlink(str(t)), target)
- except OSError:
- pass
-
- try:
- SCons.Node.FS.file_link(str(source[0]), str(target[0]))
- print 'Install file: "%s" as "%s"' % \
- (source[0], target[0])
- return 0
- except IOError, e:
- sys.stderr.write('Unable to install "%s" as "%s"\n%s\n' % \
- (source[0], target[0], str(e)))
- return -1
- except OSError, e:
- sys.stderr.write('Unable to install "%s" as "%s"\n%s\n' % \
- (source[0], target[0], str(e)))
- return -1
-
-InstallBuilder = SCons.Builder.Builder(name='Install',
- action=installFunc)
+InstallBuilder = SCons.Builder.Builder(name='Install', action=installAction)
def our_deepcopy(x):
"""deepcopy lists and dictionaries, and just copy the reference
@@ -232,7 +217,7 @@ class Environment:
for name, builder in bd.items():
setattr(self, name, BuilderWrapper(self, builder))
else:
- raise UserError, "The use of the BUILDERS Environment variable as a list or Builder instance is deprecated. BUILDERS should be a dictionary of name->Builder instead."
+ raise SCons.Errors.UserError, "The use of the BUILDERS Environment variable as a list or Builder instance is deprecated. BUILDERS should be a dictionary of name->Builder instead."
for s in self._dict['SCANNERS']:
setattr(self, s.name, s)
@@ -378,7 +363,7 @@ class Environment:
# buildable without actually having a builder, so we allow
# it to be a side effect as well.
if side_effect.builder is not None and side_effect.builder != 1:
- raise UserError, "Multiple ways to build the same target were specified for: %s" % str(side_effect)
+ raise SCons.Errors.UserError, "Multiple ways to build the same target were specified for: %s" % str(side_effect)
side_effect.add_source(targets)
side_effect.side_effect = 1
self.Precious(side_effect)
diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py
index 5c01c9d..626a22a 100644
--- a/src/engine/SCons/Node/FS.py
+++ b/src/engine/SCons/Node/FS.py
@@ -36,19 +36,35 @@ canonical default.
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
-import string
import os
import os.path
+import string
+import sys
import types
-import SCons.Node
from UserDict import UserDict
-import sys
+
+import SCons.Action
import SCons.Errors
+import SCons.Node
import SCons.Warnings
-execute_actions = 1
+#
+# SCons.Action objects for interacting with the outside world.
+#
+# The Node.FS methods in this module should use these actions to
+# create and/or remove files and directories; they should *not* use
+# os.{link,symlink,unlink,mkdir}(), etc., directly.
+#
+# Using these SCons.Action objects ensures that descriptions of these
+# external activities are properly displayed, that the displays are
+# suppressed when the -s (silent) option is used, and (most importantly)
+# the actions are disabled when the the -n option is used, in which case
+# there should be *no* changes to the external file system(s)...
+#
-def file_link(src, dest):
+def LinkFunc(target, source, env):
+ src = source[0].path
+ dest = target[0].path
dir, file = os.path.split(dest)
if dir and not os.path.isdir(dir):
os.makedirs(dir)
@@ -56,17 +72,37 @@ def file_link(src, dest):
# fails, try a symlink. If that fails then just copy it.
try :
os.link(src, dest)
- except (AttributeError, OSError) :
+ except (AttributeError, OSError):
try :
os.symlink(src, dest)
- except (AttributeError, OSError) :
+ except (AttributeError, OSError):
import shutil
import stat
shutil.copy2(src, dest)
st=os.stat(src)
os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
+ return 0
+
+LinkAction = SCons.Action.Action(LinkFunc, None)
+
+def LocalString(target, source):
+ return 'Local copy of %s from %s' % (target[0], source[0])
+
+LocalCopy = SCons.Action.Action(LinkFunc, LocalString)
+
+def UnlinkFunc(target, source, env):
+ os.unlink(target[0].path)
+ return 0
+UnlinkAction = SCons.Action.Action(UnlinkFunc, None)
+def MkdirFunc(target, source, env):
+ os.mkdir(target[0].path)
+ return 0
+
+MkdirAction = SCons.Action.Action(MkdirFunc, None)
+
+#
class ParentOfRoot:
"""
An instance of this class is used as the parent of the root of a
@@ -842,13 +878,11 @@ class File(Entry):
if isinstance(p, ParentOfRoot):
raise SCons.Errors.StopError, parent.path
parent = p
- if not execute_actions:
- return
listDirs.reverse()
for dirnode in listDirs:
+ dirnode._exists = 1
try:
- os.mkdir(dirnode.abspath)
- dirnode._exists = 1
+ MkdirAction.execute(dirnode, None, None)
except OSError:
pass
@@ -871,8 +905,7 @@ class File(Entry):
if self.exists():
if self.builder and not self.precious:
- if execute_actions:
- os.unlink(self.path)
+ UnlinkAction.execute(self, None, None)
if hasattr(self, '_exists'):
delattr(self, '_exists')
else:
@@ -894,12 +927,12 @@ class File(Entry):
if self.duplicate and not self.builder and not self.created:
src=self.srcnode().rfile()
if src.exists() and src.abspath != self.abspath:
+ self._createDir()
try:
- os.unlink(self.abspath)
+ UnlinkAction.execute(self, None, None)
except OSError:
pass
- self._createDir()
- file_link(src.abspath, self.abspath)
+ LinkAction.execute(self, src, None)
self.created = 1
# Set our exists cache accordingly
@@ -919,9 +952,7 @@ class File(Entry):
# ...and it's even up-to-date...
if self._local:
# ...and they'd like a local copy.
- print "Local copy of %s from %s" % (self.path, r.path)
- if execute_actions:
- file_link(r.path, self.path)
+ LocalCopy.execute(self, r, None)
self.set_bsig(bsig)
self.store_bsig()
return 1
diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py
index 43fa41f..98857bf 100644
--- a/src/engine/SCons/Node/FSTests.py
+++ b/src/engine/SCons/Node/FSTests.py
@@ -90,7 +90,6 @@ class BuildDirTestCase(unittest.TestCase):
def runTest(self):
"""Test build dir functionality"""
test=TestCmd(workdir='')
- os.chdir(test.workdir)
fs = SCons.Node.FS.FS()
f1 = fs.File('build/test1')
@@ -157,6 +156,8 @@ class BuildDirTestCase(unittest.TestCase):
test.write([ 'rep1', 'build', 'var1', 'test2.out' ], 'test2.out_rep')
test.write([ 'rep1', 'build', 'var2', 'test2.out' ], 'test2.out_rep')
+ os.chdir(test.workpath('work'))
+
fs = SCons.Node.FS.FS(test.workpath('work'))
fs.BuildDir('build/var1', 'src', duplicate=0)
fs.BuildDir('build/var2', 'src')
@@ -254,12 +255,13 @@ class BuildDirTestCase(unittest.TestCase):
assert f8.rfile().path == os.path.normpath(test.workpath('rep1/build/var2/test2.out')),\
f8.rfile().path
- # Test to see if file_link() works...
+ # Test to see if LinkAction() works...
test.subdir('src','build')
- test.write('src/foo', 'foo\n')
+ test.write('src/foo', 'src/foo\n')
os.chmod(test.workpath('src/foo'), stat.S_IRUSR)
- SCons.Node.FS.file_link(test.workpath('src/foo'),
- test.workpath('build/foo'))
+ SCons.Node.FS.LinkAction.execute(fs.File(test.workpath('build/foo')),
+ fs.File(test.workpath('src/foo')),
+ None)
os.chmod(test.workpath('src/foo'), stat.S_IRUSR | stat.S_IWRITE)
st=os.stat(test.workpath('build/foo'))
assert (stat.S_IMODE(st[stat.ST_MODE]) & stat.S_IWRITE), \
@@ -352,14 +354,11 @@ class BuildDirTestCase(unittest.TestCase):
os.symlink = simulator.symlink_fail
shutil.copy2 = simulator.copy
- # XXX this is just to pass the baseline test, it won't be needed once
- # this change is integrated
- SCons.Node.FS._link = simulator.link_fail
-
- test.write('src/foo', 'foo\n')
+ test.write('src/foo', 'src/foo\n')
os.chmod(test.workpath('src/foo'), stat.S_IRUSR)
- SCons.Node.FS.file_link(test.workpath('src/foo'),
- test.workpath('build/foo'))
+ SCons.Node.FS.LinkAction.execute(fs.File(test.workpath('build/foo')),
+ fs.File(test.workpath('src/foo')),
+ None)
test.unlink( "src/foo" )
test.unlink( "build/foo" )
diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py
index b4afb3c..093b82c 100644
--- a/src/engine/SCons/Script/__init__.py
+++ b/src/engine/SCons/Script/__init__.py
@@ -55,17 +55,16 @@ import copy
# 'lib',
# 'scons-%d' % SCons.__version__)] + sys.path[1:]
+import SCons.Errors
+import SCons.Job
import SCons.Node
import SCons.Node.FS
-import SCons.Job
-from SCons.Errors import *
-import SCons.Sig
-from SCons.Taskmaster import Taskmaster
-import SCons.Builder
-import SCons.Script.SConscript
-import SCons.Warnings
from SCons.Optik import OptionParser, SUPPRESS_HELP, OptionValueError
+import SCons.Script.SConscript
+import SCons.Sig
+import SCons.Taskmaster
from SCons.Util import display
+import SCons.Warnings
#
@@ -124,15 +123,15 @@ class BuildTask(SCons.Taskmaster.Task):
def failed(self):
e = sys.exc_value
- if sys.exc_type == BuildError:
+ if sys.exc_type == SCons.Errors.BuildError:
sys.stderr.write("scons: *** [%s] %s\n" % (e.node, e.errstr))
if e.errstr == 'Exception':
traceback.print_exception(e.args[0], e.args[1], e.args[2])
- elif sys.exc_type == UserError:
+ elif sys.exc_type == SCons.Errors.UserError:
# We aren't being called out of a user frame, so
# don't try to walk the stack, just print the error.
sys.stderr.write("\nscons: *** %s\n" % e)
- elif sys.exc_type == StopError:
+ elif sys.exc_type == SCons.Errors.StopError:
s = str(e)
if not keep_going_on_error:
s = s + ' Stop.'
@@ -661,7 +660,6 @@ def _main():
_setup_warn(options.warn)
if options.noexec:
SCons.Action.execute_actions = None
- SCons.Node.FS.execute_actions = None
CleanTask.execute = CleanTask.show
if options.no_progress or options.silent:
display.set_mode(0)
@@ -696,7 +694,7 @@ def _main():
display("scons: Entering directory %s" % script_dir)
os.chdir(script_dir)
else:
- raise UserError, "No SConstruct file found."
+ raise SCons.Errors.UserError, "No SConstruct file found."
SCons.Node.FS.default_fs.set_toplevel_dir(os.getcwd())
@@ -718,7 +716,7 @@ def _main():
SCons.Script.SConscript.print_help = 1
if not scripts:
- raise UserError, "No SConstruct file found."
+ raise SCons.Errors.UserError, "No SConstruct file found."
class Unbuffered:
def __init__(self, file):
@@ -863,7 +861,7 @@ def main():
sys.exit(2)
except SyntaxError, e:
_scons_syntax_error(e)
- except UserError, e:
+ except SCons.Errors.UserError, e:
_scons_user_error(e)
except:
_scons_other_errors()
diff --git a/test/SetBuildSignatureType.py b/test/SetBuildSignatureType.py
index b9dd080..2ec9773 100644
--- a/test/SetBuildSignatureType.py
+++ b/test/SetBuildSignatureType.py
@@ -32,7 +32,6 @@ test.write('SConstruct', """
env = Environment()
def copy1(env, source, target):
- print 'copy %s -> %s'%(str(source[0]), str(target[0]))
open(str(target[0]), 'wb').write(open(str(source[0]), 'rb').read())
def copy2(env, source, target):
@@ -50,7 +49,10 @@ SetBuildSignatureType('content')
test.write('foo.in', 'foo.in')
test.run(arguments='foo.out.out',
- stdout=test.wrap_stdout('copy foo.in -> foo.out\ncopy foo.out -> foo.out.out\n'))
+ stdout=test.wrap_stdout("""\
+copy2("foo.out", "foo.in")
+copy1("foo.out.out", "foo.out")
+"""))
test.run(arguments='foo.out.out',
stdout=test.wrap_stdout('scons: "foo.out.out" is up to date.\n'))
@@ -59,7 +61,6 @@ test.write('SConstruct', """
env = Environment()
def copy1(env, source, target):
- print 'copy %s -> %s'%(str(source[0]), str(target[0]))
open(str(target[0]), 'wb').write(open(str(source[0]), 'rb').read())
def copy2(env, source, target):
@@ -76,13 +77,15 @@ SetBuildSignatureType('content')
""")
test.run(arguments='foo.out.out',
- stdout=test.wrap_stdout('copy foo.in -> foo.out\nscons: "foo.out.out" is up to date.\n'))
+ stdout=test.wrap_stdout("""\
+copy2("foo.out", "foo.in")
+scons: "foo.out.out" is up to date.
+"""))
test.write('SConstruct', """
env = Environment()
def copy1(env, source, target):
- print 'copy %s -> %s'%(str(source[0]), str(target[0]))
open(str(target[0]), 'wb').write(open(str(source[0]), 'rb').read())
def copy2(env, source, target):
@@ -99,13 +102,14 @@ SetBuildSignatureType('build')
""")
test.run(arguments='foo.out.out',
- stdout=test.wrap_stdout('copy foo.out -> foo.out.out\n'))
+ stdout=test.wrap_stdout("""\
+copy1("foo.out.out", "foo.out")
+"""))
test.write('SConstruct', """
env = Environment()
def copy1(env, source, target):
- print 'copy %s -> %s'%(str(source[0]), str(target[0]))
open(str(target[0]), 'wb').write(open(str(source[0]), 'rb').read())
def copy2(env, source, target):
@@ -121,7 +125,10 @@ SetBuildSignatureType('build')
""")
test.run(arguments='foo.out.out',
- stdout=test.wrap_stdout('copy foo.in -> foo.out\ncopy foo.out -> foo.out.out\n'))
+ stdout=test.wrap_stdout("""\
+copy2("foo.out", "foo.in")
+copy1("foo.out.out", "foo.out")
+"""))
test.pass_test()
diff --git a/test/SetContentSignatureType.py b/test/SetContentSignatureType.py
index f9915ad..17fba2e 100644
--- a/test/SetContentSignatureType.py
+++ b/test/SetContentSignatureType.py
@@ -53,7 +53,12 @@ test.write('f4.in', "f4.in\n")
test.run(arguments = 'f1.out f3.out')
test.run(arguments = 'f1.out f2.out f3.out f4.out',
- stdout = test.wrap_stdout('scons: "f1.out" is up to date.\nscons: "f3.out" is up to date.\n'))
+ stdout = test.wrap_stdout("""\
+scons: "f1.out" is up to date.
+build("f2.out", "f2.in")
+scons: "f3.out" is up to date.
+build("f4.out", "f4.in")
+"""))
os.utime(test.workpath('f1.in'),
(os.path.getatime(test.workpath('f1.in')),
@@ -63,7 +68,12 @@ os.utime(test.workpath('f3.in'),
os.path.getmtime(test.workpath('f3.in'))+10))
test.run(arguments = 'f1.out f2.out f3.out f4.out',
- stdout = test.wrap_stdout('scons: "f2.out" is up to date.\nscons: "f4.out" is up to date.\n'))
+ stdout = test.wrap_stdout("""\
+build("f1.out", "f1.in")
+scons: "f2.out" is up to date.
+build("f3.out", "f3.in")
+scons: "f4.out" is up to date.
+"""))
test.write('SConstruct', """
def build(env, target, source):
@@ -86,7 +96,12 @@ test.write('f4.in', "f4.in\n")
test.run(arguments = 'f1.out f3.out')
test.run(arguments = 'f1.out f2.out f3.out f4.out',
- stdout = test.wrap_stdout('scons: "f1.out" is up to date.\nscons: "f3.out" is up to date.\n'))
+ stdout = test.wrap_stdout("""\
+scons: "f1.out" is up to date.
+build("f2.out", "f2.in")
+scons: "f3.out" is up to date.
+build("f4.out", "f4.in")
+"""))
os.utime(test.workpath('f1.in'),
(os.path.getatime(test.workpath('f1.in')),
@@ -110,7 +125,12 @@ env.B(target = 'f4.out', source = 'f4.in')
""")
test.run(arguments = 'f1.out f2.out f3.out f4.out',
- stdout = test.wrap_stdout('scons: "f1.out" is up to date.\nscons: "f2.out" is up to date.\nscons: "f3.out" is up to date.\nscons: "f4.out" is up to date.\n'))
+ stdout = test.wrap_stdout("""\
+scons: "f1.out" is up to date.
+scons: "f2.out" is up to date.
+scons: "f3.out" is up to date.
+scons: "f4.out" is up to date.
+"""))
test.pass_test()
diff --git a/test/SideEffect.py b/test/SideEffect.py
index 29acb83..2fdf90d 100644
--- a/test/SideEffect.py
+++ b/test/SideEffect.py
@@ -32,7 +32,6 @@ test = TestSCons.TestSCons()
test.write('SConstruct',
"""
def copy(source, target):
- print 'copy() < %s > %s' % (source, target)
open(target, "wb").write(open(source, "rb").read())
def build(env, source, target):
@@ -55,8 +54,8 @@ test.write('bar.in', 'bar.in\n')
test.write('blat.in', 'blat.in\n')
test.run(arguments = 'foo.out bar.out', stdout=test.wrap_stdout("""\
-copy() < foo.in > foo.out
-copy() < bar.in > bar.out
+build("foo.out", "foo.in")
+build("bar.out", "bar.in")
"""))
expect = """\
@@ -68,8 +67,8 @@ assert test.read('log.txt') == expect
test.write('bar.in', 'bar.in 2 \n')
test.run(arguments = 'log.txt', stdout=test.wrap_stdout("""\
-copy() < bar.in > bar.out
-copy() < blat.in > blat.out
+build("bar.out", "bar.in")
+build("blat.out", "blat.in")
"""))
expect = """\
@@ -83,8 +82,8 @@ assert test.read('log.txt') == expect
test.write('foo.in', 'foo.in 2 \n')
test.run(arguments = ".", stdout=test.wrap_stdout("""\
-copy() < foo.in > foo.out
-copy() < log.txt > log.out
+build("foo.out", "foo.in")
+build("log.out", "log.txt")
"""))
expect = """\
@@ -104,10 +103,10 @@ test.fail_test(os.path.exists(test.workpath('blat.out')))
test.fail_test(os.path.exists(test.workpath('log.txt')))
test.run(arguments = "-j 4 .", stdout=test.wrap_stdout("""\
-copy() < bar.in > bar.out
-copy() < blat.in > blat.out
-copy() < foo.in > foo.out
-copy() < log.txt > log.out
+build("bar.out", "bar.in")
+build("blat.out", "blat.in")
+build("foo.out", "foo.in")
+build("log.out", "log.txt")
"""))
expect = """\
@@ -123,7 +122,6 @@ import os.path
import os
def copy(source, target):
- print 'copy() < %s > %s' % (source, target)
open(target, "wb").write(open(source, "rb").read())
def build(env, source, target):
diff --git a/test/chained-build.py b/test/chained-build.py
index 94277fd..fc0d2d4 100644
--- a/test/chained-build.py
+++ b/test/chained-build.py
@@ -31,7 +31,6 @@ test = TestSCons.TestSCons()
test.write('SConstruct1', """
def build(env, target, source):
open(str(target[0]), 'wt').write(open(str(source[0]), 'rt').read())
- print "built %s"%target[0]
env=Environment(BUILDERS={'B' : Builder(action=build)})
env.B('foo.mid', 'foo.in')
@@ -40,7 +39,6 @@ env.B('foo.mid', 'foo.in')
test.write('SConstruct2', """
def build(env, target, source):
open(str(target[0]), 'wt').write(open(str(source[0]), 'rt').read())
- print "built %s"%target[0]
env=Environment(BUILDERS={'B' : Builder(action=build)})
env.B('foo.out', 'foo.mid')
@@ -49,9 +47,9 @@ env.B('foo.out', 'foo.mid')
test.write('foo.in', "foo.in")
test.run(arguments="--max-drift=0 -f SConstruct1 foo.mid",
- stdout = test.wrap_stdout('built foo.mid\n'))
+ stdout = test.wrap_stdout('build("foo.mid", "foo.in")\n'))
test.run(arguments="--max-drift=0 -f SConstruct2 foo.out",
- stdout = test.wrap_stdout('built foo.out\n'))
+ stdout = test.wrap_stdout('build("foo.out", "foo.mid")\n'))
test.run(arguments="--max-drift=0 -f SConstruct1 foo.mid",
stdout = test.wrap_stdout('scons: "foo.mid" is up to date.\n'))
@@ -61,9 +59,9 @@ test.run(arguments="--max-drift=0 -f SConstruct2 foo.out",
test.write('foo.in', "foo.in 2")
test.run(arguments="--max-drift=0 -f SConstruct1 foo.mid",
- stdout = test.wrap_stdout('built foo.mid\n'))
+ stdout = test.wrap_stdout('build("foo.mid", "foo.in")\n'))
test.run(arguments="--max-drift=0 -f SConstruct2 foo.out",
- stdout = test.wrap_stdout('built foo.out\n'))
+ stdout = test.wrap_stdout('build("foo.out", "foo.mid")\n'))
test.run(arguments="--max-drift=0 -f SConstruct1 foo.mid",
stdout = test.wrap_stdout('scons: "foo.mid" is up to date.\n'))
diff --git a/test/option-n.py b/test/option-n.py
index c0ca611..ee21ae7 100644
--- a/test/option-n.py
+++ b/test/option-n.py
@@ -75,7 +75,10 @@ test.write('f3.in', "f3.in\n")
test.write(['src', 'f4.in'], "src/f4.in\n")
args = 'f1.out f2.out'
-expect = test.wrap_stdout("%s build.py f1.out\n%s build.py f2.out\n" % (python, python))
+expect = test.wrap_stdout("""\
+%s build.py f1.out
+%s build.py f2.out
+""" % (python, python))
test.run(arguments = args, stdout = expect)
test.fail_test(not os.path.exists(test.workpath('f1.out')))
@@ -117,30 +120,18 @@ test.run(arguments = '-c -n ' + args, stdout = expect)
test.fail_test(not os.path.exists(test.workpath('f1.out')))
test.fail_test(not os.path.exists(test.workpath('f2.out')))
-# XXX Because Install is a function action, it doesn't know how
-# to print what's going on when -n is used. Following the
-# directions on the XXX lines below whenever that gets fixed.
#
install_f3_in = os.path.join('install', 'f3.in')
-# XXX Uncomment the next line and remove the one after it when we
-# fix the Install print during -n.
-#expect = test.wrap_stdout('Install file: "f3.in" as "%s"\n' % install_f3_in)
-expect = test.wrap_stdout('')
+expect = test.wrap_stdout('Install file: "f3.in" as "%s"\n' % install_f3_in)
test.run(arguments = '-n install', stdout = expect)
test.fail_test(os.path.exists(test.workpath('install', 'f3.in')))
-# XXX Remove the next line when we fix the Install print during -n.
-expect = test.wrap_stdout('Install file: "f3.in" as "%s"\n' % install_f3_in)
-
test.run(arguments = 'install', stdout = expect)
test.fail_test(not os.path.exists(test.workpath('install', 'f3.in')))
test.write('f3.in', "f3.in again\n")
-# XXX Remove the next line when we fix the Install print during -n.
-expect = test.wrap_stdout('')
-
test.run(arguments = '-n install', stdout = expect)
test.fail_test(not os.path.exists(test.workpath('install', 'f3.in')))
diff --git a/test/scan-once.py b/test/scan-once.py
index 19cb495..a1674e6 100644
--- a/test/scan-once.py
+++ b/test/scan-once.py
@@ -64,9 +64,12 @@ test.write('file1.s', 'file1.s\n')
test.run(arguments = '.',
stdout = test.wrap_stdout("""scanning file1.s for file2.s
+echo("file2.s", "file1.s")
create file2.s from file1.s
scanning file1.s for file2.s
+echo("file3.s", "file2.s")
create file3.s from file2.s
+echo("file4.s", "file3.s")
create file4.s from file3.s
"""))
@@ -75,8 +78,10 @@ test.write('file2.s', 'file2.s\n')
test.run(arguments = '.',
stdout = test.wrap_stdout("""scanning file1.s for file2.s
scanning file2.s for file3.s
+echo("file3.s", "file2.s")
create file3.s from file2.s
scanning file2.s for file3.s
+echo("file4.s", "file3.s")
create file4.s from file3.s
"""))
@@ -86,6 +91,7 @@ test.run(arguments = '.',
stdout = test.wrap_stdout("""scanning file1.s for file2.s
scanning file2.s for file3.s
scanning file3.s for file4.s
+echo("file4.s", "file3.s")
create file4.s from file3.s
"""))
diff --git a/test/sconsign.py b/test/sconsign.py
index 5978da3..6d88f79 100644
--- a/test/sconsign.py
+++ b/test/sconsign.py
@@ -74,7 +74,6 @@ os.chmod(sub1__sconsign, 0666)
test.write('SConstruct', """
def build1(target, source, env):
- print '%s->%s'%(str(source[0]), str(target[0]))
open(str(target[0]), 'wb').write(open(str(source[0]), 'rb').read())
return None
@@ -88,7 +87,7 @@ scons: warning: Ignoring corrupt .sconsign file: sub1..sconsign
.*
'''
-stdout = test.wrap_stdout('foo.in->sub1.foo.out\n')
+stdout = test.wrap_stdout('build1\("sub1/foo.out", "foo.in"\)\n')
test.write(sub1__sconsign, 'not:a:sconsign:file')
test.run(arguments = '.', stderr=stderr, stdout=stdout, status=2)
diff --git a/test/timestamp-fallback.py b/test/timestamp-fallback.py
index 749ee5b..3862ec4 100644
--- a/test/timestamp-fallback.py
+++ b/test/timestamp-fallback.py
@@ -67,7 +67,12 @@ test.write('f4.in', "f4.in\n")
test.run(arguments = 'f1.out f3.out')
test.run(arguments = 'f1.out f2.out f3.out f4.out',
- stdout = test.wrap_stdout('scons: "f1.out" is up to date.\nscons: "f3.out" is up to date.\n'))
+ stdout = test.wrap_stdout("""\
+scons: "f1.out" is up to date.
+build("f2.out", "f2.in")
+scons: "f3.out" is up to date.
+build("f4.out", "f4.in")
+"""))
os.utime(test.workpath('f1.in'),
(os.path.getatime(test.workpath('f1.in')),
@@ -77,7 +82,12 @@ os.utime(test.workpath('f3.in'),
os.path.getmtime(test.workpath('f3.in'))+10))
test.run(arguments = 'f1.out f2.out f3.out f4.out',
- stdout = test.wrap_stdout('scons: "f2.out" is up to date.\nscons: "f4.out" is up to date.\n'))
+ stdout = test.wrap_stdout("""\
+build("f1.out", "f1.in")
+scons: "f2.out" is up to date.
+build("f3.out", "f3.in")
+scons: "f4.out" is up to date.
+"""))
test.pass_test()