From: stevenknight Date: Sun, 4 Dec 2005 17:10:10 +0000 (+0000) Subject: Refactor to let specific Node types override scanner selection, and to add a separate... X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=55949630db54f9f1cc359dc542c1cc0fe3a20fef;p=scons.git Refactor to let specific Node types override scanner selection, and to add a separate in-memory Directory scanner (to be used later). git-svn-id: http://scons.tigris.org/svn/scons/trunk@1401 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- diff --git a/src/engine/SCons/Executor.py b/src/engine/SCons/Executor.py index 4f4e650c..ad671521 100644 --- a/src/engine/SCons/Executor.py +++ b/src/engine/SCons/Executor.py @@ -191,7 +191,7 @@ class Executor: each individual target, which is a hell of a lot more efficient. """ env = self.get_build_env() - select_specific_scanner = lambda t: (t[0], t[1].select(t[0])) + select_specific_scanner = lambda t: (t[0], t[0].select_scanner(t[1])) remove_null_scanners = lambda t: not t[1] is None add_scanner_path = lambda t, s=self: \ (t[0], t[1], s.get_build_scanner_path(t[1])) diff --git a/src/engine/SCons/ExecutorTests.py b/src/engine/SCons/ExecutorTests.py index fd163221..a5ac9a65 100644 --- a/src/engine/SCons/ExecutorTests.py +++ b/src/engine/SCons/ExecutorTests.py @@ -88,6 +88,8 @@ class MyNode: return self.missing_val def calc_signature(self, calc): return 'cs-'+calc+'-'+self.name + def select_scanner(self, scanner): + return scanner.select(self) class MyScanner: def __init__(self, prefix): diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py index 8c2e6ea6..11c57a95 100644 --- a/src/engine/SCons/Node/NodeTests.py +++ b/src/engine/SCons/Node/NodeTests.py @@ -1030,6 +1030,12 @@ class NodeTestCase(unittest.TestCase): """Test that a scanner_key() method exists""" assert SCons.Node.Node().scanner_key() == None + def test_select_scanner(self): + """Test the base select_scanner() method returns its scanner""" + scanner = Scanner() + s = SCons.Node.Node().select_scanner(scanner) + assert scanner is s, s + def test_children(self): """Test fetching the non-ignored "children" of a Node. """ diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py index e73e5f38..a77b09ba 100644 --- a/src/engine/SCons/Node/__init__.py +++ b/src/engine/SCons/Node/__init__.py @@ -442,7 +442,7 @@ class Node: # Give the scanner a chance to select a more specific scanner # for this Node. - scanner = scanner.select(self) + #scanner = scanner.select(self) nodes = [self] seen = {} @@ -556,6 +556,16 @@ class Node: def scanner_key(self): return None + def select_scanner(self, scanner): + """Selects a scanner for this Node. + + This is a separate method so it can be overridden by Node + subclasses (specifically, Node.FS.Dir) that *must* use their + own Scanner and don't select one the Scanner.Selector that's + configured for the target. + """ + return scanner.select(self) + def env_set(self, env, safe=0): if safe and self.env: return diff --git a/src/engine/SCons/Scanner/Dir.py b/src/engine/SCons/Scanner/Dir.py index e722230f..3da1661d 100644 --- a/src/engine/SCons/Scanner/Dir.py +++ b/src/engine/SCons/Scanner/Dir.py @@ -28,17 +28,23 @@ import string import SCons.Node.FS import SCons.Scanner +def only_dirs(nodes): + is_Dir = lambda n: isinstance(n.disambiguate(), SCons.Node.FS.Dir) + return filter(is_Dir, nodes) + def DirScanner(**kw): """Return a prototype Scanner instance for scanning directories for on-disk files""" - def only_dirs(nodes): - return filter(lambda n: isinstance(n.disambiguate(), - SCons.Node.FS.Dir), - nodes) kw['node_factory'] = SCons.Node.FS.Entry kw['recursive'] = only_dirs - ds = apply(SCons.Scanner.Base, (scan, "DirScanner"), kw) - return ds + return apply(SCons.Scanner.Base, (scan_on_disk, "DirScanner"), kw) + +def DirEntryScanner(**kw): + """Return a prototype Scanner instance for "scanning" + directory Nodes for their in-memory entries""" + kw['node_factory'] = SCons.Node.FS.Entry + kw['recursive'] = only_dirs + return apply(SCons.Scanner.Base, (scan_in_memory, "DirEntryScanner"), kw) skip_entry = { '.' : 1, @@ -47,17 +53,31 @@ skip_entry = { '.sconsign.dblite' : 1, } -def scan(node, env, path=()): +do_not_scan = lambda k: not skip_entry.has_key(k) + +def scan_on_disk(node, env, path=()): """ - This scanner scans a directory for on-disk files and directories therein. + Scans a directory for on-disk files and directories therein. + + Looking up the entries will add these to the in-memory Node tree + representation of the file system, so all we have to do is just + that and then call the in-memory scanning function. """ try: flist = node.fs.listdir(node.abspath) except (IOError, OSError): return [] - dont_scan = lambda k: not skip_entry.has_key(k) - flist = filter(dont_scan, flist) - flist.sort() - # Add ./ to the beginning of the file name so that if it begins with a - # '#' we don't look it up relative to the top-level directory. - return map(lambda f, node=node: node.Entry('./'+f), flist) + e = node.Entry + for f in filter(do_not_scan, flist): + # Add ./ to the beginning of the file name so if it begins with a + # '#' we don't look it up relative to the top-level directory. + e('./' + f) + return scan_in_memory(node, env, path) + +def scan_in_memory(node, env, path=()): + """ + "Scans" a Node.FS.Dir for its in-memory entries. + """ + entry_list = filter(do_not_scan, node.entries.keys()) + entry_list.sort() + return map(lambda n, e=node.entries: e[n], entry_list) diff --git a/src/engine/SCons/Scanner/DirTests.py b/src/engine/SCons/Scanner/DirTests.py index 257e76b8..e4e59a39 100644 --- a/src/engine/SCons/Scanner/DirTests.py +++ b/src/engine/SCons/Scanner/DirTests.py @@ -33,55 +33,73 @@ import TestCmd import SCons.Node.FS import SCons.Scanner.Dir -test = TestCmd.TestCmd(workdir = '') - -test.subdir('dir', ['dir', 'sub']) - -test.write(['dir', 'f1'], "dir/f1\n") -test.write(['dir', 'f2'], "dir/f2\n") -test.write(['dir', '.sconsign'], "dir/.sconsign\n") -test.write(['dir', '.sconsign.dblite'], "dir/.sconsign.dblite\n") -test.write(['dir', 'sub', 'f3'], "dir/sub/f3\n") -test.write(['dir', 'sub', 'f4'], "dir/sub/f4\n") -test.write(['dir', 'sub', '.sconsign'], "dir/.sconsign\n") -test.write(['dir', 'sub', '.sconsign.dblite'], "dir/.sconsign.dblite\n") - -class DummyNode: - def __init__(self, name, fs): - self.name = name - self.abspath = test.workpath(name) - self.fs = fs - def __str__(self): - return self.name - def Entry(self, name): - return self.fs.Entry(name) +#class DummyNode: +# def __init__(self, name, fs): +# self.name = name +# self.abspath = test.workpath(name) +# self.fs = fs +# def __str__(self): +# return self.name +# def Entry(self, name): +# return self.fs.Entry(name) class DummyEnvironment: - def __init__(self): - self.fs = SCons.Node.FS.FS() + def __init__(self, root): + self.fs = SCons.Node.FS.FS(root) + def Dir(self, name): + return self.fs.Dir(name) def Entry(self, name): - node = DummyNode(name, self.fs) - return node + return self.fs.Entry(name) def get_factory(self, factory): return factory or self.fs.Entry -class DirScannerTestCase1(unittest.TestCase): +class DirScannerTestBase(unittest.TestCase): + def setUp(self): + self.test = TestCmd.TestCmd(workdir = '') + + self.test.subdir('dir', ['dir', 'sub']) + + self.test.write(['dir', 'f1'], "dir/f1\n") + self.test.write(['dir', 'f2'], "dir/f2\n") + self.test.write(['dir', '.sconsign'], "dir/.sconsign\n") + self.test.write(['dir', '.sconsign.dblite'], "dir/.sconsign.dblite\n") + self.test.write(['dir', 'sub', 'f3'], "dir/sub/f3\n") + self.test.write(['dir', 'sub', 'f4'], "dir/sub/f4\n") + self.test.write(['dir', 'sub', '.sconsign'], "dir/.sconsign\n") + self.test.write(['dir', 'sub', '.sconsign.dblite'], "dir/.sconsign.dblite\n") + +class DirScannerTestCase1(DirScannerTestBase): def runTest(self): - env = DummyEnvironment() + env = DummyEnvironment(self.test.workpath()) s = SCons.Scanner.Dir.DirScanner() - deps = s(env.Entry('dir'), env, ()) + deps = s(env.Dir('dir'), env, ()) + sss = map(str, deps) + assert sss == ['dir/f1', 'dir/f2', 'dir/sub'], sss + + deps = s(env.Dir('dir/sub'), env, ()) + sss = map(str, deps) + assert sss == ['dir/sub/f3', 'dir/sub/f4'], sss + +class DirScannerTestCase2(DirScannerTestBase): + def runTest(self): + env = DummyEnvironment(self.test.workpath()) + + s = SCons.Scanner.Dir.DirEntryScanner() + + deps = s(env.Dir('dir'), env, ()) sss = map(str, deps) - assert sss == ['f1', 'f2', 'sub'], sss + assert sss == [], sss - deps = s(env.Entry('dir/sub'), env, ()) + deps = s(env.Dir('dir/sub'), env, ()) sss = map(str, deps) - assert sss == ['f3', 'f4'], sss + assert sss == [], sss def suite(): suite = unittest.TestSuite() suite.addTest(DirScannerTestCase1()) + suite.addTest(DirScannerTestCase2()) return suite if __name__ == "__main__":