Backed out changeset 015fd18edd63 (bug 1582155) for python failures on test_configure.py.
authorCosmin Sabou <csabou@mozilla.com>
Mon, 21 Oct 2019 19:05:02 +0300
changeset 498404 118aa8a35c792f37e0e2472119112f047b68fce6
parent 498403 fe98d2b3f313f64ebb716baf98a50dc12439fb2b
child 498405 63a558f063ab80a06cb140606bb50e33d54ec8cf
push id98439
push usercsabou@mozilla.com
push dateMon, 21 Oct 2019 16:09:20 +0000
treeherderautoland@63a558f063ab [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1582155
milestone71.0a1
backs out015fd18edd63b060330657d665e8661f608b92c7
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
Backed out changeset 015fd18edd63 (bug 1582155) for python failures on test_configure.py.
python/mozbuild/mozbuild/configure/__init__.py
python/mozbuild/mozbuild/configure/help.py
python/mozbuild/mozbuild/configure/options.py
python/mozbuild/mozbuild/test/configure/data/included.configure
python/mozbuild/mozbuild/test/configure/data/moz.configure
python/mozbuild/mozbuild/test/configure/test_configure.py
--- a/python/mozbuild/mozbuild/configure/__init__.py
+++ b/python/mozbuild/mozbuild/configure/__init__.py
@@ -14,17 +14,16 @@ from six.moves import builtins as __buil
 import sys
 import types
 from collections import OrderedDict
 from contextlib import contextmanager
 from functools import wraps
 from mozbuild.configure.options import (
     CommandLineHelper,
     ConflictingOptionError,
-    HELP_OPTIONS_CATEGORY,
     InvalidOptionError,
     Option,
     OptionValue,
 )
 from mozbuild.configure.help import HelpFormatter
 from mozbuild.configure.util import (
     ConfigureOutputHandler,
     getpreferredencoding,
@@ -339,19 +338,16 @@ class ConfigureSandbox(dict):
         # A list of conditions to apply as a default `when` for every *_impl()
         self._default_conditions = []
 
         self._helper = CommandLineHelper(environ, argv)
 
         assert isinstance(config, dict)
         self._config = config
 
-        # Tracks how many templates "deep" we are in the stack.
-        self._template_depth = 0
-
         logging.addLevelName(TRACE, 'TRACE')
         if logger is None:
             logger = moz_logger = logging.getLogger('moz.configure')
             logger.setLevel(logging.DEBUG)
             formatter = logging.Formatter('%(levelname)s: %(message)s')
             handler = ConfigureOutputHandler(stdout, stderr)
             handler.setFormatter(formatter)
             queue_debug = handler.queue_debug
@@ -387,18 +383,18 @@ class ConfigureSandbox(dict):
         log_namespace = {
             k: wrapped_log_method(logger, k)
             for k in ('debug', 'info', 'warning', 'error')
         }
         log_namespace['queue_debug'] = queue_debug
         self.log_impl = ReadOnlyNamespace(**log_namespace)
 
         self._help = None
-        self._help_option = self.option_impl(
-            '--help', help='print this message', category=HELP_OPTIONS_CATEGORY)
+        self._help_option = self.option_impl('--help',
+                                             help='print this message')
         self._seen.add(self._help_option)
 
         self._always = DependsFunction(self, lambda: True, [])
         self._never = DependsFunction(self, lambda: False, [])
 
         if self._value_for(self._help_option):
             self._help = HelpFormatter(argv[0])
             self._help.add(self._help_option)
@@ -675,22 +671,16 @@ class ConfigureSandbox(dict):
         be used.
         Command line argument/environment variable parsing for this Option is
         handled here.
         '''
         when = self._normalize_when(kwargs.get('when'), 'option')
         args = [self._resolve(arg) for arg in args]
         kwargs = {k: self._resolve(v) for k, v in six.iteritems(kwargs)
                   if k != 'when'}
-        # The Option constructor needs to look up the stack to infer a category
-        # for the Option, since the category is based on the filename where the
-        # Option is defined. However, if the Option is defined in a template, we
-        # want the category to reference the caller of the template rather than
-        # the caller of the option() function.
-        kwargs['define_depth'] = self._template_depth * 3
         option = Option(*args, **kwargs)
         if when:
             self._conditions[option] = when
         if option.name in self._options:
             raise ConfigureError('Option `%s` already defined' % option.option)
         if option.env in self._options:
             raise ConfigureError('Option `%s` already defined' % option.env)
         if option.name:
@@ -803,19 +793,17 @@ class ConfigureSandbox(dict):
             # file. It can however depend on variables from the closure, thus
             # maybe_prepare_function and isfunction are declared above to be
             # available there.
             @self.wraps(template)
             def wrapper(*args, **kwargs):
                 args = [maybe_prepare_function(arg) for arg in args]
                 kwargs = {k: maybe_prepare_function(v)
                           for k, v in kwargs.items()}
-                self._template_depth += 1
                 ret = template(*args, **kwargs)
-                self._template_depth -= 1
                 if isfunction(ret):
                     # We can't expect the sandboxed code to think about all the
                     # details of implementing decorators, so do some of the
                     # work for them. If the function takes exactly one function
                     # as argument and returns a function, it must be a
                     # decorator, so mark the returned function as wrapping the
                     # function passed in.
                     if len(args) == 1 and not kwargs and isfunction(args[0]):
--- a/python/mozbuild/mozbuild/configure/help.py
+++ b/python/mozbuild/mozbuild/configure/help.py
@@ -1,55 +1,49 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import absolute_import, print_function, unicode_literals
 
-from collections import defaultdict
 import os
 import re
 from mozbuild.configure.options import Option
 
 
 class HelpFormatter(object):
     def __init__(self, argv0):
         self.intro = ['Usage: %s [options]' % os.path.basename(argv0)]
-        self.options = []
+        self.options = ['Options: [defaults in brackets after descriptions]']
+        self.env = ['Environment variables:']
 
     def add(self, option):
         assert isinstance(option, Option)
+
         if option.possible_origins == ('implied',):
             # Don't display help if our option can only be implied.
             return
-        self.options.append(option)
 
-    def format_options_by_category(self, options_by_category):
-        ret = []
-        for category, options in sorted(options_by_category.items(),
-                                        key=lambda x: x[0]):
-            ret.append('  ' + category + ':')
-            for option in sorted(options, key=lambda opt: opt.option):
-                opt = option.option
-                if option.choices:
-                    opt += '={%s}' % ','.join(option.choices)
-                help = self.format_help(option)
-                if len(option.default):
-                    if help:
-                        help += ' '
-                    help += '[%s]' % ','.join(option.default)
+        # TODO: improve formatting
+        target = self.options if option.name else self.env
+        opt = option.option
+        if option.choices:
+            opt += '={%s}' % ','.join(option.choices)
+        help = self.format_help(option)
+        if len(option.default):
+            if help:
+                help += ' '
+            help += '[%s]' % ','.join(option.default)
 
-                if len(opt) > 24 or not help:
-                    ret.append('    %s' % opt)
-                    if help:
-                        ret.append('%s%s' % (' ' * 30, help))
-                else:
-                    ret.append('    %-24s  %s' % (opt, help))
-            ret.append('')
-        return ret
+        if len(opt) > 24 or not help:
+            target.append('  %s' % opt)
+            if help:
+                target.append('%s%s' % (' ' * 28, help))
+        else:
+            target.append('  %-24s  %s' % (opt, help))
 
     RE_FORMAT = re.compile(r'{([^|}]*)\|([^|}]*)}')
 
     # Return formatted help text for --{enable,disable,with,without}-* options.
     #
     # Format is the following syntax:
     #   {String for --enable or --with|String for --disable or --without}
     #
@@ -66,22 +60,11 @@ class HelpFormatter(object):
         elif option.prefix in ('disable', 'without'):
             replacement = r'\2'
         else:
             return option.help
 
         return self.RE_FORMAT.sub(replacement, option.help)
 
     def usage(self, out):
-        options_by_category = defaultdict(list)
-        env_by_category = defaultdict(list)
-        for option in self.options:
-            target = options_by_category if option.name else env_by_category
-            target[option.category].append(option)
-        options_formatted = [
-            'Options: [defaults in brackets after descriptions]'
-        ] + self.format_options_by_category(options_by_category)
-        env_formatted = (['Environment variables:'] +
-                         self.format_options_by_category(env_by_category))
         print('\n\n'.join('\n'.join(t)
-                          for t in (self.intro, options_formatted,
-                                    env_formatted)),
+                          for t in (self.intro, self.options, self.env)),
               file=out)
--- a/python/mozbuild/mozbuild/configure/options.py
+++ b/python/mozbuild/mozbuild/configure/options.py
@@ -1,34 +1,18 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import absolute_import, print_function, unicode_literals
 
-from collections import OrderedDict
-import inspect
 import os
 import six
 import sys
-
-
-HELP_OPTIONS_CATEGORY = 'Help options'
-# List of whitelisted option categories. If you want to add a new category,
-# simply add it to this list; however, exercise discretion as
-# "./configure --help" becomes less useful if there are an excessive number of
-# categories.
-_ALL_CATEGORIES = (
-    HELP_OPTIONS_CATEGORY,
-)
-
-
-def _infer_option_category(define_depth):
-    stack_frame = inspect.stack()[3 + define_depth]
-    return 'Options from ' + os.path.relpath(stack_frame[0].f_code.co_filename)
+from collections import OrderedDict
 
 
 def istupleofstrings(obj):
     return isinstance(obj, tuple) and len(obj) and all(
         isinstance(o, six.string_types) for o in obj)
 
 
 class OptionValue(tuple):
@@ -169,34 +153,24 @@ class Option(object):
     - `default` can be used to give a default value to the option. When the
       `name` of the option starts with '--enable-' or '--with-', the implied
       default is an empty PositiveOptionValue. When it starts with '--disable-'
       or '--without-', the implied default is a NegativeOptionValue.
     - `choices` restricts the set of values that can be given to the option.
     - `help` is the option description for use in the --help output.
     - `possible_origins` is a tuple of strings that are origins accepted for
       this option. Example origins are 'mozconfig', 'implied', and 'environment'.
-    - `category` is a human-readable string used only for categorizing command-
-      line options when displaying the output of `configure --help`. If not
-      supplied, the script will attempt to infer an appropriate category based
-      on the name of the file where the option was defined. If supplied it must
-      be in the _ALL_CATEGORIES list above.
-    - `define_depth` should generally only be used by templates that are used
-      to instantiate an option indirectly. Set this to a positive integer to
-      force the script to look into a deeper stack frame when inferring the
-      `category`.
     '''
     __slots__ = (
         'id', 'prefix', 'name', 'env', 'nargs', 'default', 'choices', 'help',
-        'possible_origins', 'category', 'define_depth',
+        'possible_origins',
     )
 
     def __init__(self, name=None, env=None, nargs=None, default=None,
-                 possible_origins=None, choices=None, category=None, help=None,
-                 define_depth=0):
+                 possible_origins=None, choices=None, help=None):
         if not name and not env:
             raise InvalidOptionError(
                 'At least an option name or an environment variable name must '
                 'be given')
         if name:
             if not isinstance(name, six.string_types):
                 raise InvalidOptionError('Option must be a string')
             if not name.startswith('--'):
@@ -219,24 +193,16 @@ class Option(object):
         if (not isinstance(default, six.string_types) and
                 not isinstance(default, (bool, type(None))) and
                 not istupleofstrings(default)):
             raise InvalidOptionError(
                 'default must be a bool, a string or a tuple of strings')
         if choices and not istupleofstrings(choices):
             raise InvalidOptionError(
                 'choices must be a tuple of strings')
-        if category and not isinstance(category, six.string_types):
-            raise InvalidOptionError('Category must be a string')
-        if category and category not in _ALL_CATEGORIES:
-            raise InvalidOptionError(
-                'Category must either be inferred or in the _ALL_CATEGORIES '
-                'list in options.py: %s' % ', '.join(_ALL_CATEGORIES))
-        if not isinstance(define_depth, int):
-            raise InvalidOptionError('DefineDepth must be an integer')
         if not help:
             raise InvalidOptionError('A help string must be provided')
         if possible_origins and not istupleofstrings(possible_origins):
             raise InvalidOptionError(
                 'possible_origins must be a tuple of strings')
         self.possible_origins = possible_origins
 
         if name:
@@ -296,17 +262,16 @@ class Option(object):
                     'The `default` value must be one of %s' %
                     ', '.join("'%s'" % c for c in choices))
         elif has_choices:
             maxargs = self.maxargs
             if len(choices) < maxargs and maxargs != sys.maxint:
                 raise InvalidOptionError('Not enough `choices` for `nargs`')
         self.choices = choices
         self.help = help
