Bug 1403519: reset SCHEDULES.exclusive if set multiple times; r=gps
authorDustin J. Mitchell <dustin@mozilla.com>
Tue, 16 Jan 2018 22:33:08 +0000
changeset 399751 ce4e64aa7ea0452877bfbd597a5db413e476c1c2
parent 399750 0f0395687d36597098e4248457ed69f092c39f8f
child 399752 142e0c92435a281bc5389e16694dfff8d815ea6c
push id99021
push userdluca@mozilla.com
push dateThu, 18 Jan 2018 09:49:46 +0000
treeherdermozilla-inbound@7bc2219779f7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgps
bugs1403519
milestone59.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 1403519: reset SCHEDULES.exclusive if set multiple times; r=gps MozReview-Commit-ID: Kycd9i5f19P
python/mozbuild/mozbuild/frontend/context.py
python/mozbuild/mozbuild/test/frontend/data/schedules/moz.build
python/mozbuild/mozbuild/test/frontend/test_reader.py
taskcluster/docs/optimization-schedules.rst
--- a/python/mozbuild/mozbuild/frontend/context.py
+++ b/python/mozbuild/mozbuild/frontend/context.py
@@ -843,20 +843,19 @@ class Schedules(object):
         rv._inclusive = self._inclusive + other._inclusive
         if other._exclusive == self._exclusive:
             rv._exclusive = self._exclusive
         elif self._exclusive == schedules.EXCLUSIVE_COMPONENTS:
             rv._exclusive = other._exclusive
         elif other._exclusive == schedules.EXCLUSIVE_COMPONENTS:
             rv._exclusive = self._exclusive
         else:
-            msg = 'Two Files sections have set SCHEDULES.exclusive to different' \
-                'values; these cannot be combined: {} and {}'
-            msg = msg.format(self._exclusive, other._exclusive)
-            raise ValueError(msg)
+            # in a case where two SCHEDULES.exclusive set different values, take
+            # the later one; this acts the way we expect assignment to work.
+            rv._exclusive = other._exclusive
         return rv
 
 
 @memoize
 def ContextDerivedTypedHierarchicalStringList(type):
     """Specialized HierarchicalStringList for use with ContextDerivedValue
     types."""
     class _TypedListWithItems(ContextDerivedValue, HierarchicalStringList):
--- a/python/mozbuild/mozbuild/test/frontend/data/schedules/moz.build
+++ b/python/mozbuild/mozbuild/test/frontend/data/schedules/moz.build
@@ -2,17 +2,17 @@
 # http://creativecommons.org/publicdomain/zero/1.0/
 
 with Files('*.win'):
     SCHEDULES.exclusive = ['windows']
 
 with Files('*.osx'):
     SCHEDULES.exclusive = ['macosx']
 
-with Files('bad.osx'):
+with Files('win.and.osx'):
     # this conflicts with the previous clause and will cause an error
     # when read
     SCHEDULES.exclusive = ['macosx', 'windows']
 
 with Files('subd/**.py'):
     SCHEDULES.inclusive += ['py-lint']
 
 with Files('**/*.js'):
--- a/python/mozbuild/mozbuild/test/frontend/test_reader.py
+++ b/python/mozbuild/mozbuild/test/frontend/test_reader.py
@@ -479,16 +479,17 @@ class TestBuildReader(unittest.TestCase)
         reader = self.reader('invalid-files-flavor')
 
         with self.assertRaises(BuildReaderError):
             reader.files_info(['foo.js'])
 
     def test_schedules(self):
         reader = self.reader('schedules')
         info = reader.files_info([
+            'win.and.osx',
             'somefile',
             'foo.win',
             'foo.osx',
             'subd/aa.py',
             'subd/yaml.py',
             'subd/win.js',
         ])
         # default: all exclusive, no inclusive
@@ -508,18 +509,15 @@ class TestBuildReader(unittest.TestCase)
         self.assertEqual(info['subd/yaml.py']['SCHEDULES'].exclusive, schedules.EXCLUSIVE_COMPONENTS)
         # .. but exlusive does not override inclusive
         self.assertEqual(info['subd/win.js']['SCHEDULES'].inclusive, ['js-lint'])
         self.assertEqual(info['subd/win.js']['SCHEDULES'].exclusive, ['windows'])
 
         self.assertEqual(set(info['subd/yaml.py']['SCHEDULES'].components),
                          set(schedules.EXCLUSIVE_COMPONENTS + ['py-lint', 'yaml-lint']))
 
-    def test_schedules_conflicting_excludes(self):
-        reader = self.reader('schedules')
-
-        # bad.osx is defined explicitly, and matches *.osx, and the two have
-        # conflicting SCHEDULES.exclusive settings
-        with self.assertRaisesRegexp(ValueError, r"Two Files sections"):
-            reader.files_info(['bad.osx'])
+        # win.and.osx is defined explicitly, and matches *.osx, and the two have
+        # conflicting SCHEDULES.exclusive settings, so the later one is used
+        self.assertEqual(set(info['win.and.osx']['SCHEDULES'].exclusive),
+                         set(['macosx', 'windows']))
 
 if __name__ == '__main__':
     main()
--- a/taskcluster/docs/optimization-schedules.rst
+++ b/taskcluster/docs/optimization-schedules.rst
@@ -73,16 +73,24 @@ for inclusive components and ::
 
 for exclusive components.
 Note the use of ``+=`` for inclusive compoenents (as this is adding to the existing set of affected components) but ``=`` for exclusive components (as this is resetting the affected set to something smaller).
 For cases where an inclusive component is affected exclusively (such as the python-lint configuration in the example above), that component can be assigned to ``SCHEDULES.exclusive``::
 
     with Files('**/pep8rc'):
         SCHEDULES.exclusive = ['py-lint']
 
+If multiple stanzas set ``SCHEDULES.exclusive``, the last one will take precedence.  Thus the following will set ``SCHEDULES.exclusive`` to ``hpux`` for all files except those under ``docs/``.
+
+    with Files('**'):
+        SCHEDULES.exclusive = ['hpux']
+
+    with Files('**/docs'):
+        SCHEDULES.exclusive = ['docs']
+
 Task Annotation
 :::::::::::::::
 
 Tasks are annotated with the components they belong to using the ``"skip-unless-schedules"`` optimization, which takes a list of components for this task::
 
     task['optimization'] = {'skip-unless-schedules': ['windows', 'gtest']}
 
 For tests, this value is set automatically by the test transform based on the suite name and the platform family, doing the correct thing for inclusive test suites.