Bug 1147207 - Add a ComposedFinder class that acts like a FileFinder proxy over multiple FileFinders. r=gps, a=sledru
authorMike Hommey <mh+mozilla@glandium.org>
Thu, 26 Mar 2015 12:07:17 +0900
changeset 258314 fc1e894eec2f
parent 258313 d59b572e546f
child 258315 46262c24ca5b
push id4643
push userryanvm@gmail.com
push date2015-04-07 14:24 +0000
treeherdermozilla-beta@0c29ab096b90 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgps, sledru
bugs1147207
milestone38.0
Bug 1147207 - Add a ComposedFinder class that acts like a FileFinder proxy over multiple FileFinders. r=gps, a=sledru
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()