summaryrefslogtreecommitdiffstats
path: root/python/mozboot/mozboot/mozconfig.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/mozboot/mozboot/mozconfig.py')
-rw-r--r--python/mozboot/mozboot/mozconfig.py156
1 files changed, 156 insertions, 0 deletions
diff --git a/python/mozboot/mozboot/mozconfig.py b/python/mozboot/mozboot/mozconfig.py
new file mode 100644
index 0000000000..a1ae4c8523
--- /dev/null
+++ b/python/mozboot/mozboot/mozconfig.py
@@ -0,0 +1,156 @@
+# 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