Bug 1641962: Defer imports of distutils.util to ensure bootstrap can run r=rstewart,perftest-reviewers,sparky
authorMitchell Hentges <mhentges@mozilla.com>
Fri, 29 May 2020 20:17:27 +0000
changeset 533051 2050484c1868668644ad4801eac2990dd7556342
parent 533050 a7395b8a770653da17905eeb991203f897058b22
child 533052 df8bd16c2935394df0cc53b9f15dad330a72343d
push id37462
push usermalexandru@mozilla.com
push dateSat, 30 May 2020 09:46:43 +0000
treeherdermozilla-central@8aaca63ec5c6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrstewart, perftest-reviewers, sparky
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 1641962: Defer imports of distutils.util to ensure bootstrap can run r=rstewart,perftest-reviewers,sparky Differential Revision: https://phabricator.services.mozilla.com/D77516
--- a/taskcluster/mach_commands.py
+++ b/taskcluster/mach_commands.py
@@ -10,28 +10,39 @@ from __future__ import absolute_import, 
 import argparse
 import json
 import logging
 import os
 from six import text_type
 import sys
 import traceback
 import re
-from distutils.util import strtobool
 from mach.decorators import (
 from mozbuild.base import MachCommandBase
+def strtobool(value):
+    """Convert string to boolean.
+    Wraps "distutils.util.strtobool", deferring the import of the package
+    in case it's not installed. Otherwise, we have a "chicken and egg problem" where
+    |mach bootstrap| would install the required package to enable "distutils.util", but
+    it can't because mach fails to interpret this file.
+    """
+    from distutils.util import strtobool
+    return bool(strtobool(value))
 class ShowTaskGraphSubCommand(SubCommand):
     """A SubCommand with TaskGraph-specific arguments"""
     def __call__(self, func):
         after = SubCommand.__call__(self, func)
         args = [
             CommandArgument('--root', '-r',
                             help="root of the taskgraph definition relative to topsrcdir"),
@@ -157,17 +168,17 @@ class MachCommands(MachCommandBase):
     @CommandArgument('--owner', type=text_type, required=True,
                      help='email address of who owns this graph')
     @CommandArgument('--level', type=text_type, required=True,
                      help='SCM level of this repository')
     @CommandArgument('--target-tasks-method', type=text_type,
                      help='method for selecting the target tasks to generate')
-                     type=lambda flag: bool(strtobool(flag)),
+                     type=lambda flag: strtobool(flag),
                      nargs='?', const='true',
                      help='If specified, this indicates whether the target '
                           'tasks are eligible for optimization. Otherwise, '
                           'the default for the project is used.')
     @CommandArgument('--try-task-config-file', type=text_type,
                      help='path to try task configuration file')
     @CommandArgument('--tasks-for', type=text_type, required=True,
                      help='the tasks_for value used to generate this task')
--- a/testing/raptor/mach_commands.py
+++ b/testing/raptor/mach_commands.py
@@ -20,17 +20,16 @@ import mozfile
 from mach.decorators import Command, CommandProvider
 from mozboot.util import get_state_dir
 from mozbuild.base import (
 from mozbuild.base import MachCommandConditions as Conditions
-from raptor.power import enable_charging, disable_charging
 HERE = os.path.dirname(os.path.realpath(__file__))
 BENCHMARK_REPOSITORY = 'https://github.com/mozilla/perf-automation'
 BENCHMARK_REVISION = 'e19a0865c946ae2f9a64dd25614b1c275a3996b2'
 ANDROID_BROWSERS = ["fennec", "geckoview", "refbrow", "fenix", "chrome-m"]
@@ -217,16 +216,20 @@ def create_parser():
 class MachRaptor(MachCommandBase):
     @Command('raptor', category='testing',
              description='Run Raptor performance tests.',
     def run_raptor(self, **kwargs):
+        # Defers this import so that a transitive dependency doesn't
+        # stop |mach bootstrap| from running
+        from raptor.power import enable_charging, disable_charging
         build_obj = self
         is_android = Conditions.is_android(build_obj) or \
             kwargs['app'] in ANDROID_BROWSERS
         if is_android:
             from mozrunner.devices.android_device import (verify_android_device, InstallIntent)
             from mozdevice import ADBAndroid