tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

compare-mozconfigs.py (5711B)


      1 #!/usr/bin/python
      2 # This Source Code Form is subject to the terms of the Mozilla Public
      3 # License, v. 2.0. If a copy of the MPL was not distributed with this
      4 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
      5 
      6 # originally from https://hg.mozilla.org/build/tools/file/4ab9c1a4e05b/scripts/release/compare-mozconfigs.py  # NOQA: E501
      7 
      8 import difflib
      9 import logging
     10 import os
     11 import unittest
     12 
     13 import mozunit
     14 
     15 here = os.path.abspath(os.path.dirname(__file__))
     16 
     17 FAILURE_CODE = 1
     18 SUCCESS_CODE = 0
     19 
     20 PLATFORMS = (
     21    "linux64",
     22    "macosx64",
     23    "win32",
     24    "win64",
     25    "win64-aarch64",
     26 )
     27 
     28 log = logging.getLogger(__name__)
     29 
     30 
     31 class ConfigError(Exception):
     32    pass
     33 
     34 
     35 def readConfig(configfile):
     36    c = {}
     37    with open(configfile) as config:
     38        exec(config.read(), c)
     39    return c["allowlist"]
     40 
     41 
     42 def verify_mozconfigs(
     43    mozconfig_pair, nightly_mozconfig_pair, platform, mozconfigAllowlist
     44 ):
     45    """Compares mozconfig to nightly_mozconfig and compare to an optional
     46    allowlist of known differences. mozconfig_pair and nightly_mozconfig_pair
     47    are pairs containing the mozconfig's identifier and the list of lines in
     48    the mozconfig."""
     49 
     50    # unpack the pairs to get the names, the names are just for
     51    # identifying the mozconfigs when logging the error messages
     52    mozconfig_name, mozconfig_lines = mozconfig_pair
     53    nightly_mozconfig_name, nightly_mozconfig_lines = nightly_mozconfig_pair
     54 
     55    if not mozconfig_lines or not nightly_mozconfig_lines:
     56        log.info("Missing mozconfigs to compare for %s" % platform)
     57        return False
     58 
     59    success = True
     60 
     61    diff_instance = difflib.Differ()
     62    diff_result = diff_instance.compare(mozconfig_lines, nightly_mozconfig_lines)
     63    diff_list = list(diff_result)
     64 
     65    for line in diff_list:
     66        clean_line = line[1:].strip()
     67        if (line[0] == "-" or line[0] == "+") and len(clean_line) > 1:
     68            # skip comment lines
     69            if clean_line.startswith("#"):
     70                continue
     71            # compare to allowlist
     72            message = ""
     73            if line[0] == "-":
     74                # handle lines that move around in diff
     75                if "+" + line[1:] in diff_list:
     76                    continue
     77                if platform in mozconfigAllowlist.get("release", {}):
     78                    if clean_line in mozconfigAllowlist["release"][platform]:
     79                        continue
     80            elif line[0] == "+":
     81                if "-" + line[1:] in diff_list:
     82                    continue
     83                if platform in mozconfigAllowlist.get("nightly", {}):
     84                    if clean_line in mozconfigAllowlist["nightly"][platform]:
     85                        continue
     86                    else:
     87                        log.warning(
     88                            "%s not in %s %s!"
     89                            % (
     90                                clean_line,
     91                                platform,
     92                                mozconfigAllowlist["nightly"][platform],
     93                            )
     94                        )
     95            else:
     96                log.error("Skipping line %s!" % line)
     97                continue
     98            message = "found in %s but not in %s: %s"
     99            if line[0] == "-":
    100                log.error(
    101                    message % (mozconfig_name, nightly_mozconfig_name, clean_line)
    102                )
    103            else:
    104                log.error(
    105                    message % (nightly_mozconfig_name, mozconfig_name, clean_line)
    106                )
    107            success = False
    108    return success
    109 
    110 
    111 def get_mozconfig(path):
    112    """Consumes a path and returns a list of lines from the mozconfig file."""
    113    with open(path) as fh:
    114        return fh.readlines()
    115 
    116 
    117 def compare(topsrcdir):
    118    app = os.path.join(topsrcdir, "browser")
    119    allowlist = readConfig(os.path.join(app, "config", "mozconfigs", "allowlist"))
    120 
    121    success = True
    122 
    123    def normalize_lines(lines):
    124        return {l.strip() for l in lines}
    125 
    126    for platform in PLATFORMS:
    127        log.info("Comparing platform %s" % platform)
    128 
    129        mozconfigs_path = os.path.join(app, "config", "mozconfigs", platform)
    130 
    131        nightly_path = os.path.join(mozconfigs_path, "nightly")
    132        beta_path = os.path.join(mozconfigs_path, "beta")
    133        release_path = os.path.join(mozconfigs_path, "release")
    134 
    135        nightly_lines = get_mozconfig(nightly_path)
    136        beta_lines = get_mozconfig(beta_path)
    137        release_lines = get_mozconfig(release_path)
    138 
    139        # Validate that entries in allowlist['nightly'][platform] are actually
    140        # present.
    141        allowlist_normalized = normalize_lines(allowlist["nightly"].get(platform, []))
    142        nightly_normalized = normalize_lines(nightly_lines)
    143 
    144        for line in sorted(allowlist_normalized - nightly_normalized):
    145            log.error("extra line in nightly allowlist: %s" % line)
    146            success = False
    147 
    148        log.info("Comparing beta and nightly mozconfigs")
    149        passed = verify_mozconfigs(
    150            (beta_path, beta_lines), (nightly_path, nightly_lines), platform, allowlist
    151        )
    152 
    153        if not passed:
    154            success = False
    155 
    156        log.info("Comparing release and nightly mozconfigs")
    157        passed = verify_mozconfigs(
    158            (release_path, release_lines),
    159            (nightly_path, nightly_lines),
    160            platform,
    161            allowlist,
    162        )
    163        if not passed:
    164            success = False
    165 
    166    return success
    167 
    168 
    169 class TestCompareMozconfigs(unittest.TestCase):
    170    def test_compare_mozconfigs(self):
    171        topsrcdir = os.path.abspath(os.path.join(here, "..", ".."))
    172        self.assertTrue(compare(topsrcdir))
    173 
    174 
    175 if __name__ == "__main__":
    176    logging.basicConfig(level=logging.INFO)
    177    mozunit.main()