From ed90a04ad16a02a2dee89ace8113c2a3e3fecf55 Mon Sep 17 00:00:00 2001 From: Mitchell Hentges Date: Mon, 8 Jun 2020 19:36:56 +0000 Subject: [PATCH] Bug 1632874: |mach bootstrap| should write mozconfig file if it doesn't exist r=rstewart Rather than always printing instructions at the end of the bootstrap phase, we will now create a mozconfig file if one doesn't exist and there's configuration to be written. Differential Revision: https://phabricator.services.mozilla.com/D78417 --- build/docs/mozconfigs.rst | 10 +- build/moz.configure/init.configure | 3 +- configure.py | 1 + python/mozboot/mozboot/android.py | 25 +- python/mozboot/mozboot/archlinux.py | 8 +- python/mozboot/mozboot/base.py | 21 +- python/mozboot/mozboot/bootstrap.py | 27 ++- python/mozboot/mozboot/centosfedora.py | 8 +- python/mozboot/mozboot/debian.py | 8 +- python/mozboot/mozboot/gentoo.py | 8 +- python/mozboot/mozboot/mozconfig.py | 127 ++++++++++ python/mozboot/mozboot/mozillabuild.py | 8 +- python/mozboot/mozboot/opensuse.py | 8 +- python/mozboot/mozboot/osx.py | 19 +- python/mozboot/mozboot/solus.py | 8 +- python/mozboot/mozboot/test/python.ini | 1 + python/mozboot/mozboot/test/test_mozconfig.py | 229 ++++++++++++++++++ python/mozboot/mozboot/void.py | 8 +- python/mozbuild/mozbuild/base.py | 2 +- python/mozbuild/mozbuild/mozconfig.py | 124 +--------- .../mozbuild/mozbuild/test/test_mozconfig.py | 189 +-------------- testing/mozbase/mozinfo/mozinfo/mozinfo.py | 2 +- 22 files changed, 460 insertions(+), 384 deletions(-) create mode 100644 python/mozboot/mozboot/mozconfig.py create mode 100644 python/mozboot/mozboot/test/test_mozconfig.py diff --git a/build/docs/mozconfigs.rst b/build/docs/mozconfigs.rst index f71c75a26c4c..1859b8787566 100644 --- a/build/docs/mozconfigs.rst +++ b/build/docs/mozconfigs.rst @@ -57,7 +57,13 @@ Finding the active mozconfig Multiple mozconfig files can exist to provide different configuration options for different tasks. The rules for finding the active mozconfig are defined in the -:py:func:`mozbuild.mozconfig.MozconfigLoader.find_mozconfig` method: +:py:func:`mozboot.mozconfig.find_mozconfig` method. + +.. automodule:: mozboot.mozconfig + :members: find_mozconfig + +Loading the active mozconfig +---------------------------- .. autoclass:: mozbuild.mozconfig.MozconfigLoader - :members: find_mozconfig + :members: read_mozconfig diff --git a/build/moz.configure/init.configure b/build/moz.configure/init.configure index b74e7f8db4af..d9ee35886d39 100644 --- a/build/moz.configure/init.configure +++ b/build/moz.configure/init.configure @@ -159,6 +159,7 @@ add_old_configure_assignment('EXTERNAL_SOURCE_DIR', external_source_dir) check_build_environment, '--with-external-source-dir', '--help') @imports(_from='mozbuild.mozconfig', _import='MozconfigLoader') +@imports(_from='mozboot.mozconfig', _import='find_mozconfig') def mozconfig(mozconfig, old_configure, build_env, external_source_dir, help): if not old_configure and not help: @@ -188,7 +189,7 @@ def mozconfig(mozconfig, old_configure, build_env, topsrcdir = external_source_dir[0] loader = MozconfigLoader(topsrcdir) mozconfig = mozconfig[0] if mozconfig else None - mozconfig = loader.find_mozconfig(env={'MOZCONFIG': mozconfig}) + mozconfig = find_mozconfig(topsrcdir, env={'MOZCONFIG': mozconfig}) mozconfig = loader.read_mozconfig(mozconfig) return mozconfig diff --git a/configure.py b/configure.py index ef85e246822a..fe55a35810dd 100644 --- a/configure.py +++ b/configure.py @@ -20,6 +20,7 @@ except ImportError: base_dir = os.path.abspath(os.path.dirname(__file__)) +sys.path.insert(0, os.path.join(base_dir, 'python', 'mozboot')) sys.path.insert(0, os.path.join(base_dir, 'python', 'mozbuild')) sys.path.insert(0, os.path.join(base_dir, 'third_party', 'python', 'six')) from mozbuild.configure import ( diff --git a/python/mozboot/mozboot/android.py b/python/mozboot/mozboot/android.py index 17a2b0efa8c8..d4d8c755f892 100644 --- a/python/mozboot/mozboot/android.py +++ b/python/mozboot/mozboot/android.py @@ -13,6 +13,8 @@ import sys # We need the NDK version in multiple different places, and it's inconvenient # to pass down the NDK version to all relevant places, so we have this global # variable. +from mozboot.bootstrap import MOZCONFIG_SUGGESTION_TEMPLATE + NDK_VERSION = 'r20' ANDROID_NDK_EXISTS = ''' @@ -42,10 +44,6 @@ output as packages are downloaded and installed. ''' MOBILE_ANDROID_MOZCONFIG_TEMPLATE = ''' -Paste the lines between the chevrons (>>> and <<<) into your -$topsrcdir/mozconfig file, or create the file if it does not exist: - ->>> # Build GeckoView/Firefox for Android: ac_add_options --enable-application=mobile/android @@ -59,14 +57,9 @@ ac_add_options --enable-application=mobile/android # ac_add_options --target=x86_64 {extra_lines} -<<< ''' MOBILE_ANDROID_ARTIFACT_MODE_MOZCONFIG_TEMPLATE = ''' -Paste the lines between the chevrons (>>> and <<<) into your -$topsrcdir/mozconfig file, or create the file if it does not exist: - ->>> # Build GeckoView/Firefox for Android Artifact Mode: ac_add_options --enable-application=mobile/android ac_add_options --target=arm-linux-androideabi @@ -75,7 +68,6 @@ ac_add_options --enable-artifact-builds {extra_lines} # Write build artifacts to: mk_add_options MOZ_OBJDIR=./objdir-frontend -<<< ''' @@ -304,7 +296,7 @@ def ensure_android_packages(sdkmanager_tool, emulator_only=False, no_interactive raise e -def suggest_mozconfig(os_name, artifact_mode=False): +def generate_mozconfig(os_name, artifact_mode=False): moz_state_dir, sdk_path, ndk_path = get_paths(os_name) extra_lines = [] @@ -322,7 +314,7 @@ def suggest_mozconfig(os_name, artifact_mode=False): moz_state_dir=moz_state_dir, extra_lines='\n'.join(extra_lines), ) - print(template.format(**kwargs)) + return template.format(**kwargs).strip() def android_ndk_url(os_name, ver=NDK_VERSION): @@ -379,7 +371,14 @@ def main(argv): ndk_only=options.ndk_only, emulator_only=options.emulator_only, no_interactive=options.no_interactive) - suggest_mozconfig(os_name, options.artifact_mode) + mozconfig = generate_mozconfig(os_name, options.artifact_mode) + + # |./mach bootstrap| automatically creates a mozconfig file for you if it doesn't + # exist. However, here, we don't know where the "topsrcdir" is, and it's not worth + # pulling in CommandContext (and its dependencies) to find out. + # So, instead, we'll politely ask users to create (or update) the file themselves. + suggestion = MOZCONFIG_SUGGESTION_TEMPLATE % ("$topsrcdir/mozconfig", mozconfig) + print('\n' + suggestion) return 0 diff --git a/python/mozboot/mozboot/archlinux.py b/python/mozboot/mozboot/archlinux.py index 8dd72e44bb2a..5f3a6d51f731 100644 --- a/python/mozboot/mozboot/archlinux.py +++ b/python/mozboot/mozboot/archlinux.py @@ -125,12 +125,12 @@ class ArchlinuxBootstrapper( android.ensure_android('linux', artifact_mode=artifact_mode, no_interactive=self.no_interactive) - def suggest_mobile_android_mozconfig(self, artifact_mode=False): + def generate_mobile_android_mozconfig(self, artifact_mode=False): from mozboot import android - android.suggest_mozconfig('linux', artifact_mode=artifact_mode) + return android.generate_mozconfig('linux', artifact_mode=artifact_mode) - def suggest_mobile_android_artifact_mode_mozconfig(self): - self.suggest_mobile_android_mozconfig(artifact_mode=True) + def generate_mobile_android_artifact_mode_mozconfig(self): + return self.generate_mobile_android_mozconfig(artifact_mode=True) def _update_package_manager(self): self.pacman_update diff --git a/python/mozboot/mozboot/base.py b/python/mozboot/mozboot/base.py index a4a1c13f8387..3fffa5b1a9f4 100644 --- a/python/mozboot/mozboot/base.py +++ b/python/mozboot/mozboot/base.py @@ -142,14 +142,9 @@ tool or package manager on your system, or directly from https://rust-lang.org/ ''' BROWSER_ARTIFACT_MODE_MOZCONFIG = ''' -Paste the lines between the chevrons (>>> and <<<) into your -$topsrcdir/mozconfig file, or create the file if it does not exist: - ->>> # Automatically download and use compiled C++ components: ac_add_options --enable-artifact-builds -<<< -''' +'''.strip() # Upgrade Mercurial older than this. MODERN_MERCURIAL_VERSION = LooseVersion('4.8') @@ -191,7 +186,7 @@ class BaseBootstrapper(object): '%s does not yet implement install_browser_packages()' % __name__) - def suggest_browser_mozconfig(self): + def generate_browser_mozconfig(self): ''' Print a message to the console detailing what the user's mozconfig should contain. @@ -211,7 +206,7 @@ class BaseBootstrapper(object): '%s does not yet implement install_browser_artifact_mode_packages()' % __name__) - def suggest_browser_artifact_mode_mozconfig(self): + def generate_browser_artifact_mode_mozconfig(self): ''' Print a message to the console detailing what the user's mozconfig should contain. @@ -219,7 +214,7 @@ class BaseBootstrapper(object): Firefox for Desktop Artifact Mode needs to enable artifact builds and a path where the build artifacts will be written to. ''' - print(BROWSER_ARTIFACT_MODE_MOZCONFIG) + return BROWSER_ARTIFACT_MODE_MOZCONFIG def install_mobile_android_packages(self): ''' @@ -230,7 +225,7 @@ class BaseBootstrapper(object): '%s does not yet implement install_mobile_android_packages()' % __name__) - def suggest_mobile_android_mozconfig(self): + def generate_mobile_android_mozconfig(self): ''' Print a message to the console detailing what the user's mozconfig should contain. @@ -238,7 +233,7 @@ class BaseBootstrapper(object): GeckoView/Firefox for Android needs an application and an ABI set, and it needs paths to the Android SDK and NDK. ''' - raise NotImplementedError('%s does not yet implement suggest_mobile_android_mozconfig()' % + raise NotImplementedError('%s does not yet implement generate_mobile_android_mozconfig()' % __name__) def install_mobile_android_artifact_mode_packages(self): @@ -251,7 +246,7 @@ class BaseBootstrapper(object): '%s does not yet implement install_mobile_android_artifact_mode_packages()' % __name__) - def suggest_mobile_android_artifact_mode_mozconfig(self): + def generate_mobile_android_artifact_mode_mozconfig(self): ''' Print a message to the console detailing what the user's mozconfig should contain. @@ -260,7 +255,7 @@ class BaseBootstrapper(object): and it needs paths to the Android SDK. ''' raise NotImplementedError( - '%s does not yet implement suggest_mobile_android_artifact_mode_mozconfig()' + '%s does not yet implement generate_mobile_android_artifact_mode_mozconfig()' % __name__) def ensure_clang_static_analysis_package(self, state_dir, checkout_root): diff --git a/python/mozboot/mozboot/bootstrap.py b/python/mozboot/mozboot/bootstrap.py index 92f381baf036..faf8a2569686 100644 --- a/python/mozboot/mozboot/bootstrap.py +++ b/python/mozboot/mozboot/bootstrap.py @@ -42,6 +42,7 @@ from mozboot.solus import SolusBootstrapper from mozboot.void import VoidBootstrapper from mozboot.windows import WindowsBootstrapper from mozboot.mozillabuild import MozillaBuildBootstrapper +from mozboot.mozconfig import find_mozconfig from mozboot.util import ( get_state_dir, ) @@ -111,6 +112,15 @@ FINISHED = ''' Your system should be ready to build %s! ''' +MOZCONFIG_SUGGESTION_TEMPLATE = ''' +Paste the lines between the chevrons (>>> and <<<) into +%s: + +>>> +%s +<<< +'''.strip() + SOURCE_ADVERTISE = ''' Source code can be obtained by running @@ -555,8 +565,21 @@ class Bootstrapper(object): if not self.instance.which("moz-phab"): print(MOZ_PHAB_ADVERTISE) - # Like 'suggest_browser_mozconfig' or 'suggest_mobile_android_mozconfig'. - getattr(self.instance, 'suggest_%s_mozconfig' % application)() + # Like 'generate_browser_mozconfig' or 'generate_mobile_android_mozconfig'. + mozconfig = getattr(self.instance, 'generate_%s_mozconfig' % application)() + + if mozconfig: + mozconfig_path = find_mozconfig(self.mach_context.topdir) + if not mozconfig_path: + # No mozconfig file exists yet + mozconfig_path = os.path.join(self.mach_context.topdir, 'mozconfig') + with open(mozconfig_path, 'w') as mozconfig_file: + mozconfig_file.write(mozconfig) + print('Your requested configuration has been written to "%s".' + % mozconfig_path) + else: + suggestion = MOZCONFIG_SUGGESTION_TEMPLATE % (mozconfig_path, mozconfig) + print(suggestion) def update_vct(hg, root_state_dir): diff --git a/python/mozboot/mozboot/centosfedora.py b/python/mozboot/mozboot/centosfedora.py index 1656ae58bf73..8370105608a8 100644 --- a/python/mozboot/mozboot/centosfedora.py +++ b/python/mozboot/mozboot/centosfedora.py @@ -143,12 +143,12 @@ class CentOSFedoraBootstrapper( android.ensure_android('linux', artifact_mode=artifact_mode, no_interactive=self.no_interactive) - def suggest_mobile_android_mozconfig(self, artifact_mode=False): + def generate_mobile_android_mozconfig(self, artifact_mode=False): from mozboot import android - android.suggest_mozconfig('linux', artifact_mode=artifact_mode) + return android.generate_mozconfig('linux', artifact_mode=artifact_mode) - def suggest_mobile_android_artifact_mode_mozconfig(self): - self.suggest_mobile_android_mozconfig(artifact_mode=True) + def generate_mobile_android_artifact_mode_mozconfig(self): + return self.generate_mobile_android_mozconfig(artifact_mode=True) def upgrade_mercurial(self, current): if current is None: diff --git a/python/mozboot/mozboot/debian.py b/python/mozboot/mozboot/debian.py index 728f030530c8..1cc14637337c 100644 --- a/python/mozboot/mozboot/debian.py +++ b/python/mozboot/mozboot/debian.py @@ -159,12 +159,12 @@ class DebianBootstrapper( android.ensure_android('linux', artifact_mode=artifact_mode, no_interactive=self.no_interactive) - def suggest_mobile_android_mozconfig(self, artifact_mode=False): + def generate_mobile_android_mozconfig(self, artifact_mode=False): from mozboot import android - android.suggest_mozconfig('linux', artifact_mode=artifact_mode) + return android.generate_mozconfig('linux', artifact_mode=artifact_mode) - def suggest_mobile_android_artifact_mode_mozconfig(self): - self.suggest_mobile_android_mozconfig(artifact_mode=True) + def generate_mobile_android_artifact_mode_mozconfig(self): + return self.generate_mobile_android_mozconfig(artifact_mode=True) def _update_package_manager(self): self.apt_update() diff --git a/python/mozboot/mozboot/gentoo.py b/python/mozboot/mozboot/gentoo.py index a18f79c9eae6..ec7849df0432 100644 --- a/python/mozboot/mozboot/gentoo.py +++ b/python/mozboot/mozboot/gentoo.py @@ -60,12 +60,12 @@ class GentooBootstrapper( android.ensure_android('linux', artifact_mode=artifact_mode, no_interactive=self.no_interactive) - def suggest_mobile_android_mozconfig(self, artifact_mode=False): + def generate_mobile_android_mozconfig(self, artifact_mode=False): from mozboot import android - android.suggest_mozconfig('linux', artifact_mode=artifact_mode) + return android.generate_mozconfig('linux', artifact_mode=artifact_mode) - def suggest_mobile_android_artifact_mode_mozconfig(self): - self.suggest_mobile_android_mozconfig(artifact_mode=True) + def generate_mobile_android_artifact_mode_mozconfig(self): + return self.generate_mobile_android_mozconfig(artifact_mode=True) def _update_package_manager(self): self.run_as_root(['emerge', '--sync']) diff --git a/python/mozboot/mozboot/mozconfig.py b/python/mozboot/mozboot/mozconfig.py new file mode 100644 index 000000000000..01073446825a --- /dev/null +++ b/python/mozboot/mozboot/mozconfig.py @@ -0,0 +1,127 @@ +# 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 + +import filecmp +import os + + +MOZ_MYCONFIG_ERROR = ''' +The MOZ_MYCONFIG environment variable to define the location of mozconfigs +is deprecated. If you wish to define the mozconfig path via an environment +variable, use MOZCONFIG instead. +'''.strip() + +MOZCONFIG_LEGACY_PATH_ERROR = ''' +You currently have a mozconfig at %s. This implicit location is no longer +supported. Please move it to %s/.mozconfig or set an explicit path +via the $MOZCONFIG environment variable. +'''.strip() + +DEFAULT_TOPSRCDIR_PATHS = ('.mozconfig', 'mozconfig') +DEPRECATED_TOPSRCDIR_PATHS = ('mozconfig.sh', 'myconfig.sh') +DEPRECATED_HOME_PATHS = ('.mozconfig', '.mozconfig.sh', '.mozmyconfig.sh') + + +class MozconfigFindException(Exception): + """Raised when a mozconfig location is not defined properly.""" + + +def find_mozconfig(topsrcdir, env=os.environ): + """Find the active mozconfig file for the current environment. + + This emulates the logic in mozconfig-find. + + 1) If ENV[MOZCONFIG] is set, use that + 2) If $TOPSRCDIR/mozconfig or $TOPSRCDIR/.mozconfig exists, use it. + 3) If both exist or if there are legacy locations detected, error out. + + The absolute path to the found mozconfig will be returned on success. + None will be returned if no mozconfig could be found. A + MozconfigFindException will be raised if there is a bad state, + including conditions from #3 above. + """ + # Check for legacy methods first. + if 'MOZ_MYCONFIG' in env: + raise MozconfigFindException(MOZ_MYCONFIG_ERROR) + + env_path = env.get('MOZCONFIG', None) or None + if env_path is not None: + if not os.path.isabs(env_path): + potential_roots = [topsrcdir, os.getcwd()] + # Attempt to eliminate duplicates for e.g. + # self.topsrcdir == os.curdir. + potential_roots = set(os.path.abspath(p) for p in potential_roots) + existing = [root for root in potential_roots + if os.path.exists(os.path.join(root, env_path))] + if len(existing) > 1: + # There are multiple files, but we might have a setup like: + # + # somedirectory/ + # srcdir/ + # objdir/ + # + # MOZCONFIG=../srcdir/some/path/to/mozconfig + # + # and be configuring from the objdir. So even though we + # have multiple existing files, they are actually the same + # file. + mozconfigs = [os.path.join(root, env_path) + for root in existing] + if not all(map(lambda p1, p2: filecmp.cmp(p1, p2, shallow=False), + mozconfigs[:-1], mozconfigs[1:])): + raise MozconfigFindException( + 'MOZCONFIG environment variable refers to a path that ' + + 'exists in more than one of ' + ', '.join(potential_roots) + + '. Remove all but one.') + elif not existing: + raise MozconfigFindException( + 'MOZCONFIG environment variable refers to a path that ' + + 'does not exist in any of ' + ', '.join(potential_roots)) + + env_path = os.path.join(existing[0], env_path) + elif not os.path.exists(env_path): # non-relative path + raise MozconfigFindException( + 'MOZCONFIG environment variable refers to a path that ' + 'does not exist: ' + env_path) + + if not os.path.isfile(env_path): + raise MozconfigFindException( + 'MOZCONFIG environment variable refers to a ' + 'non-file: ' + env_path) + + srcdir_paths = [os.path.join(topsrcdir, p) for p in + DEFAULT_TOPSRCDIR_PATHS] + existing = [p for p in srcdir_paths if os.path.isfile(p)] + + if env_path is None and len(existing) > 1: + raise MozconfigFindException('Multiple default mozconfig files ' + 'present. Remove all but one. ' + ', '.join(existing)) + + path = None + + if env_path is not None: + path = env_path + elif len(existing): + assert len(existing) == 1 + path = existing[0] + + if path is not None: + return os.path.abspath(path) + + deprecated_paths = [os.path.join(topsrcdir, s) for s in + DEPRECATED_TOPSRCDIR_PATHS] + + home = env.get('HOME', None) + if home is not None: + deprecated_paths.extend([os.path.join(home, s) for s in + DEPRECATED_HOME_PATHS]) + + for path in deprecated_paths: + if os.path.exists(path): + raise MozconfigFindException( + MOZCONFIG_LEGACY_PATH_ERROR % (path, topsrcdir)) + + return None diff --git a/python/mozboot/mozboot/mozillabuild.py b/python/mozboot/mozboot/mozillabuild.py index 29e95deb45b9..f9fcf5340365 100644 --- a/python/mozboot/mozboot/mozillabuild.py +++ b/python/mozboot/mozboot/mozillabuild.py @@ -92,12 +92,12 @@ class MozillaBuildBootstrapper(BaseBootstrapper): android.ensure_android('windows', artifact_mode=artifact_mode, no_interactive=self.no_interactive) - def suggest_mobile_android_mozconfig(self, artifact_mode=False): + def generate_mobile_android_mozconfig(self, artifact_mode=False): from mozboot import android - android.suggest_mozconfig('windows', artifact_mode=artifact_mode) + return android.generate_mozconfig('windows', artifact_mode=artifact_mode) - def suggest_mobile_android_artifact_mode_mozconfig(self): - self.suggest_mobile_android_mozconfig(artifact_mode=True) + def generate_mobile_android_artifact_mode_mozconfig(self): + return self.generate_mobile_android_mozconfig(artifact_mode=True) def ensure_clang_static_analysis_package(self, state_dir, checkout_root): from mozboot import static_analysis diff --git a/python/mozboot/mozboot/opensuse.py b/python/mozboot/mozboot/opensuse.py index f98454357072..7dcf5b02e010 100644 --- a/python/mozboot/mozboot/opensuse.py +++ b/python/mozboot/mozboot/opensuse.py @@ -111,12 +111,12 @@ class OpenSUSEBootstrapper( android.ensure_android('linux', artifact_mode=artifact_mode, no_interactive=self.no_interactive) - def suggest_mobile_android_mozconfig(self, artifact_mode=False): + def generate_mobile_android_mozconfig(self, artifact_mode=False): from mozboot import android - android.suggest_mozconfig('linux', artifact_mode=artifact_mode) + return android.generate_mozconfig('linux', artifact_mode=artifact_mode) - def suggest_mobile_android_artifact_mode_mozconfig(self): - self.suggest_mobile_android_mozconfig(artifact_mode=True) + def generate_mobile_android_artifact_mode_mozconfig(self): + return self.generate_mobile_android_mozconfig(artifact_mode=True) def _update_package_manager(self): self.zypper_update diff --git a/python/mozboot/mozboot/osx.py b/python/mozboot/mozboot/osx.py index bd6badf9124c..d013cdf8bcb9 100644 --- a/python/mozboot/mozboot/osx.py +++ b/python/mozboot/mozboot/osx.py @@ -204,12 +204,13 @@ class OSXBootstrapper(BaseBootstrapper): getattr(self, 'ensure_%s_mobile_android_packages' % self.package_manager)(artifact_mode=True) - def suggest_mobile_android_mozconfig(self): - getattr(self, 'suggest_%s_mobile_android_mozconfig' % self.package_manager)() + def generate_mobile_android_mozconfig(self): + return getattr(self, 'generate_%s_mobile_android_mozconfig' % + self.package_manager)() - def suggest_mobile_android_artifact_mode_mozconfig(self): - getattr(self, 'suggest_%s_mobile_android_mozconfig' % - self.package_manager)(artifact_mode=True) + def generate_mobile_android_artifact_mode_mozconfig(self): + return getattr(self, 'generate_%s_mobile_android_mozconfig' % + self.package_manager)(artifact_mode=True) def ensure_xcode(self): if self.os_version < StrictVersion('10.7'): @@ -405,9 +406,9 @@ class OSXBootstrapper(BaseBootstrapper): android.ensure_android('macosx', artifact_mode=artifact_mode, no_interactive=self.no_interactive) - def suggest_homebrew_mobile_android_mozconfig(self, artifact_mode=False): + def generate_homebrew_mobile_android_mozconfig(self, artifact_mode=False): from mozboot import android - android.suggest_mozconfig('macosx', artifact_mode=artifact_mode) + return android.generate_mozconfig('macosx', artifact_mode=artifact_mode) def _ensure_macports_packages(self, packages): self.port = self.which('port') @@ -482,9 +483,9 @@ class OSXBootstrapper(BaseBootstrapper): android.ensure_android('macosx', artifact_mode=artifact_mode, no_interactive=self.no_interactive) - def suggest_macports_mobile_android_mozconfig(self, artifact_mode=False): + def generate_macports_mobile_android_mozconfig(self, artifact_mode=False): from mozboot import android - android.suggest_mozconfig('macosx', artifact_mode=artifact_mode) + return android.generate_mozconfig('macosx', artifact_mode=artifact_mode) def ensure_package_manager(self): ''' diff --git a/python/mozboot/mozboot/solus.py b/python/mozboot/mozboot/solus.py index fc66a80c4828..de3f02883b8d 100644 --- a/python/mozboot/mozboot/solus.py +++ b/python/mozboot/mozboot/solus.py @@ -101,12 +101,12 @@ class SolusBootstrapper( android.ensure_android('linux', artifact_mode=artifact_mode, no_interactive=self.no_interactive) - def suggest_mobile_android_mozconfig(self, artifact_mode=False): + def generate_mobile_android_mozconfig(self, artifact_mode=False): from mozboot import android - android.suggest_mozconfig('linux', artifact_mode=artifact_mode) + return android.generate_mozconfig('linux', artifact_mode=artifact_mode) - def suggest_mobile_android_artifact_mode_mozconfig(self): - self.suggest_mobile_android_mozconfig(artifact_mode=True) + def generate_mobile_android_artifact_mode_mozconfig(self): + return self.generate_mobile_android_mozconfig(artifact_mode=True) def _update_package_manager(self): pass diff --git a/python/mozboot/mozboot/test/python.ini b/python/mozboot/mozboot/test/python.ini index ad6e3970e6cf..453fc397ef90 100644 --- a/python/mozboot/mozboot/test/python.ini +++ b/python/mozboot/mozboot/test/python.ini @@ -1,3 +1,4 @@ [DEFAULT] +[test_mozconfig.py] [test_write_config.py] diff --git a/python/mozboot/mozboot/test/test_mozconfig.py b/python/mozboot/mozboot/test/test_mozconfig.py new file mode 100644 index 000000000000..9949cd4b40f5 --- /dev/null +++ b/python/mozboot/mozboot/test/test_mozconfig.py @@ -0,0 +1,229 @@ +# 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 + +import os +import unittest + +from shutil import rmtree + +from tempfile import ( + gettempdir, + mkdtemp, +) + +from mozboot.mozconfig import ( + MozconfigFindException, + find_mozconfig, + DEFAULT_TOPSRCDIR_PATHS, + DEPRECATED_TOPSRCDIR_PATHS, + DEPRECATED_HOME_PATHS, +) +from mozunit import main + + +class TestFindMozconfig(unittest.TestCase): + def setUp(self): + self._old_env = dict(os.environ) + os.environ.pop('MOZCONFIG', None) + os.environ.pop('MOZ_OBJDIR', None) + os.environ.pop('CC', None) + os.environ.pop('CXX', None) + self._temp_dirs = set() + + def tearDown(self): + os.environ.clear() + os.environ.update(self._old_env) + + for d in self._temp_dirs: + rmtree(d) + + def get_temp_dir(self): + d = mkdtemp() + self._temp_dirs.add(d) + + return d + + def test_find_legacy_env(self): + """Ensure legacy mozconfig path definitions result in error.""" + + os.environ['MOZ_MYCONFIG'] = '/foo' + + with self.assertRaises(MozconfigFindException) as e: + find_mozconfig(self.get_temp_dir()) + + self.assertTrue(str(e.exception).startswith('The MOZ_MYCONFIG')) + + def test_find_multiple_configs(self): + """Ensure multiple relative-path MOZCONFIGs result in error.""" + relative_mozconfig = '.mconfig' + os.environ['MOZCONFIG'] = relative_mozconfig + + srcdir = self.get_temp_dir() + curdir = self.get_temp_dir() + dirs = [srcdir, curdir] + for d in dirs: + path = os.path.join(d, relative_mozconfig) + with open(path, 'w') as f: + f.write(path) + + orig_dir = os.getcwd() + try: + os.chdir(curdir) + with self.assertRaises(MozconfigFindException) as e: + find_mozconfig(srcdir) + finally: + os.chdir(orig_dir) + + self.assertIn('exists in more than one of', str(e.exception)) + for d in dirs: + self.assertIn(d, str(e.exception)) + + def test_find_multiple_but_identical_configs(self): + """Ensure multiple relative-path MOZCONFIGs pointing at the same file are OK.""" + relative_mozconfig = '../src/.mconfig' + os.environ['MOZCONFIG'] = relative_mozconfig + + topdir = self.get_temp_dir() + srcdir = os.path.join(topdir, 'src') + os.mkdir(srcdir) + curdir = os.path.join(topdir, 'obj') + os.mkdir(curdir) + + path = os.path.join(srcdir, relative_mozconfig) + with open(path, 'w'): + pass + + orig_dir = os.getcwd() + try: + os.chdir(curdir) + self.assertEqual(os.path.realpath(find_mozconfig(srcdir)), + os.path.realpath(path)) + finally: + os.chdir(orig_dir) + + def test_find_no_relative_configs(self): + """Ensure a missing relative-path MOZCONFIG is detected.""" + relative_mozconfig = '.mconfig' + os.environ['MOZCONFIG'] = relative_mozconfig + + srcdir = self.get_temp_dir() + curdir = self.get_temp_dir() + dirs = [srcdir, curdir] + + orig_dir = os.getcwd() + try: + os.chdir(curdir) + with self.assertRaises(MozconfigFindException) as e: + find_mozconfig(srcdir) + finally: + os.chdir(orig_dir) + + self.assertIn('does not exist in any of', str(e.exception)) + for d in dirs: + self.assertIn(d, str(e.exception)) + + def test_find_relative_mozconfig(self): + """Ensure a relative MOZCONFIG can be found in the srcdir.""" + relative_mozconfig = '.mconfig' + os.environ['MOZCONFIG'] = relative_mozconfig + + srcdir = self.get_temp_dir() + curdir = self.get_temp_dir() + + path = os.path.join(srcdir, relative_mozconfig) + with open(path, 'w'): + pass + + orig_dir = os.getcwd() + try: + os.chdir(curdir) + self.assertEqual(os.path.normpath(find_mozconfig(srcdir)), + os.path.normpath(path)) + finally: + os.chdir(orig_dir) + + def test_find_abs_path_not_exist(self): + """Ensure a missing absolute path is detected.""" + os.environ['MOZCONFIG'] = '/foo/bar/does/not/exist' + + with self.assertRaises(MozconfigFindException) as e: + find_mozconfig(self.get_temp_dir()) + + self.assertIn('path that does not exist', str(e.exception)) + self.assertTrue(str(e.exception).endswith('/foo/bar/does/not/exist')) + + def test_find_path_not_file(self): + """Ensure non-file paths are detected.""" + + os.environ['MOZCONFIG'] = gettempdir() + + with self.assertRaises(MozconfigFindException) as e: + find_mozconfig(self.get_temp_dir()) + + self.assertIn('refers to a non-file', str(e.exception)) + self.assertTrue(str(e.exception).endswith(gettempdir())) + + def test_find_default_files(self): + """Ensure default paths are used when present.""" + for p in DEFAULT_TOPSRCDIR_PATHS: + d = self.get_temp_dir() + path = os.path.join(d, p) + + with open(path, 'w'): + pass + + self.assertEqual(find_mozconfig(d), path) + + def test_find_multiple_defaults(self): + """Ensure we error when multiple default files are present.""" + self.assertGreater(len(DEFAULT_TOPSRCDIR_PATHS), 1) + + d = self.get_temp_dir() + for p in DEFAULT_TOPSRCDIR_PATHS: + with open(os.path.join(d, p), 'w'): + pass + + with self.assertRaises(MozconfigFindException) as e: + find_mozconfig(d) + + self.assertIn('Multiple default mozconfig files present', + str(e.exception)) + + def test_find_deprecated_path_srcdir(self): + """Ensure we error when deprecated path locations are present.""" + for p in DEPRECATED_TOPSRCDIR_PATHS: + d = self.get_temp_dir() + with open(os.path.join(d, p), 'w'): + pass + + with self.assertRaises(MozconfigFindException) as e: + find_mozconfig(d) + + self.assertIn('This implicit location is no longer', + str(e.exception)) + self.assertIn(d, str(e.exception)) + + def test_find_deprecated_home_paths(self): + """Ensure we error when deprecated home directory paths are present.""" + + for p in DEPRECATED_HOME_PATHS: + home = self.get_temp_dir() + os.environ['HOME'] = home + path = os.path.join(home, p) + + with open(path, 'w'): + pass + + with self.assertRaises(MozconfigFindException) as e: + find_mozconfig(self.get_temp_dir()) + + self.assertIn('This implicit location is no longer', + str(e.exception)) + self.assertIn(path, str(e.exception)) + + +if __name__ == '__main__': + main() diff --git a/python/mozboot/mozboot/void.py b/python/mozboot/mozboot/void.py index 55de00c75d4b..af6d18225955 100644 --- a/python/mozboot/mozboot/void.py +++ b/python/mozboot/mozboot/void.py @@ -117,12 +117,12 @@ class VoidBootstrapper( android.ensure_android('linux', artifact_mode=artifact_mode, no_interactive=self.no_interactive) - def suggest_mobile_android_mozconfig(self, artifact_mode=False): + def generate_mobile_android_mozconfig(self, artifact_mode=False): from mozboot import android - android.suggest_mozconfig('linux', artifact_mode=artifact_mode) + return android.generate_mozconfig('linux', artifact_mode=artifact_mode) - def suggest_mobile_android_artifact_mode_mozconfig(self): - self.suggest_mobile_android_mozconfig(artifact_mode=True) + def generate_mobile_android_artifact_mode_mozconfig(self): + return self.generate_mobile_android_mozconfig(artifact_mode=True) def _update_package_manager(self): self.xbps_update() diff --git a/python/mozbuild/mozbuild/base.py b/python/mozbuild/mozbuild/base.py index 59f5aae3769a..636db40482e1 100644 --- a/python/mozbuild/mozbuild/base.py +++ b/python/mozbuild/mozbuild/base.py @@ -16,6 +16,7 @@ import sys import errno from mach.mixin.process import ProcessExecutionMixin +from mozboot.mozconfig import MozconfigFindException from mozfile import which from mozversioncontrol import ( get_repository_from_build_config, @@ -33,7 +34,6 @@ from .backend.configenvironment import ( from .configure import ConfigureSandbox from .controller.clobber import Clobberer from .mozconfig import ( - MozconfigFindException, MozconfigLoadException, MozconfigLoader, ) diff --git a/python/mozbuild/mozbuild/mozconfig.py b/python/mozbuild/mozbuild/mozconfig.py index cbb969e8fc03..31081d86ac93 100644 --- a/python/mozbuild/mozbuild/mozconfig.py +++ b/python/mozbuild/mozbuild/mozconfig.py @@ -4,7 +4,6 @@ from __future__ import absolute_import, print_function, unicode_literals -import filecmp import os import re import six @@ -13,21 +12,10 @@ import subprocess import traceback from textwrap import dedent +from mozboot.mozconfig import find_mozconfig from mozpack import path as mozpath from mozbuild.util import ensure_subprocess_env -MOZ_MYCONFIG_ERROR = ''' -The MOZ_MYCONFIG environment variable to define the location of mozconfigs -is deprecated. If you wish to define the mozconfig path via an environment -variable, use MOZCONFIG instead. -'''.strip() - -MOZCONFIG_LEGACY_PATH = ''' -You currently have a mozconfig at %s. This implicit location is no longer -supported. Please move it to %s/.mozconfig or set an explicit path -via the $MOZCONFIG environment variable. -'''.strip() - MOZCONFIG_BAD_EXIT_CODE = ''' Evaluation of your mozconfig exited with an error. This could be triggered by a command inside your mozconfig failing. Please change your mozconfig @@ -42,10 +30,6 @@ errors in executed commands. '''.strip() -class MozconfigFindException(Exception): - """Raised when a mozconfig location is not defined properly.""" - - class MozconfigLoadException(Exception): """Raised when a mozconfig could not be loaded properly. @@ -84,12 +68,6 @@ class MozconfigLoader(object): (?P.*$)''', # Everything else (likely the value) re.VERBOSE) - # Default mozconfig files in the topsrcdir. - DEFAULT_TOPSRCDIR_PATHS = ('.mozconfig', 'mozconfig') - - DEPRECATED_TOPSRCDIR_PATHS = ('mozconfig.sh', 'myconfig.sh') - DEPRECATED_HOME_PATHS = ('.mozconfig', '.mozconfig.sh', '.mozmyconfig.sh') - IGNORE_SHELL_VARIABLES = {'_', 'BASH_ARGV', 'BASH_ARGV0', 'BASH_ARGC'} ENVIRONMENT_VARIABLES = { @@ -107,104 +85,6 @@ class MozconfigLoader(object): return os.path.join(our_dir, 'mozconfig_loader') - def find_mozconfig(self, env=os.environ): - """Find the active mozconfig file for the current environment. - - This emulates the logic in mozconfig-find. - - 1) If ENV[MOZCONFIG] is set, use that - 2) If $TOPSRCDIR/mozconfig or $TOPSRCDIR/.mozconfig exists, use it. - 3) If both exist or if there are legacy locations detected, error out. - - The absolute path to the found mozconfig will be returned on success. - None will be returned if no mozconfig could be found. A - MozconfigFindException will be raised if there is a bad state, - including conditions from #3 above. - """ - # Check for legacy methods first. - - if 'MOZ_MYCONFIG' in env: - raise MozconfigFindException(MOZ_MYCONFIG_ERROR) - - env_path = env.get('MOZCONFIG', None) or None - if env_path is not None: - if not os.path.isabs(env_path): - potential_roots = [self.topsrcdir, os.getcwd()] - # Attempt to eliminate duplicates for e.g. - # self.topsrcdir == os.curdir. - potential_roots = set(os.path.abspath(p) for p in potential_roots) - existing = [root for root in potential_roots - if os.path.exists(os.path.join(root, env_path))] - if len(existing) > 1: - # There are multiple files, but we might have a setup like: - # - # somedirectory/ - # srcdir/ - # objdir/ - # - # MOZCONFIG=../srcdir/some/path/to/mozconfig - # - # and be configuring from the objdir. So even though we - # have multiple existing files, they are actually the same - # file. - mozconfigs = [os.path.join(root, env_path) - for root in existing] - if not all(map(lambda p1, p2: filecmp.cmp(p1, p2, shallow=False), - mozconfigs[:-1], mozconfigs[1:])): - raise MozconfigFindException( - 'MOZCONFIG environment variable refers to a path that ' + - 'exists in more than one of ' + ', '.join(potential_roots) + - '. Remove all but one.') - elif not existing: - raise MozconfigFindException( - 'MOZCONFIG environment variable refers to a path that ' + - 'does not exist in any of ' + ', '.join(potential_roots)) - - env_path = os.path.join(existing[0], env_path) - elif not os.path.exists(env_path): # non-relative path - raise MozconfigFindException( - 'MOZCONFIG environment variable refers to a path that ' - 'does not exist: ' + env_path) - - if not os.path.isfile(env_path): - raise MozconfigFindException( - 'MOZCONFIG environment variable refers to a ' - 'non-file: ' + env_path) - - srcdir_paths = [os.path.join(self.topsrcdir, p) for p in - self.DEFAULT_TOPSRCDIR_PATHS] - existing = [p for p in srcdir_paths if os.path.isfile(p)] - - if env_path is None and len(existing) > 1: - raise MozconfigFindException('Multiple default mozconfig files ' - 'present. Remove all but one. ' + ', '.join(existing)) - - path = None - - if env_path is not None: - path = env_path - elif len(existing): - assert len(existing) == 1 - path = existing[0] - - if path is not None: - return os.path.abspath(path) - - deprecated_paths = [os.path.join(self.topsrcdir, s) for s in - self.DEPRECATED_TOPSRCDIR_PATHS] - - home = env.get('HOME', None) - if home is not None: - deprecated_paths.extend([os.path.join(home, s) for s in - self.DEPRECATED_HOME_PATHS]) - - for path in deprecated_paths: - if os.path.exists(path): - raise MozconfigFindException( - MOZCONFIG_LEGACY_PATH % (path, self.topsrcdir)) - - return None - def read_mozconfig(self, path=None): """Read the contents of a mozconfig into a data structure. @@ -218,7 +98,7 @@ class MozconfigLoader(object): static data structure. """ if path is self.AUTODETECT: - path = self.find_mozconfig() + path = find_mozconfig(self.topsrcdir) result = { 'path': path, diff --git a/python/mozbuild/mozbuild/test/test_mozconfig.py b/python/mozbuild/mozbuild/test/test_mozconfig.py index 00c5b585249b..ca05777ff80c 100644 --- a/python/mozbuild/mozbuild/test/test_mozconfig.py +++ b/python/mozbuild/mozbuild/test/test_mozconfig.py @@ -9,17 +9,12 @@ import unittest from shutil import rmtree -from tempfile import ( - gettempdir, - mkdtemp, -) - +from tempfile import mkdtemp from mozfile.mozfile import NamedTemporaryFile from mozunit import main from mozbuild.mozconfig import ( - MozconfigFindException, MozconfigLoadException, MozconfigLoader, ) @@ -50,188 +45,6 @@ class TestMozconfigLoader(unittest.TestCase): return d - def test_find_legacy_env(self): - """Ensure legacy mozconfig path definitions result in error.""" - - os.environ['MOZ_MYCONFIG'] = '/foo' - - with self.assertRaises(MozconfigFindException) as e: - self.get_loader().find_mozconfig() - - self.assertTrue(str(e.exception).startswith('The MOZ_MYCONFIG')) - - def test_find_multiple_configs(self): - """Ensure multiple relative-path MOZCONFIGs result in error.""" - relative_mozconfig = '.mconfig' - os.environ['MOZCONFIG'] = relative_mozconfig - - srcdir = self.get_temp_dir() - curdir = self.get_temp_dir() - dirs = [srcdir, curdir] - loader = MozconfigLoader(srcdir) - for d in dirs: - path = os.path.join(d, relative_mozconfig) - with open(path, 'w') as f: - f.write(path) - - orig_dir = os.getcwd() - try: - os.chdir(curdir) - with self.assertRaises(MozconfigFindException) as e: - loader.find_mozconfig() - finally: - os.chdir(orig_dir) - - self.assertIn('exists in more than one of', str(e.exception)) - for d in dirs: - self.assertIn(d, str(e.exception)) - - def test_find_multiple_but_identical_configs(self): - """Ensure multiple relative-path MOZCONFIGs pointing at the same file are OK.""" - relative_mozconfig = '../src/.mconfig' - os.environ['MOZCONFIG'] = relative_mozconfig - - topdir = self.get_temp_dir() - srcdir = os.path.join(topdir, 'src') - os.mkdir(srcdir) - curdir = os.path.join(topdir, 'obj') - os.mkdir(curdir) - - loader = MozconfigLoader(srcdir) - path = os.path.join(srcdir, relative_mozconfig) - with open(path, 'w'): - pass - - orig_dir = os.getcwd() - try: - os.chdir(curdir) - self.assertEqual(os.path.realpath(loader.find_mozconfig()), - os.path.realpath(path)) - finally: - os.chdir(orig_dir) - - def test_find_no_relative_configs(self): - """Ensure a missing relative-path MOZCONFIG is detected.""" - relative_mozconfig = '.mconfig' - os.environ['MOZCONFIG'] = relative_mozconfig - - srcdir = self.get_temp_dir() - curdir = self.get_temp_dir() - dirs = [srcdir, curdir] - loader = MozconfigLoader(srcdir) - - orig_dir = os.getcwd() - try: - os.chdir(curdir) - with self.assertRaises(MozconfigFindException) as e: - loader.find_mozconfig() - finally: - os.chdir(orig_dir) - - self.assertIn('does not exist in any of', str(e.exception)) - for d in dirs: - self.assertIn(d, str(e.exception)) - - def test_find_relative_mozconfig(self): - """Ensure a relative MOZCONFIG can be found in the srcdir.""" - relative_mozconfig = '.mconfig' - os.environ['MOZCONFIG'] = relative_mozconfig - - srcdir = self.get_temp_dir() - curdir = self.get_temp_dir() - loader = MozconfigLoader(srcdir) - - path = os.path.join(srcdir, relative_mozconfig) - with open(path, 'w'): - pass - - orig_dir = os.getcwd() - try: - os.chdir(curdir) - self.assertEqual(os.path.normpath(loader.find_mozconfig()), - os.path.normpath(path)) - finally: - os.chdir(orig_dir) - - def test_find_abs_path_not_exist(self): - """Ensure a missing absolute path is detected.""" - os.environ['MOZCONFIG'] = '/foo/bar/does/not/exist' - - with self.assertRaises(MozconfigFindException) as e: - self.get_loader().find_mozconfig() - - self.assertIn('path that does not exist', str(e.exception)) - self.assertTrue(str(e.exception).endswith('/foo/bar/does/not/exist')) - - def test_find_path_not_file(self): - """Ensure non-file paths are detected.""" - - os.environ['MOZCONFIG'] = gettempdir() - - with self.assertRaises(MozconfigFindException) as e: - self.get_loader().find_mozconfig() - - self.assertIn('refers to a non-file', str(e.exception)) - self.assertTrue(str(e.exception).endswith(gettempdir())) - - def test_find_default_files(self): - """Ensure default paths are used when present.""" - for p in MozconfigLoader.DEFAULT_TOPSRCDIR_PATHS: - d = self.get_temp_dir() - path = os.path.join(d, p) - - with open(path, 'w'): - pass - - self.assertEqual(MozconfigLoader(d).find_mozconfig(), path) - - def test_find_multiple_defaults(self): - """Ensure we error when multiple default files are present.""" - self.assertGreater(len(MozconfigLoader.DEFAULT_TOPSRCDIR_PATHS), 1) - - d = self.get_temp_dir() - for p in MozconfigLoader.DEFAULT_TOPSRCDIR_PATHS: - with open(os.path.join(d, p), 'w'): - pass - - with self.assertRaises(MozconfigFindException) as e: - MozconfigLoader(d).find_mozconfig() - - self.assertIn('Multiple default mozconfig files present', - str(e.exception)) - - def test_find_deprecated_path_srcdir(self): - """Ensure we error when deprecated path locations are present.""" - for p in MozconfigLoader.DEPRECATED_TOPSRCDIR_PATHS: - d = self.get_temp_dir() - with open(os.path.join(d, p), 'w'): - pass - - with self.assertRaises(MozconfigFindException) as e: - MozconfigLoader(d).find_mozconfig() - - self.assertIn('This implicit location is no longer', - str(e.exception)) - self.assertIn(d, str(e.exception)) - - def test_find_deprecated_home_paths(self): - """Ensure we error when deprecated home directory paths are present.""" - - for p in MozconfigLoader.DEPRECATED_HOME_PATHS: - home = self.get_temp_dir() - os.environ['HOME'] = home - path = os.path.join(home, p) - - with open(path, 'w'): - pass - - with self.assertRaises(MozconfigFindException) as e: - self.get_loader().find_mozconfig() - - self.assertIn('This implicit location is no longer', - str(e.exception)) - self.assertIn(path, str(e.exception)) - def test_read_no_mozconfig(self): # This is basically to ensure changes to defaults incur a test failure. result = self.get_loader().read_mozconfig() diff --git a/testing/mozbase/mozinfo/mozinfo/mozinfo.py b/testing/mozbase/mozinfo/mozinfo/mozinfo.py index d901151471e3..314fcc23ca66 100755 --- a/testing/mozbase/mozinfo/mozinfo/mozinfo.py +++ b/testing/mozbase/mozinfo/mozinfo/mozinfo.py @@ -247,7 +247,7 @@ def find_and_update_from_json(*dirs, **kwargs): # First, see if we're in an objdir try: from mozbuild.base import MozbuildObject, BuildEnvironmentNotFoundException - from mozbuild.mozconfig import MozconfigFindException + from mozboot.mozconfig import MozconfigFindException build = MozbuildObject.from_environment() json_path = _os.path.join(build.topobjdir, "mozinfo.json") if _os.path.isfile(json_path):