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
bugs1641962
milestone78.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 1641962: Defer imports of distutils.util to ensure bootstrap can run r=rstewart,perftest-reviewers,sparky Differential Revision: https://phabricator.services.mozilla.com/D77516
taskcluster/mach_commands.py
testing/raptor/mach_commands.py
--- 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 (
     CommandArgument,
     CommandProvider,
     Command,
     SubCommand,
 )
 
 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):
                      default=0)
     @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')
     @CommandArgument('--optimize-target-tasks',
-                     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 (
     MachCommandBase,
     MozbuildObject,
     BinaryNotFoundException,
 )
 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():
 
 
 @CommandProvider
 class MachRaptor(MachCommandBase):
     @Command('raptor', category='testing',
              description='Run Raptor performance tests.',
              parser=create_parser)
     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