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
This commit is contained in:
Mitchell Hentges 2020-06-08 19:36:56 +00:00
parent a5ea1d83c5
commit ed90a04ad1
22 changed files with 460 additions and 384 deletions

View File

@ -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

View File

@ -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

View File

@ -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 (

View File

@ -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

View File

@ -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

View File

@ -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):

View File

@ -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):

View File

@ -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:

View File

@ -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()

View File

@ -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'])

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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):
'''

View File

@ -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

View File

@ -1,3 +1,4 @@
[DEFAULT]
[test_mozconfig.py]
[test_write_config.py]

View File

@ -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()

View File

@ -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()

View File

@ -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,
)

View File

@ -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<value>.*$)''', # 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,

View File

@ -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()

View File

@ -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):