From: stevenknight Date: Mon, 18 Aug 2003 05:31:42 +0000 (+0000) Subject: Refactor DictCmdGenerator to be a subclass of Selector. X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=14177a41b774b49210ef589489a6a3eb04445852;p=scons.git Refactor DictCmdGenerator to be a subclass of Selector. git-svn-id: http://scons.tigris.org/svn/scons/trunk@772 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 375bb81f..a990f934 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -14,6 +14,10 @@ RELEASE X.XX - XXX, XX XXX XXXX XX:XX:XX XXXXX - Fix Tool import problems with the Intel and PharLap linkers. + From Steven Knight + + - Refactor the DictCmdGenerator class to be a Selector subclass. + From Gerard Patel - When the yacc -d flag is used, take the .h file base name from the diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py index f7630e63..af03e823 100644 --- a/src/engine/SCons/Builder.py +++ b/src/engine/SCons/Builder.py @@ -59,23 +59,20 @@ class _Null: _null = _Null -class DictCmdGenerator: +class DictCmdGenerator(SCons.Util.Selector): """This is a callable class that can be used as a command generator function. It holds on to a dictionary mapping file suffixes to Actions. It uses that dictionary to return the proper action based on the file suffix of the source file.""" - - def __init__(self, action_dict): - self.action_dict = action_dict def src_suffixes(self): - return self.action_dict.keys() + return self.keys() def add_action(self, suffix, action): """Add a suffix-action pair to the mapping. """ - self.action_dict[suffix] = action + self[suffix] = action def __call__(self, target, source, env, for_signature): ext = None @@ -87,62 +84,25 @@ class DictCmdGenerator: if not ext: raise UserError("While building `%s': Cannot deduce file extension from source files: %s" % (repr(map(str, target)), repr(map(str, source)))) - try: - return self.action_dict[ext] - except KeyError: - # Before raising the user error, try to perform Environment - # substitution on the keys of action_dict. - s_dict = {} - for (k,v) in self.action_dict.items(): - s_k = env.subst(k) - if s_dict.has_key(s_k): - # XXX Note that we do only raise errors, when variables - # point to the same suffix. If one suffix is a - # literal and a variable suffix contains this literal - # we don't raise an error (cause the literal 'wins') - raise UserError("Ambiguous suffixes after environment substitution: %s == %s == %s" % (s_dict[s_k][0], k, s_k)) - s_dict[s_k] = (k,v) - try: - return s_dict[ext][1] - except KeyError: - raise UserError("While building `%s': Don't know how to build a file with suffix %s." % (repr(map(str, target)), repr(ext))) - def __cmp__(self, other): - return cmp(self.action_dict, other.action_dict) - -class Selector(UserDict.UserDict): - """A callable dictionary that maps file suffixes to dictionary - values.""" - def __call__(self, env, source): - ext = SCons.Util.splitext(str(source[0]))[1] try: - return self[ext] - except KeyError: - # Try to perform Environment substitution on the keys of - # emitter_dict before giving up. - s_dict = {} - for (k,v) in self.items(): - if not k is None: - s_k = env.subst(k) - s_dict[s_k] = v - try: - return s_dict[ext] - except KeyError: - try: - return self[None] - except KeyError: - return None + ret = SCons.Util.Selector.__call__(self, env, source) + except KeyError, e: + raise UserError("Ambiguous suffixes after environment substitution: %s == %s == %s" % (e[0], e[1], e[2])) + if ret is None: + raise UserError("While building `%s': Don't know how to build a file with suffix `%s'." % (repr(map(str, target)), ext)) + return ret -class CallableSelector(Selector): - """A callable dictionary that wills, in turn, call the value it +class CallableSelector(SCons.Util.Selector): + """A callable dictionary that will, in turn, call the value it finds if it can.""" def __call__(self, env, source): - value = Selector.__call__(self, env, source) + value = SCons.Util.Selector.__call__(self, env, source) if callable(value): value = value(env, source) return value -class DictEmitter(Selector): +class DictEmitter(SCons.Util.Selector): """A callable dictionary that maps file suffixes to emitters. When called, it finds the right emitter in its dictionary for the suffix of the first source file, and calls that emitter to get the @@ -151,7 +111,7 @@ class DictEmitter(Selector): returned. """ def __call__(self, target, source, env): - emitter = Selector.__call__(self, env, source) + emitter = SCons.Util.Selector.__call__(self, env, source) if emitter: target, source = emitter(target, source, env) return (target, source) @@ -188,7 +148,7 @@ def Builder(**kw): else: ret = apply(BuilderBase, (), kw) - if composite: + if not composite is None: ret = CompositeBuilder(ret, composite) return ret diff --git a/src/engine/SCons/BuilderTests.py b/src/engine/SCons/BuilderTests.py index f65230ca..e0ba2feb 100644 --- a/src/engine/SCons/BuilderTests.py +++ b/src/engine/SCons/BuilderTests.py @@ -700,7 +700,7 @@ class BuilderTestCase(unittest.TestCase): except SCons.Errors.UserError, e: flag = 1 assert flag, "UserError should be thrown when we build targets with files of different suffixes." - match = str(e) == "While building `['t8']': Don't know how to build a file with suffix '.unknown'." + match = str(e) == "While building `['t8']': Don't know how to build a file with suffix `.unknown'." assert match, e def test_build_scanner(self): diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py index cba61e5e..3d3f563b 100644 --- a/src/engine/SCons/Util.py +++ b/src/engine/SCons/Util.py @@ -1006,3 +1006,32 @@ else: return path display = DisplayEngine() + +class Selector(UserDict.UserDict): + """A callable dictionary that maps file suffixes to dictionary + values.""" + def __call__(self, env, source): + ext = splitext(str(source[0]))[1] + try: + return self[ext] + except KeyError: + # Try to perform Environment substitution on the keys of + # emitter_dict before giving up. + s_dict = {} + for (k,v) in self.items(): + if not k is None: + s_k = env.subst(k) + if s_dict.has_key(s_k): + # We only raise an error when variables point + # to the same suffix. If one suffix is literal + # and a variable suffix contains this literal, + # the literal wins and we don't raise an error. + raise KeyError, (s_dict[s_k][0], k, s_k) + s_dict[s_k] = (k,v) + try: + return s_dict[ext][1] + except KeyError: + try: + return self[None] + except KeyError: + return None diff --git a/src/engine/SCons/UtilTests.py b/src/engine/SCons/UtilTests.py index b7b41be0..23120e61 100644 --- a/src/engine/SCons/UtilTests.py +++ b/src/engine/SCons/UtilTests.py @@ -863,6 +863,48 @@ class UtilTestCase(unittest.TestCase): assert nl[0:2].child.bar == [ 't1child', 't2child' ], \ nl[0:2].child.bar + def test_Selector(self): + """Test the Selector class""" + + s = Selector({'a' : 'AAA', 'b' : 'BBB'}) + assert s['a'] == 'AAA', s['a'] + assert s['b'] == 'BBB', s['b'] + exc_caught = None + try: + x = s['c'] + except KeyError: + exc_caught = 1 + assert exc_caught, "should have caught a KeyError" + s['c'] = 'CCC' + assert s['c'] == 'CCC', s['c'] + + class DummyEnv(UserDict.UserDict): + def subst(self, key): + if key[0] == '$': + return self[key[1:]] + return key + + env = DummyEnv() + + s = Selector({'.d' : 'DDD', '.e' : 'EEE'}) + ret = s(env, ['foo.d']) + assert ret == 'DDD', ret + ret = s(env, ['bar.e']) + assert ret == 'EEE', ret + ret = s(env, ['bar.x']) + assert ret == None, ret + s[None] = 'XXX' + ret = s(env, ['bar.x']) + assert ret == 'XXX', ret + + env = DummyEnv({'FSUFF' : '.f', 'GSUFF' : '.g'}) + + s = Selector({'$FSUFF' : 'FFF', '$GSUFF' : 'GGG'}) + ret = s(env, ['foo.f']) + assert ret == 'FFF', ret + ret = s(env, ['bar.g']) + assert ret == 'GGG', ret + if __name__ == "__main__": suite = unittest.makeSuite(UtilTestCase, 'test_') if not unittest.TextTestRunner().run(suite).wasSuccessful():