Bug 1147207 - Add a ComposedFinder class that acts like a FileFinder proxy over multiple FileFinders. r=gps
authorMike Hommey <mh+mozilla@glandium.org>
Thu, 26 Mar 2015 12:07:17 +0900
changeset 236663 3357891715c4bf18cd1b7af93f82dccbc7cf9db9
parent 236662 453c7f388d5ab7bc1165cd48ef350b627d3a58b6
child 236664 685aa4dfe753b06a03771485b1cbd2586824cc88
push id57733
push usermh@glandium.org
push dateTue, 31 Mar 2015 03:34:48 +0000
treeherdermozilla-inbound@9e2723115b09 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgps
bugs1147207
milestone40.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1147207 - Add a ComposedFinder class that acts like a FileFinder proxy over multiple FileFinders. r=gps
python/mozbuild/mozpack/files.py
python/mozbuild/mozpack/test/test_files.py
--- a/python/mozbuild/mozpack/files.py
+++ b/python/mozbuild/mozpack/files.py
@@ -880,8 +880,35 @@ class JarFinder(BaseFinder):
             for p in self._files:
                 yield p, DeflatedFile(self._files[p])
         elif pattern in self._files:
             yield pattern, DeflatedFile(self._files[pattern])
         else:
             for p in self._files:
                 if mozpath.basedir(p, [pattern]) == pattern:
                     yield p, DeflatedFile(self._files[p])
+
+
+class ComposedFinder(BaseFinder):
+    '''
+    Composes multiple File Finders in some sort of virtual file system.
+
+    A ComposedFinder is initialized from a dictionary associating paths to
+    *Finder instances.
+
+    Note this could be optimized to be smarter than getting all the files
+    in advance.
+    '''
+    def __init__(self, finders):
+        # Can't import globally, because of the dependency of mozpack.copier
+        # on this module.
+        from mozpack.copier import FileRegistry
+        self.files = FileRegistry()
+
+        for base, finder in sorted(finders.iteritems()):
+            if self.files.contains(base):
+                self.files.remove(base)
+            for p, f in finder.find(''):
+                self.files.add(mozpath.join(base, p), f)
+
+    def find(self, pattern):
+        for p in self.files.match(pattern):
+            yield p, self.files[p]
--- a/python/mozbuild/mozpack/test/test_files.py
+++ b/python/mozbuild/mozpack/test/test_files.py
@@ -5,16 +5,17 @@
 from mozbuild.util import ensureParentDir
 
 from mozpack.errors import (
     ErrorMessage,
     errors,
 )
 from mozpack.files import (
     AbsoluteSymlinkFile,
+    ComposedFinder,
     DeflatedFile,
     Dest,
     ExistingFile,
     FileFinder,
     File,
     GeneratedFile,
     JarFinder,
     ManifestFile,
@@ -847,16 +848,20 @@ class MatchTestTemplate(object):
             'foo/qux/1', 'foo/qux/bar', 'foo/qux/2/test', 'foo/qux/2/test2'
         ])
         self.do_check('foo/q*ux', [
             'foo/qux/1', 'foo/qux/bar', 'foo/qux/2/test', 'foo/qux/2/test2'
         ])
         self.do_check('foo/*/2/test*', ['foo/qux/2/test', 'foo/qux/2/test2'])
         self.do_check('**/bar', ['bar', 'foo/bar', 'foo/qux/bar'])
         self.do_check('foo/**/test', ['foo/qux/2/test'])
+        self.do_check('foo', [
+            'foo/bar', 'foo/baz', 'foo/qux/1', 'foo/qux/bar',
+            'foo/qux/2/test', 'foo/qux/2/test2'
+        ])
         self.do_check('foo/**', [
             'foo/bar', 'foo/baz', 'foo/qux/1', 'foo/qux/bar',
             'foo/qux/2/test', 'foo/qux/2/test2'
         ])
         self.do_check('**/2/test*', ['foo/qux/2/test', 'foo/qux/2/test2'])
         self.do_check('**/foo', [
             'foo/bar', 'foo/baz', 'foo/qux/1', 'foo/qux/bar',
             'foo/qux/2/test', 'foo/qux/2/test2'
@@ -960,10 +965,41 @@ class TestJarFinder(MatchTestTemplate, T
         self.jar = JarWriter(file=self.tmppath('test.jar'))
         self.prepare_match_test()
         self.jar.finish()
         reader = JarReader(file=self.tmppath('test.jar'))
         self.finder = JarFinder(self.tmppath('test.jar'), reader)
         self.do_match_test()
 
 
+class TestComposedFinder(MatchTestTemplate, TestWithTmpDir):
+    def add(self, path, content=None):
+        # Put foo/qux files under $tmp/b.
+        if path.startswith('foo/qux/'):
+            real_path = mozpath.join('b', path[8:])
+        else:
+            real_path = mozpath.join('a', path)
+        ensureParentDir(self.tmppath(real_path))
+        if not content:
+            content = path
+        open(self.tmppath(real_path), 'wb').write(content)
+
+    def do_check(self, pattern, result):
+        if '*' in pattern:
+            return
+        do_check(self, self.finder, pattern, result)
+
+    def test_composed_finder(self):
+        self.prepare_match_test()
+        # Also add files in $tmp/a/foo/qux because ComposedFinder is
+        # expected to mask foo/qux entirely with content from $tmp/b.
+        ensureParentDir(self.tmppath('a/foo/qux/hoge'))
+        open(self.tmppath('a/foo/qux/hoge'), 'wb').write('hoge')
+        open(self.tmppath('a/foo/qux/bar'), 'wb').write('not the right content')
+        self.finder = ComposedFinder({
+            '': FileFinder(self.tmppath('a')),
+            'foo/qux': FileFinder(self.tmppath('b')),
+        })
+        self.do_match_test()
+
+
 if __name__ == '__main__':
     mozunit.main()