Commits

Anonymous committed 783b0cb

Refactor to let specific Node types override scanner selection, and to add a separate in-memory Directory scanner (to be used later).

Comments (0)

Files changed (6)

src/engine/SCons/Executor.py

         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]))

src/engine/SCons/ExecutorTests.py

         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):

src/engine/SCons/Node/NodeTests.py

         """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.
         """

src/engine/SCons/Node/__init__.py

 
         # 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 = {}
     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

src/engine/SCons/Scanner/Dir.py

 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,
    '.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)

src/engine/SCons/Scanner/DirTests.py

 import SCons.Node.FS
 import SCons.Scanner.Dir
 
-test = TestCmd.TestCmd(workdir = '')
+#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)
 
-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
+class DummyEnvironment:
+    def __init__(self, root):
+        self.fs = SCons.Node.FS.FS(root)
+    def Dir(self, name):
+        return self.fs.Dir(name)
     def Entry(self, name):
         return self.fs.Entry(name)
-
-class DummyEnvironment:
-    def __init__(self):
-        self.fs = SCons.Node.FS.FS()
-    def Entry(self, name):
-        node = DummyNode(name, self.fs)
-        return node
     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 == ['f1', 'f2', 'sub'], sss
+        assert sss == ['dir/f1', 'dir/f2', 'dir/sub'], 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 == ['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 == [], sss
+
+        deps = s(env.Dir('dir/sub'), env, ())
+        sss = map(str, deps)
+        assert sss == [], sss
 
 def suite():
     suite = unittest.TestSuite()
     suite.addTest(DirScannerTestCase1())
+    suite.addTest(DirScannerTestCase2())
     return suite
 
 if __name__ == "__main__":