# 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 os import re import subprocess import sys import traceback from pathlib import Path from textwrap import dedent
from mozboot.mozconfig import find_mozconfig from mozpack import path as mozpath
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
to not error and/or to catch errors in executed commands. """.strip()
MOZCONFIG_BAD_OUTPUT = """
Evaluation of your mozconfig produced unexpected output. This could be
triggered by a command inside your mozconfig failing or producing some warnings or error messages. Please change your mozconfig to not error and/or to catch
errors in executed commands. """.strip()
class MozconfigLoadException(Exception): """Raised when a mozconfig could not be loaded properly.
This typically indicates a malformed or misbehaving mozconfig file. """
def read_mozconfig(self, path=None): """Read the contents of a mozconfig into a data structure.
This takes the path to a mozconfig to load. If the given path is
AUTODETECT, will try to find a mozconfig from the environment using
find_mozconfig().
mozconfig files are shell scripts. So, we can't just parse them.
Instead, we run the shell script in a wrapper which allows us to record
state from execution. Thus, the output from a mozconfig is a friendly
static data structure. """ if path is self.AUTODETECT:
path = find_mozconfig(self.topsrcdir) if isinstance(path, Path):
path = str(path)
# Since mozconfig_loader is a shell script, running it "normally" # actually leads to two shell executions on Windows. Avoid this by # directly calling sh mozconfig_loader.
shell = "sh"
env = dict(os.environ)
env["PYTHONIOENCODING"] = "utf-8"
try: # We need to capture stderr because that's where the shell sends # errors if execution fails.
output = subprocess.check_output(
command,
stderr=subprocess.STDOUT,
cwd=self.topsrcdir,
env=env,
universal_newlines=True,
encoding="utf-8",
)
except subprocess.CalledProcessError as e:
lines = e.output.splitlines()
# Output before actual execution shouldn't be relevant. try:
index = lines.index("------END_BEFORE_SOURCE")
lines = lines[index + 1 :] except ValueError: pass
try:
parsed = self._parse_loader_output(output) except AssertionError: # _parse_loader_output uses assertions to verify the # well-formedness of the shell output; when these fail, it # generally means there was a problem with the output, but we # include the assertion traceback just to be sure.
print("Assertion failed in _parse_loader_output:")
traceback.print_exc() raise MozconfigLoadException(
path, MOZCONFIG_BAD_OUTPUT, output.splitlines()
)
for key in added:
changed["added"][key] = vars_after[key]
for key in removed:
changed["removed"][key] = vars_before[key]
for key in maybe_modified: if vars_before[key] != vars_after[key]:
changed["modified"][key] = (vars_before[key], vars_after[key]) elif key in self.ENVIRONMENT_VARIABLES: # In order for irrelevant environment variable changes not # to incur in re-running configure, only a set of # environment variables are stored when they are # unmodified. Otherwise, changes such as using a different # terminal window, or even rebooting, would trigger # reconfigures.
changed["unmodified"][key] = vars_after[key]
# Environment variables also appear as shell variables, but that's # uninteresting duplication of information. Filter them out. def filt(x, y): return {k: v for k, v in x.items() if k notin y}
for o in mk:
match = self.RE_MAKE_VARIABLE.match(o)
if match isNone:
result["make_extra"].append(o) continue
name, value = match.group("var"), match.group("value")
if name == "MOZ_MAKE_FLAGS":
result["make_flags"] = value.split() continue
if name == "MOZ_OBJDIR":
result["topobjdir"] = value if parsed["env_before"].get("MOZ_PROFILE_GENERATE") == "1": # If MOZ_OBJDIR is specified in the mozconfig, we need to # make sure that the '/instrumented' directory gets appended # for the first build to avoid an objdir mismatch when # running 'mach package' on Windows.
result["topobjdir"] = mozpath.join(
result["topobjdir"], "instrumented"
) continue
if current_type in vars_mapping: # mozconfigs are sourced using the Bourne shell (or at least # in Bourne shell mode). This means |set| simply lists # variables from the current shell (not functions). (Note that # if Bash is installed in /bin/sh it acts like regular Bourne # and doesn't print functions.) So, lines should have the # form: # # key='value' # key=value # # The only complication is multi-line variables. Those have the # form: # # key='first # second'
# TODO Bug 818377 Properly handle multi-line variables of form: # $ foo="a='b' # c='d'" # $ set # foo='a='"'"'b'"'"' # c='"'"'d'"'"
name = in_variable
value = None if in_variable: # Reached the end of a multi-line variable. if line.endswith("'") andnot line.endswith("\\'"):
current.append(line[:-1])
value = "\n".join(current)
in_variable = None else:
current.append(line) continue else:
equal_pos = line.find("=")
if equal_pos < 1: # TODO log warning? continue
name = line[0:equal_pos]
value = line[equal_pos + 1 :]
if len(value):
has_quote = value[0] == "'"
if has_quote:
value = value[1:]
# Lines with a quote not ending in a quote are multi-line. if has_quote andnot value.endswith("'"):
in_variable = name
current.append(value) continue else:
value = value[:-1] if has_quote else value
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.