-        self.category = category or _infer_option_category(define_depth)
 
     @staticmethod
     def split_option(option):
         '''Split a flag or variable into a prefix, a name and values
 
         Variables come in the form NAME=values (no prefix).
         Flags come in the form --name=values or --prefix-name=values
         where prefix is one of 'with', 'without', 'enable' or 'disable'.
--- a/python/mozbuild/mozbuild/test/configure/data/included.configure
+++ b/python/mozbuild/mozbuild/test/configure/data/included.configure
@@ -46,12 +46,8 @@ def platform():
 
 option('--enable-imports-in-template', help='Imports in template')
 @depends('--enable-imports-in-template')
 def check(value):
     if value:
         return platform()
 
 set_config('PLATFORM', check)
-
-@template
-def indirectly_define_option(*args, **kwargs):
-    option(*args, **kwargs)
--- a/python/mozbuild/mozbuild/test/configure/data/moz.configure
+++ b/python/mozbuild/mozbuild/test/configure/data/moz.configure
@@ -165,15 +165,8 @@ def with_imports(value):
 set_config('HAS_GETATIME', with_imports)
 
 @depends('--with-imports')
 def with_imports(value):
     if len(value):
         return hasattr(os.path, 'getatime')
 
 set_config('HAS_GETATIME2', with_imports)
-
-# This option should be attributed to this file in the --help output even though
-# included.configure is the actual file that defines the option.
-indirectly_define_option('--indirect-option', help='Indirectly defined option')
-@depends('--indirect-option')
-def indirect_option(option):
-    return option
--- a/python/mozbuild/mozbuild/test/configure/test_configure.py
+++ b/python/mozbuild/mozbuild/test/configure/test_configure.py
@@ -37,17 +37,17 @@ class TestConfigure(unittest.TestCase):
                    prog='/bin/configure'):
         config = {}
         out = StringIO()
         sandbox = ConfigureSandbox(config, env, [prog] + options, out, out)
 
         sandbox.run(mozpath.join(test_data_path, configure))
 
         if '--help' in options:
-            return out.getvalue().decode('utf-8'), config
+            return out.getvalue(), config
         self.assertEquals('', out.getvalue())
         return config
 
     def moz_configure(self, source):
         return MockedOpen({
             os.path.join(test_data_path,
                          'moz.configure'): textwrap.dedent(source)
         })
@@ -72,40 +72,34 @@ class TestConfigure(unittest.TestCase):
         help, config = self.get_config(['--help'], prog='configure')
 
         self.assertEquals({}, config)
         self.maxDiff = None
         self.assertEquals(
             'Usage: configure [options]\n'
             '\n'
             'Options: [defaults in brackets after descriptions]\n'
-            '  Help options:\n'
-            '    --help                    print this message\n'
-            '\n'
-            '  Options from python/mozbuild/mozbuild/test/configure/data/included.configure:\n'
-            '    --enable-imports-in-template\n                              Imports in template\n'
-            '\n'
-            '  Options from python/mozbuild/mozbuild/test/configure/data/moz.configure:\n'
-            '    --enable-include          Include\n'
-            '    --enable-simple           Enable simple\n'
-            '    --enable-values           Enable values\n'
-            '    --enable-with-env         Enable with env\n'
-            '    --indirect-option         Indirectly defined option\n'
-            '    --option                  Option\n'
-            '    --returned-choices        Choices\n'
-            '    --with-imports            Imports\n'
-            '    --with-returned-default   Returned default [not-simple]\n'
-            '    --with-stuff              Build with stuff\n'
-            '    --without-thing           Build without thing\n'
-            '\n'
+            '  --help                    print this message\n'
+            '  --enable-simple           Enable simple\n'
+            '  --enable-with-env         Enable with env\n'
+            '  --enable-values           Enable values\n'
+            '  --without-thing           Build without thing\n'
+            '  --with-stuff              Build with stuff\n'
+            '  --option                  Option\n'
+            '  --with-returned-default   Returned default [not-simple]\n'
+            '  --returned-choices        Choices\n'
+            '  --enable-imports-in-template\n'
+            '                            Imports in template\n'
+            '  --enable-include          Include\n'
+            '  --with-imports            Imports\n'
             '\n'
             'Environment variables:\n'
-            '  Options from python/mozbuild/mozbuild/test/configure/data/moz.configure:\n'
-            '    CC                        C Compiler\n'
-            '\n', help)
+            '  CC                        C Compiler\n',
+            help
+        )
 
     def test_unknown(self):
         with self.assertRaises(InvalidOptionError):
             self.get_config(['--unknown'])
 
     def test_simple(self):
         for config in (
                 self.get_config(),
@@ -1008,38 +1002,30 @@ class TestConfigure(unittest.TestCase):
                 'FOO': NegativeOptionValue(),
             })
 
             help, config = self.get_config(['--help'])
             self.assertEquals(help, textwrap.dedent('''\
                 Usage: configure [options]
 
                 Options: [defaults in brackets after descriptions]
-                  Help options:
-                    --help                    print this message
-
-                  Options from python/mozbuild/mozbuild/test/configure/data/moz.configure:
-                    --with-foo                foo
-
+                  --help                    print this message
+                  --with-foo                foo
 
                 Environment variables:
             '''))
 
             help, config = self.get_config(['--help', '--with-foo'])
             self.assertEquals(help, textwrap.dedent('''\
                 Usage: configure [options]
 
                 Options: [defaults in brackets after descriptions]
-                  Help options:
-                    --help                    print this message
-
-                  Options from python/mozbuild/mozbuild/test/configure/data/moz.configure:
-                    --with-foo                foo
-                    --with-qux                qux
-
+                  --help                    print this message
+                  --with-foo                foo
+                  --with-qux                qux
 
                 Environment variables:
             '''))
 
         with self.moz_configure('''
             option('--with-foo', help='foo', when=True)
             set_config('FOO', depends('--with-foo')(lambda x: x))
         '''):