Bug 1138579 - Support multiple Files patterns in moz.build r=gps
☠☠ backed out by d517652362dc ☠ ☠
authorTed Campbell <tcampbell@mozilla.com>
Tue, 18 Sep 2018 17:18:30 +0000
changeset 436988 08f0bf17514dd763a1c99b5f02cd88628b5f7ebc
parent 436987 ecf3df8fabc71796f1b14ec86da1a038dce77aff
child 436989 3a93dd337a0ebdd7b0e7e5bbe16c80529e99ae68
push id34667
push useraiakab@mozilla.com
push dateWed, 19 Sep 2018 02:13:23 +0000
treeherdermozilla-central@3857cbe7b717 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgps
bugs1138579
milestone64.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 1138579 - Support multiple Files patterns in moz.build r=gps Add support for |with Files('a/**', 'b/**')| in mozbuild config files. MozReview-Commit-ID: IoM4qfEhXXc Differential Revision: https://phabricator.services.mozilla.com/D5315
python/mozbuild/mozbuild/frontend/context.py
python/mozbuild/mozbuild/frontend/reader.py
python/mozbuild/mozbuild/test/frontend/test_context.py
--- a/python/mozbuild/mozbuild/frontend/context.py
+++ b/python/mozbuild/mozbuild/frontend/context.py
@@ -1064,19 +1064,19 @@ class Files(SubContext):
 
             Exclusive components are named by setting `SCHEDULES.exclusive`:
 
             with Files('mobile/android/**'):
                 SCHEDULES.exclusive = ['android']
             """),
     }
 
-    def __init__(self, parent, pattern=None):
+    def __init__(self, parent, *patterns):
         super(Files, self).__init__(parent)
-        self.pattern = pattern
+        self.patterns = patterns
         self.finalized = set()
         self.test_files = set()
         self.test_tags = set()
         self.test_flavors = set()
 
     def __iadd__(self, other):
         assert isinstance(other, Files)
 
--- a/python/mozbuild/mozbuild/frontend/reader.py
+++ b/python/mozbuild/mozbuild/frontend/reader.py
@@ -1337,16 +1337,25 @@ class BuildReader(object):
 
             if key not in defaults_cache:
                 defaults_cache[key] = self.test_defaults_for_path(ctxs)
 
             return defaults_cache[key]
 
         r = {}
 
+        # Only do wildcard matching if the '*' character is present.
+        # Otherwise, mozpath.match will match directories, which we've
+        # arbitrarily chosen to not allow.
+        def path_matches_pattern(relpath, pattern):
+            if pattern == relpath:
+                return True
+
+            return '*' in pattern and mozpath.match(relpath, pattern)
+
         for path, ctxs in paths.items():
             # Should be normalized by read_relevant_mozbuilds.
             assert '\\' not in path
 
             flags = Files(Context())
 
             for ctx in ctxs:
                 if not isinstance(ctx, Files):
@@ -1359,23 +1368,17 @@ class BuildReader(object):
                 # we implement an optimized version.
                 ctx_rel_dir = ctx.relsrcdir
                 if ctx_rel_dir:
                     assert path.startswith(ctx_rel_dir)
                     relpath = path[len(ctx_rel_dir) + 1:]
                 else:
                     relpath = path
 
-                pattern = ctx.pattern
-
-                # Only do wildcard matching if the '*' character is present.
-                # Otherwise, mozpath.match will match directories, which we've
-                # arbitrarily chosen to not allow.
-                if pattern == relpath or \
-                        ('*' in pattern and mozpath.match(relpath, pattern)):
+                if any(path_matches_pattern(relpath, p) for p in ctx.patterns):
                     flags += ctx
 
             if not any([flags.test_tags, flags.test_files, flags.test_flavors]):
                 flags += test_defaults_for_path(ctxs)
 
             r[path] = flags
 
         return r
--- a/python/mozbuild/mozbuild/test/frontend/test_context.py
+++ b/python/mozbuild/mozbuild/test/frontend/test_context.py
@@ -658,64 +658,80 @@ class TestTypedRecord(unittest.TestCase)
         with self.assertRaises(TypeError):
             inst.field2 = object()
 
 
 class TestFiles(unittest.TestCase):
     def test_aggregate_empty(self):
         c = Context({})
 
-        files = {'moz.build': Files(c, pattern='**')}
+        files = {'moz.build': Files(c, '**')}
 
         self.assertEqual(Files.aggregate(files), {
             'bug_component_counts': [],
             'recommended_bug_component': None,
         })
 
     def test_single_bug_component(self):
         c = Context({})
-        f = Files(c, pattern='**')
+        f = Files(c, '**')
         f['BUG_COMPONENT'] = (u'Product1', u'Component1')
 
         files = {'moz.build': f}
         self.assertEqual(Files.aggregate(files), {
             'bug_component_counts': [((u'Product1', u'Component1'), 1)],
             'recommended_bug_component': (u'Product1', u'Component1'),
         })
 
     def test_multiple_bug_components(self):
         c = Context({})
-        f1 = Files(c, pattern='**')
+        f1 = Files(c, '**')
         f1['BUG_COMPONENT'] = (u'Product1', u'Component1')
 
-        f2 = Files(c, pattern='**')
+        f2 = Files(c, '**')
         f2['BUG_COMPONENT'] = (u'Product2', u'Component2')
 
         files = {'a': f1, 'b': f2, 'c': f1}
         self.assertEqual(Files.aggregate(files), {
             'bug_component_counts': [
                 ((u'Product1', u'Component1'), 2),
                 ((u'Product2', u'Component2'), 1),
             ],
             'recommended_bug_component': (u'Product1', u'Component1'),
         })
 
     def test_no_recommended_bug_component(self):
         """If there is no clear count winner, we don't recommend a bug component."""
         c = Context({})
-        f1 = Files(c, pattern='**')
+        f1 = Files(c, '**')
         f1['BUG_COMPONENT'] = (u'Product1', u'Component1')
 
-        f2 = Files(c, pattern='**')
+        f2 = Files(c, '**')
         f2['BUG_COMPONENT'] = (u'Product2', u'Component2')
 
         files = {'a': f1, 'b': f2}
         self.assertEqual(Files.aggregate(files), {
             'bug_component_counts': [
                 ((u'Product1', u'Component1'), 1),
                 ((u'Product2', u'Component2'), 1),
             ],
             'recommended_bug_component': None,
         })
 
+    def test_multiple_patterns(self):
+        c = Context({})
+        f1 = Files(c, 'a/**')
+        f1['BUG_COMPONENT'] = (u'Product1', u'Component1')
+        f2 = Files(c, 'b/**', 'a/bar')
+        f2['BUG_COMPONENT'] = (u'Product2', u'Component2')
+
+        files = {'a/foo': f1, 'a/bar' : f2, 'b/foo' : f2 }
+        self.assertEqual(Files.aggregate(files), {
+            'bug_component_counts': [
+                ((u'Product2', u'Component2'), 2),
+                ((u'Product1', u'Component1'), 1),
+            ],
+            'recommended_bug_component': (u'Product2', u'Component2'),
+        })
+
 
 if __name__ == '__main__':
     main()