Bug 1528241 - Add a trace mode to python configure that logs internal values. r=chmanchester
authorMike Hommey <mh+mozilla@glandium.org>
Fri, 15 Feb 2019 22:52:47 +0900
changeset 517889 effd6611eaccae8fcc3572286a229f9efe96ce7d
parent 517888 20edea24a191284d3547fed803e9faae40192be1
child 517890 e48a5648d0674bcee624f67a898ce17a21898b22
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
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 1528241 - Add a trace mode to python configure that logs internal values. r=chmanchester Differential Revision: https://phabricator.services.mozilla.com/D19940
--- a/configure.py
+++ b/configure.py
@@ -9,29 +9,37 @@ import itertools
 import logging
 import os
 import sys
 import textwrap
 base_dir = os.path.abspath(os.path.dirname(__file__))
 sys.path.insert(0, os.path.join(base_dir, 'python', 'mozbuild'))
-from mozbuild.configure import ConfigureSandbox
+from mozbuild.configure import (
+    ConfigureSandbox,
+    TRACE,
 from mozbuild.pythonutil import iter_modules_in_path
 from mozbuild.backend.configenvironment import PartialConfigEnvironment
 from mozbuild.util import (
 import mozpack.path as mozpath
 def main(argv):
     config = {}
     sandbox = ConfigureSandbox(config, os.environ, argv)
+    if os.environ.get('MOZ_CONFIGURE_TRACE'):
+        sandbox._logger.setLevel(TRACE)
     sandbox.run(os.path.join(os.path.dirname(__file__), 'moz.configure'))
     if sandbox._help:
         return 0
     return config_status(config)
--- a/python/mozbuild/mozbuild/configure/__init__.py
+++ b/python/mozbuild/mozbuild/configure/__init__.py
@@ -36,16 +36,20 @@ from mozbuild.util import (
 import mozpack.path as mozpath
+# TRACE logging level, below (thus more verbose than) DEBUG
+TRACE = 5
 class ConfigureError(Exception):
 class SandboxDependsFunction(object):
     '''Sandbox-visible representation of @depends functions.'''
     def __init__(self, unsandboxed):
         self._or = unsandboxed.__or__
@@ -144,18 +148,17 @@ class DependsFunction(object):
         if self.when and not self.sandbox._value_for(self.when):
             return None
         resolved_args = [self.sandbox._value_for(d)
                          for d in self.dependencies]
         return self._func(*resolved_args)
     def __repr__(self):
-        return '<%s.%s %s(%s)>' % (
-            self.__class__.__module__,
+        return '<%s %s(%s)>' % (
             ', '.join(repr(d) for d in self.dependencies),
     def __or__(self, other):
         if isinstance(other, SandboxDependsFunction):
             other = self.sandbox._depends.get(other)
@@ -328,16 +331,17 @@ 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
+        logging.addLevelName(TRACE, 'TRACE')
         if logger is None:
             logger = moz_logger = logging.getLogger('moz.configure')
             formatter = logging.Formatter('%(levelname)s: %(message)s')
             handler = ConfigureOutputHandler(stdout, stderr)
             queue_debug = handler.queue_debug
@@ -506,17 +510,19 @@ class ConfigureSandbox(dict):
         elif isinstance(obj, Option):
             return self._value_for_option(obj)
         assert False
     def _value_for_depends(self, obj):
-        return obj.result()
+        value = obj.result()
+        self._logger.log(TRACE, '%r = %r', obj, value)
+        return value
     def _value_for_option(self, option):
         implied = {}
         for implied_option in self._implied_options[:]:
             if implied_option.name not in (option.name, option.env):
@@ -567,18 +573,20 @@ class ConfigureSandbox(dict):
         if when and not self._value_for(when) and value is not None:
             # If the option was passed explicitly, we throw an error that
             # the option is not available. Except when the option was passed
             # from the environment, because that would be too cumbersome.
             if value.origin not in ('default', 'environment'):
                 raise InvalidOptionError(
                     '%s is not available in this configuration'
                     % option_string.split('=', 1)[0])
+            self._logger.log(TRACE, '%r = None', option)
             return None
+        self._logger.log(TRACE, '%r = %r', option, value)
         return value
     def _dependency(self, arg, callee_name, arg_name=None):
         if isinstance(arg, types.StringTypes):
             prefix, name, values = Option.split_option(arg)
             if values != ():
                 raise ConfigureError("Option must not contain an '='")
             if name not in self._options:
@@ -901,16 +909,21 @@ class ConfigureSandbox(dict):
         if not isinstance(name, types.StringTypes):
             raise TypeError("Unexpected type: '%s'" % type(name).__name__)
         if name in data:
             raise ConfigureError(
                 "Cannot add '%s' to configuration: Key already "
                 "exists" % name)
         value = self._resolve(value)
         if value is not None:
+            if self._logger.isEnabledFor(TRACE):
+                if data is self._config:
+                    self._logger.log(TRACE, 'set_config(%s, %r)', name, value)
+                elif data is self._config.get('DEFINES'):
+                    self._logger.log(TRACE, 'set_define(%s, %r)', name, value)
             data[name] = value
     def set_config_impl(self, name, value, when=None):
         '''Implementation of set_config().
         Set the configuration items with the given name to the given value.
         Both `name` and `value` can be references to @depends functions,
         in which case the result from these functions is used. If the result
         of either function is None, the configuration item is not set.
--- a/python/mozbuild/mozbuild/configure/options.py
+++ b/python/mozbuild/mozbuild/configure/options.py
@@ -383,18 +383,17 @@ class Option(object):
                         % (val, ', '.join("'%s'" % c for c in self.choices)))
             if relative_result is not None:
                 values = PositiveOptionValue(relative_result, origin=origin)
         return values
     def __repr__(self):
-        return '<%s.%s [%s]>' % (self.__class__.__module__,
-                                 self.__class__.__name__, self.option)
+        return '<%s [%s]>' % (self.__class__.__name__, self.option)
 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
     command line, or as FOO=1 in the environment *or* on the command line.