From: stevenknight Date: Sat, 5 Mar 2005 02:08:10 +0000 (+0000) Subject: Eliminate find_file() inefficiency. X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=2a507a8e57eca1d95e75102d67c53164cabbc433;p=scons.git Eliminate find_file() inefficiency. git-svn-id: http://scons.tigris.org/svn/scons/trunk@1242 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index 52f19f55..df974de3 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -1410,24 +1410,59 @@ class Dir(Base): sccspath = 'SCCS' + os.sep + 's.'+name return self.entry_exists_on_disk(sccspath) - def srcdir_duplicate(self, name, clazz): - dname = '.' + def srcdir_list(self): + """__cacheable__""" + result = [] + + dirname = '.' dir = self while dir: if dir.srcdir: - srcdir = dir.srcdir.Dir(dname) - if srcdir.entry_exists_on_disk(name): - srcnode = self.fs._doLookup(clazz, name, srcdir) - if self.duplicate: - node = self.fs._doLookup(clazz, name, self) - node.do_duplicate(srcnode) - return node - else: - return srcnode - dname = dir.name + os.sep + dname + d = dir.srcdir.Dir(dirname) + if d.is_under(dir): + # Shouldn't source from something in the build path: + # build_dir is probably under src_dir, in which case + # we are reflecting. + break + result.append(d) + dirname = dir.name + os.sep + dirname dir = dir.get_dir() + + return result + + def srcdir_duplicate(self, name, clazz): + for dir in self.srcdir_list(): + if dir.entry_exists_on_disk(name): + srcnode = self.fs._doLookup(clazz, name, dir) + if self.duplicate: + node = self.fs._doLookup(clazz, name, self) + node.do_duplicate(srcnode) + return node + else: + return srcnode return None + def srcdir_find_file(self, filename): + """__cacheable__""" + fs = self.fs + do_Rsearch = fs.do_Rsearch + + def func(node): + if isinstance(node, SCons.Node.FS.File) and \ + (node.is_derived() or node.is_pseudo_derived() or node.exists()): + return node + return None + + node, d = do_Rsearch(filename, self, func, File) + if node: + return node, d + + for dir in self.srcdir_list(): + node, d = do_Rsearch(filename, dir, func, File) + if node: + return File(filename, self, fs), d + return None, None + def node_on_disk(self, name, clazz): if self.entry_exists_on_disk(name) or \ self.sccs_on_disk(name) or \ @@ -1888,36 +1923,12 @@ def find_file(filename, paths, verbose=None): return None paths = filter(None, map(filedir_lookup, paths)) - def func(node): - if isinstance(node, SCons.Node.FS.File) and \ - (node.is_derived() or node.is_pseudo_derived() or node.exists()): - return node - return None - for dir in paths: verbose("looking for '%s' in '%s' ...\n" % (filename, dir)) - - node, d = default_fs.do_Rsearch(filename, dir, func, File) + node, d = dir.srcdir_find_file(filename) if node: verbose("... FOUND '%s' in '%s'\n" % (filename, d)) return node - - dirname = '.' - while dir: - if dir.srcdir: - d = dir.srcdir.Dir(dirname) - if d.is_under(dir): - # Shouldn't source from something in the build path: - # build_dir is probably under src_dir, in which case - # we are reflecting. - break - node, d = dir.fs.do_Rsearch(filename, d, func, File) - if node: - verbose("... FOUND '%s' in '%s'\n" % (filename, d)) - return File(filename, dir.Dir(dirname), dir.fs) - dirname = dir.name + os.sep + dirname - dir = dir.get_dir() - return None def find_files(filenames, paths): diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py index c3f87bc9..5034d167 100644 --- a/src/engine/SCons/Node/FSTests.py +++ b/src/engine/SCons/Node/FSTests.py @@ -104,6 +104,17 @@ class Builder: def source_factory(self, name): return self.factory(name) +class _tempdirTestCase(unittest.TestCase): + def setUp(self): + self.save_cwd = os.getcwd() + self.test = TestCmd(workdir='') + # FS doesn't like the cwd to be something other than its root. + os.chdir(self.test.workpath("")) + self.fs = SCons.Node.FS.FS() + + def tearDown(self): + os.chdir(self.save_cwd) + class BuildDirTestCase(unittest.TestCase): def runTest(self): """Test build dir functionality""" @@ -1173,6 +1184,224 @@ class FSTestCase(unittest.TestCase): t = z.target_from_source('pre-', '-suf', lambda x: x[:-1]) assert str(t) == 'pre-z-suf', str(t) +class DirTestCase(_tempdirTestCase): + + def test_entry_exists_on_disk(self): + """Test the Dir.entry_exists_on_disk() method + """ + test = self.test + + does_not_exist = self.fs.Dir('does_not_exist') + assert not does_not_exist.entry_exists_on_disk('foo') + + test.subdir('d') + test.write(['d', 'exists'], "d/exists\n") + + d = self.fs.Dir('d') + assert d.entry_exists_on_disk('exists') + assert not d.entry_exists_on_disk('does_not_exist') + + def test_srcdir_list(self): + """Test the Dir.srcdir_list() method + """ + src = self.fs.Dir('src') + bld = self.fs.Dir('bld') + sub1 = bld.Dir('sub') + sub2 = sub1.Dir('sub') + sub3 = sub2.Dir('sub') + self.fs.BuildDir(bld, src, duplicate=0) + self.fs.BuildDir(sub2, src, duplicate=0) + + s = map(str, src.srcdir_list()) + assert s == [], s + + s = map(str, bld.srcdir_list()) + assert s == ['src'], s + + s = map(str, sub1.srcdir_list()) + assert s == ['src/sub'], s + + s = map(str, sub2.srcdir_list()) + assert s == ['src', 'src/sub/sub'], s + + s = map(str, sub3.srcdir_list()) + assert s == ['src/sub', 'src/sub/sub/sub'], s + + self.fs.BuildDir('src/b1/b2', 'src') + b1 = src.Dir('b1') + b1_b2 = b1.Dir('b2') + b1_b2_b1 = b1_b2.Dir('b1') + b1_b2_b1_b2 = b1_b2_b1.Dir('b2') + b1_b2_b1_b2_sub = b1_b2_b1_b2.Dir('sub') + + s = map(str, b1.srcdir_list()) + assert s == [], s + + s = map(str, b1_b2.srcdir_list()) + assert s == ['src'], s + + s = map(str, b1_b2_b1.srcdir_list()) + assert s == ['src/b1'], s + + s = map(str, b1_b2_b1_b2.srcdir_list()) + assert s == [], s + + s = map(str, b1_b2_b1_b2_sub.srcdir_list()) + assert s == [], s + + def test_srcdir_duplicate(self): + """Test the Dir.srcdir_duplicate() method + """ + test = self.test + + test.subdir('src0') + test.write(['src0', 'exists'], "src0/exists\n") + + bld0 = self.fs.Dir('bld0') + src0 = self.fs.Dir('src0') + self.fs.BuildDir(bld0, src0, duplicate=0) + + n = bld0.srcdir_duplicate('does_not_exist', SCons.Node.FS.File) + assert n is None, n + assert not os.path.exists(test.workpath('bld0', 'does_not_exist')) + + n = bld0.srcdir_duplicate('exists', SCons.Node.FS.File) + assert str(n) == 'src0/exists', str(n) + assert not os.path.exists(test.workpath('bld0', 'exists')) + + test.subdir('src1') + test.write(['src1', 'exists'], "src0/exists\n") + + bld1 = self.fs.Dir('bld1') + src1 = self.fs.Dir('src1') + self.fs.BuildDir(bld1, src1, duplicate=1) + + n = bld1.srcdir_duplicate('does_not_exist', SCons.Node.FS.File) + assert n is None, n + assert not os.path.exists(test.workpath('bld1', 'does_not_exist')) + + n = bld1.srcdir_duplicate('exists', SCons.Node.FS.File) + assert str(n) == 'bld1/exists', str(n) + assert os.path.exists(test.workpath('bld1', 'exists')) + + def test_srcdir_find_file(self): + """Test the Dir.srcdir_find_file() method + """ + test = self.test + + return_true = lambda: 1 + + test.subdir('src0') + test.write(['src0', 'on-disk-f1'], "src0/on-disk-f1\n") + test.write(['src0', 'on-disk-f2'], "src0/on-disk-f2\n") + + bld0 = self.fs.Dir('bld0') + src0 = self.fs.Dir('src0') + self.fs.BuildDir(bld0, src0, duplicate=0) + + derived = src0.File('derived-f') + derived.is_derived = return_true + pseudo = src0.File('pseudo-f') + pseudo.is_pseudo_derived = return_true + exists = src0.File('exists-f') + exists.exists = return_true + + # First check from the source directory. + n = src0.srcdir_find_file('does_not_exist') + assert n == (None, None), n + + n = src0.srcdir_find_file('derived-f') + n = map(str, n) + assert n == ['src0/derived-f', 'src0'], n + + n = src0.srcdir_find_file('pseudo-f') + n = map(str, n) + assert n == ['src0/pseudo-f', 'src0'], n + + n = src0.srcdir_find_file('exists-f') + n = map(str, n) + assert n == ['src0/exists-f', 'src0'], n + + n = src0.srcdir_find_file('on-disk-f1') + n = map(str, n) + assert n == ['src0/on-disk-f1', 'src0'], n + + # Now check from the build directory. + n = bld0.srcdir_find_file('does_not_exist') + assert n == (None, None), n + + n = bld0.srcdir_find_file('derived-f') + n = map(str, n) + assert n == ['src0/derived-f', 'bld0'], n + + n = bld0.srcdir_find_file('pseudo-f') + n = map(str, n) + assert n == ['src0/pseudo-f', 'bld0'], n + + n = bld0.srcdir_find_file('exists-f') + n = map(str, n) + assert n == ['src0/exists-f', 'bld0'], n + + n = bld0.srcdir_find_file('on-disk-f2') + n = map(str, n) + assert n == ['src0/on-disk-f2', 'bld0'], n + + + test.subdir('src1') + test.write(['src1', 'on-disk-f1'], "src1/on-disk-f1\n") + test.write(['src1', 'on-disk-f2'], "src1/on-disk-f2\n") + + bld1 = self.fs.Dir('bld1') + src1 = self.fs.Dir('src1') + self.fs.BuildDir(bld1, src1, duplicate=1) + + derived = src1.File('derived-f') + derived.is_derived = return_true + pseudo = src1.File('pseudo-f') + pseudo.is_pseudo_derived = return_true + exists = src1.File('exists-f') + exists.exists = return_true + + # First check from the source directory. + n = src1.srcdir_find_file('does_not_exist') + assert n == (None, None), n + + n = src1.srcdir_find_file('derived-f') + n = map(str, n) + assert n == ['src1/derived-f', 'src1'], n + + n = src1.srcdir_find_file('pseudo-f') + n = map(str, n) + assert n == ['src1/pseudo-f', 'src1'], n + + n = src1.srcdir_find_file('exists-f') + n = map(str, n) + assert n == ['src1/exists-f', 'src1'], n + + n = src1.srcdir_find_file('on-disk-f1') + n = map(str, n) + assert n == ['src1/on-disk-f1', 'src1'], n + + # Now check from the build directory. + n = bld1.srcdir_find_file('does_not_exist') + assert n == (None, None), n + + n = bld1.srcdir_find_file('derived-f') + n = map(str, n) + assert n == ['bld1/derived-f', 'src1'], n + + n = bld1.srcdir_find_file('pseudo-f') + n = map(str, n) + assert n == ['bld1/pseudo-f', 'src1'], n + + n = bld1.srcdir_find_file('exists-f') + n = map(str, n) + assert n == ['bld1/exists-f', 'src1'], n + + n = bld1.srcdir_find_file('on-disk-f2') + n = map(str, n) + assert n == ['bld1/on-disk-f2', 'bld1'], n + class EntryTestCase(unittest.TestCase): def runTest(self): """Test methods specific to the Entry sub-class. @@ -2156,5 +2385,11 @@ if __name__ == "__main__": suite.addTest(postprocessTestCase()) suite.addTest(SpecialAttrTestCase()) suite.addTest(SaveStringsTestCase()) + tclasses = [ + DirTestCase, + ] + for tclass in tclasses: + names = unittest.getTestCaseNames(tclass, 'test_') + suite.addTests(map(tclass, names)) if not unittest.TextTestRunner().run(suite).wasSuccessful(): sys.exit(1)