# 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/.
import filecmp
import os
from pathlib
import Path
from typing
import Union
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."""
class MozconfigBuilder(object):
def __init__(self):
self._lines = []
def append(self, block):
self._lines.extend([line.strip()
for line
in block.split(
"\n")
if line.strip()])
def generate(self):
return "".join(line +
"\n" for line
in self._lines)
def find_mozconfig(topsrcdir: Union[str, Path], 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.
"""
topsrcdir = Path(topsrcdir)
# 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:
env_path = Path(env_path)
if env_path
is not None:
if not env_path.is_absolute():
potential_roots = [topsrcdir, Path.cwd()]
# Attempt to eliminate duplicates for e.g.
# self.topsrcdir == Path.cwd().
potential_roots_strings = set(str(p.resolve())
for p
in potential_roots)
existing = [
root
for root
in potential_roots_strings
if (Path(root) / env_path).exists()
]
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 = [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_strings)
+
". 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_strings)
)
env_path = existing[0] / env_path
elif not env_path.exists():
# non-relative path
raise MozconfigFindException(
"MOZCONFIG environment variable refers to a path that "
f
"does not exist: {env_path}"
)
if not env_path.is_file():
raise MozconfigFindException(
"MOZCONFIG environment variable refers to a " f
"non-file: {env_path}"
)
srcdir_paths = [topsrcdir / p
for p
in DEFAULT_TOPSRCDIR_PATHS]
existing = [p
for p
in srcdir_paths
if p.is_file()]
if env_path
is None and len(existing) > 1:
raise MozconfigFindException(
"Multiple default mozconfig files "
"present. Remove all but one. " +
", ".join(str(p)
for p
in 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 Path.cwd() / path
deprecated_paths = [topsrcdir / s
for s
in DEPRECATED_TOPSRCDIR_PATHS]
home = env.get(
"HOME",
None)
if home
is not None:
home = Path(home)
deprecated_paths.extend([home / s
for s
in DEPRECATED_HOME_PATHS])
for path
in deprecated_paths:
if path.exists():
raise MozconfigFindException(
MOZCONFIG_LEGACY_PATH_ERROR % (path, topsrcdir)
)
return None