From 12ac0d0b81c71d7374f4706214d15aa5fa610685 Mon Sep 17 00:00:00 2001 From: stevenknight Date: Wed, 15 Sep 2004 19:47:18 +0000 Subject: [PATCH] Fix suffix selection when there's no source file. (Kevin Quick) git-svn-id: http://scons.tigris.org/svn/scons/trunk@1072 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- src/CHANGES.txt | 6 ++ src/engine/SCons/BuilderTests.py | 158 ++++++++++++++++++++++++++++ src/engine/SCons/Script/__init__.py | 12 --- src/engine/SCons/Util.py | 86 +++++++++++++-- src/engine/SCons/UtilTests.py | 9 +- 5 files changed, 247 insertions(+), 24 deletions(-) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 83ec410f..4064121e 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -59,6 +59,9 @@ RELEASE 0.97 - XXX $RPCGEN, $RPCGENFLAGS, $RPCGENCLIENTFLAGS, $RPCGENHEADERFLAGS, $RPCGENSERVICEFLAGS, $RPCGENXDRFLAGS. + - Update the man page to document that prefix and suffix Builder + keyword arguments can be strings, callables or dictionaries. + - Provide more info in the error message when a user tries to build a target multiple ways. @@ -69,6 +72,9 @@ RELEASE 0.97 - XXX - Only replace a Node's builder with a non-null source builder. + - Fix a stack trace when a suffix selection dictionary is passed + an empty source file list. + From Christoph Wiedemann: - Add an Environment.SetDefault() method that only sets values if diff --git a/src/engine/SCons/BuilderTests.py b/src/engine/SCons/BuilderTests.py index d7d7747d..913e6d4f 100644 --- a/src/engine/SCons/BuilderTests.py +++ b/src/engine/SCons/BuilderTests.py @@ -855,6 +855,164 @@ class BuilderTestCase(unittest.TestCase): assert src.source_scanner is None, src.source_scanner assert src.backup_source_scanner == scanner, src.backup_source_scanner + def test_Builder_API(self): + """Test Builder interface. + + Some of this is tested elsewhere in this file, but this is a + quick collection of common operations on builders with various + forms of component specifications.""" + + builder = SCons.Builder.Builder() + + env = Environment(BUILDERS={'Bld':builder}) + r = builder.get_name(env) + assert r == 'Bld', r + r = builder.get_prefix(env) + assert r == '', r + r = builder.get_suffix(env) + assert r == '', r + r = builder.get_src_suffix(env) + assert r == '', r + r = builder.src_suffixes(env) + assert r == [], r + r = builder.targets('foo') + assert r == ['foo'], r + + # src_suffix can be a single string or a list of strings + + builder.set_src_suffix('.foo') + r = builder.get_src_suffix(env) + assert r == '.foo', r + r = builder.src_suffixes(env) + assert r == ['.foo'], r + + builder.set_src_suffix(['.foo', '.bar']) + r = builder.get_src_suffix(env) + assert r == '.foo', r + r = builder.src_suffixes(env) + assert r == ['.foo', '.bar'], r + + builder.set_src_suffix(['.bar', '.foo']) + r = builder.get_src_suffix(env) + assert r == '.bar', r + r = builder.src_suffixes(env) + assert r == ['.bar', '.foo'], r + + # adjust_suffix normalizes the suffix, adding a `.' if needed + + r = builder.adjust_suffix('.foo') + assert r == '.foo', r + r = builder.adjust_suffix('_foo') + assert r == '_foo', r + r = builder.adjust_suffix('$foo') + assert r == '$foo', r + r = builder.adjust_suffix('foo') + assert r == '.foo', r + r = builder.adjust_suffix('f._$oo') + assert r == '.f._$oo', r + + # prefix and suffix can be one of: + # 1. a string (adjusted and env variables substituted), + # 2. a function (passed (env,sources), returns suffix string) + # 3. a dict of src_suffix:suffix settings, key==None is + # default suffix (special case of #2, so adjust_suffix + # not applied) + + builder = SCons.Builder.Builder(prefix='lib', suffix='foo') + + env = Environment(BUILDERS={'Bld':builder}) + r = builder.get_name(env) + assert r == 'Bld', r + r = builder.get_prefix(env) + assert r == 'lib', r + r = builder.get_suffix(env) + assert r == '.foo', r + + mkpref = lambda env,sources: 'Lib' + mksuff = lambda env,sources: '.Foo' + builder = SCons.Builder.Builder(prefix=mkpref, suffix=mksuff) + + env = Environment(BUILDERS={'Bld':builder}) + r = builder.get_name(env) + assert r == 'Bld', r + r = builder.get_prefix(env) + assert r == 'Lib', r + r = builder.get_suffix(env) + assert r == '.Foo', r + + builder = SCons.Builder.Builder(prefix='$PREF', suffix='$SUFF') + + env = Environment(BUILDERS={'Bld':builder},PREF="LIB",SUFF=".FOO") + r = builder.get_name(env) + assert r == 'Bld', r + r = builder.get_prefix(env) + assert r == 'LIB', r + r = builder.get_suffix(env) + assert r == '.FOO', r + + builder = SCons.Builder.Builder(prefix={None:'A_', + '.C':'E_'}, + suffix={None:'.B', + '.C':'.D'}) + + env = Environment(BUILDERS={'Bld':builder}) + r = builder.get_name(env) + assert r == 'Bld', r + r = builder.get_prefix(env) + assert r == 'A_', r + r = builder.get_suffix(env) + assert r == '.B', r + r = builder.get_prefix(env, ['X.C']) + assert r == 'E_', r + r = builder.get_suffix(env, ['X.C']) + assert r == '.D', r + + builder = SCons.Builder.Builder(prefix='A_', suffix={}, action={}) + + env = Environment(BUILDERS={'Bld':builder}) + r = builder.get_name(env) + assert r == 'Bld', r + r = builder.get_prefix(env) + assert r == 'A_', r + r = builder.get_suffix(env) + assert r == None, r + r = builder.get_src_suffix(env) + assert r == '', r + r = builder.src_suffixes(env) + assert r == [], r + + # Builder actions can be a string, a list, or a dictionary + # whose keys are the source suffix. The add_action() + # specifies a new source suffix/action binding. + + builder.add_action('.src_sfx1', 'FOO') + r = builder.get_name(env) + assert r == 'Bld', r + r = builder.get_prefix(env) + assert r == 'A_', r + r = builder.get_suffix(env) + assert r == None, r + r = builder.get_suffix(env, ['X.src_sfx1']) + assert r == None, r + r = builder.get_src_suffix(env) + assert r == '.src_sfx1', r + r = builder.src_suffixes(env) + assert r == ['.src_sfx1'], r + + builder.add_action('.src_sfx2', 'BAR') + + r = builder.get_name(env) + assert r == 'Bld', r + r = builder.get_prefix(env) + assert r == 'A_', r + r = builder.get_suffix(env) + assert r == None, r + r = builder.get_src_suffix(env) + assert r == '.src_sfx1', r + r = builder.src_suffixes(env) + assert r == ['.src_sfx1', '.src_sfx2'], r + + def test_Builder_Args(self): """Testing passing extra args to a builder.""" def buildFunc(target, source, env, s=self): diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py index 6ae76bf6..5dd907c4 100644 --- a/src/engine/SCons/Script/__init__.py +++ b/src/engine/SCons/Script/__init__.py @@ -69,18 +69,6 @@ import SCons.Taskmaster import SCons.Util import SCons.Warnings -# -import __builtin__ -try: - __builtin__.zip -except AttributeError: - def zip(*lists): - result = [] - for i in xrange(len(lists[0])): - result.append(tuple(map(lambda l, i=i: l[i], lists))) - return result - __builtin__.zip = zip - # display = SCons.Util.display progress_display = SCons.Util.DisplayEngine() diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py index 8707ed4e..df2f6040 100644 --- a/src/engine/SCons/Util.py +++ b/src/engine/SCons/Util.py @@ -38,7 +38,7 @@ import stat import string import sys import types -import UserDict +from UserDict import UserDict import UserList import SCons.Errors @@ -94,6 +94,18 @@ except ImportError: return self.__class__(self.data*n) __rmul__ = __mul__ +# +import __builtin__ +try: + __builtin__.zip +except AttributeError: + def zip(*lists): + result = [] + for i in xrange(len(lists[0])): + result.append(tuple(map(lambda l, i=i: l[i], lists))) + return result + __builtin__.zip = zip + _altsep = os.altsep if _altsep is None and sys.platform == 'win32': # My ActivePython 2.0.1 doesn't set os.altsep! What gives? @@ -952,7 +964,7 @@ def render_tree(root, child_func, prune=0, margin=[0], visited={}): return retval def is_Dict(e): - return type(e) is types.DictType or isinstance(e, UserDict.UserDict) + return type(e) is types.DictType or isinstance(e, UserDict) def is_List(e): return type(e) is types.ListType or isinstance(e, UserList.UserList) @@ -1333,16 +1345,74 @@ class CLVar(UserList.UserList): def __str__(self): return string.join(self.data) -class Selector(UserDict.UserDict): - """A callable dictionary that maps file suffixes to dictionary - values.""" +# A dictionary that preserves the order in which items are added. +# Submitted by David Benjamin to ActiveState's Python Cookbook web site: +# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/107747 +# Including fixes/enhancements from the follow-on discussions. +class OrderedDict(UserDict): + def __init__(self, dict = None): + self._keys = [] + UserDict.__init__(self, dict) + + def __delitem__(self, key): + UserDict.__delitem__(self, key) + self._keys.remove(key) + + def __setitem__(self, key, item): + UserDict.__setitem__(self, key, item) + if key not in self._keys: self._keys.append(key) + + def clear(self): + UserDict.clear(self) + self._keys = [] + + def copy(self): + dict = OrderedDict() + dict.update(self) + return dict + + def items(self): + return zip(self._keys, self.values()) + + def keys(self): + return self._keys[:] + + def popitem(self): + try: + key = self._keys[-1] + except IndexError: + raise KeyError('dictionary is empty') + + val = self[key] + del self[key] + + return (key, val) + + def setdefault(self, key, failobj = None): + UserDict.setdefault(self, key, failobj) + if key not in self._keys: self._keys.append(key) + + def update(self, dict): + for (key, val) in dict.items(): + self.__setitem__(key, val) + + def values(self): + return map(self.get, self._keys) + +class Selector(OrderedDict): + """A callable ordered dictionary that maps file suffixes to + dictionary values. We preserve the order in which items are added + so that get_suffix() calls always return the first suffix added.""" def __call__(self, env, source): - ext = splitext(str(source[0]))[1] + try: + ext = splitext(str(source[0]))[1] + except IndexError: + ext = "" try: return self[ext] except KeyError: # Try to perform Environment substitution on the keys of - # emitter_dict before giving up. + # the dictionary before giving up. s_dict = {} for (k,v) in self.items(): if not k is None: @@ -1450,5 +1520,3 @@ def unique(s): if x not in u: u.append(x) return u - - diff --git a/src/engine/SCons/UtilTests.py b/src/engine/SCons/UtilTests.py index d1873908..2b5fdefd 100644 --- a/src/engine/SCons/UtilTests.py +++ b/src/engine/SCons/UtilTests.py @@ -29,6 +29,8 @@ import string import sys import types import unittest +from UserDict import UserDict + from SCons.Util import * import TestCmd @@ -960,8 +962,7 @@ class UtilTestCase(unittest.TestCase): def test_is_Dict(self): assert is_Dict({}) - import UserDict - assert is_Dict(UserDict.UserDict()) + assert is_Dict(UserDict()) assert not is_Dict([]) assert not is_Dict("") if hasattr(types, 'UnicodeType'): @@ -1492,7 +1493,7 @@ class UtilTestCase(unittest.TestCase): s['c'] = 'CCC' assert s['c'] == 'CCC', s['c'] - class DummyEnv(UserDict.UserDict): + class DummyEnv(UserDict): def subst(self, key): if key[0] == '$': return self[key[1:]] @@ -1501,6 +1502,8 @@ class UtilTestCase(unittest.TestCase): env = DummyEnv() s = Selector({'.d' : 'DDD', '.e' : 'EEE'}) + ret = s(env, []) + assert ret == None, ret ret = s(env, ['foo.d']) assert ret == 'DDD', ret ret = s(env, ['bar.e']) -- 2.26.2