Bug 1275419 - Add support for the --option=+a,-b kind of options in python configure. r?chmanchester draft
authorMike Hommey <mh+mozilla@glandium.org>
Wed, 25 May 2016 15:55:03 +0900
changeset 370668 5f7f21ff104e2d8b1adf2fe389b1aff4ea4e6417
parent 370667 8ea3030332a90003b4a2dff0daa8329cf2109792
child 370669 1364500a9fa8246b7d1b7b89fd795ef3d66b801b
push id19130
push userbmo:mh+mozilla@glandium.org
push dateWed, 25 May 2016 07:42:09 +0000
reviewerschmanchester
bugs1275419
milestone49.0a1
Bug 1275419 - Add support for the --option=+a,-b kind of options in python configure. r?chmanchester
python/mozbuild/mozbuild/configure/options.py
python/mozbuild/mozbuild/test/configure/test_options.py
--- a/python/mozbuild/mozbuild/configure/options.py
+++ b/python/mozbuild/mozbuild/configure/options.py
@@ -338,22 +338,41 @@ class Option(object):
                     '*': '0 or more',
                     '+': '1 or more',
                 }.get(self.nargs, str(self.nargs)),
                 's' if (not isinstance(self.nargs, int) or
                         self.nargs != 1) else ''
             ))
 
         if len(values) and self.choices:
+            relative_result = None
             for val in values:
+                if self.nargs in ('+', '*'):
+                    if val.startswith(('+', '-')):
+                        if relative_result is None:
+                            relative_result = list(self.default)
+                        sign = val[0]
+                        val = val[1:]
+                        if sign == '+':
+                            if val not in relative_result:
+                                relative_result.append(val)
+                        else:
+                            try:
+                                relative_result.remove(val)
+                            except ValueError:
+                                pass
+
                 if val not in self.choices:
                     raise InvalidOptionError(
                         "'%s' is not one of %s"
                         % (val, ', '.join("'%s'" % c for c in self.choices)))
 
+            if relative_result is not None:
+                values = PositiveOptionValue(relative_result, origin=origin)
+
         return values
 
 
 class CommandLineHelper(object):
     '''Helper class to handle the various ways options can be given either
     on the command line of through the environment.
 
     For instance, an Option('--foo', env='FOO') can be passed as --foo on the
--- a/python/mozbuild/mozbuild/test/configure/test_options.py
+++ b/python/mozbuild/mozbuild/test/configure/test_options.py
@@ -233,16 +233,54 @@ class TestOption(unittest.TestCase):
         value = option.get_value('--with-option=b,a')
         self.assertTrue(value)
         self.assertEquals(PositiveOptionValue(('b', 'a')), value)
 
         # Test nargs inference from choices
         option = Option('--with-option', choices=('a', 'b'))
         self.assertEqual(option.nargs, 1)
 
+        # Test "relative" values
+        option = Option('--with-option', nargs='*', default=('b', 'c'),
+                        choices=('a', 'b', 'c', 'd'))
+
+        value = option.get_value('--with-option=+d')
+        self.assertEquals(PositiveOptionValue(('b', 'c', 'd')), value)
+
+        value = option.get_value('--with-option=-b')
+        self.assertEquals(PositiveOptionValue(('c',)), value)
+
+        value = option.get_value('--with-option=-b,+d')
+        self.assertEquals(PositiveOptionValue(('c','d')), value)
+
+        # Adding something that is int the default is fine
+        value = option.get_value('--with-option=+b')
+        self.assertEquals(PositiveOptionValue(('b', 'c')), value)
+
+        # Removing something that is not in the default is fine, as long as it
+        # is one of the choices
+        value = option.get_value('--with-option=-a')
+        self.assertEquals(PositiveOptionValue(('b', 'c')), value)
+
+        with self.assertRaises(InvalidOptionError) as e:
+            option.get_value('--with-option=-e')
+        self.assertEquals(e.exception.message,
+                          "'e' is not one of 'a', 'b', 'c', 'd'")
+
+        # Other "not a choice" errors.
+        with self.assertRaises(InvalidOptionError) as e:
+            option.get_value('--with-option=+e')
+        self.assertEquals(e.exception.message,
+                          "'e' is not one of 'a', 'b', 'c', 'd'")
+
+        with self.assertRaises(InvalidOptionError) as e:
+            option.get_value('--with-option=e')
+        self.assertEquals(e.exception.message,
+                          "'e' is not one of 'a', 'b', 'c', 'd'")
+
     def test_option_value_format(self):
         val = PositiveOptionValue()
         self.assertEquals('--with-value', val.format('--with-value'))
         self.assertEquals('--with-value', val.format('--without-value'))
         self.assertEquals('--enable-value', val.format('--enable-value'))
         self.assertEquals('--enable-value', val.format('--disable-value'))
         self.assertEquals('--value', val.format('--value'))
         self.assertEquals('VALUE=1', val.format('VALUE'))