#!/usr/bin/env python3 # 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 re import sys from subprocess import check_output def exit_with_failure(message): print(f"ERROR: {message}", file=sys.stderr) sys.exit(1) def version_string_to_underscore(version_string): """Convert version string like '3.118' to '3_118'.""" return version_string.replace(".", "_") def version_string_to_RTM_tag(version_string): """Convert version string like '3.118' to 'NSS_3_118_RTM'.""" parts = version_string.split(".") return "NSS_" + "_".join(parts) + "_RTM" def get_nspr_version(rev=None): """Read the NSPR version from automation/release/nspr-version.txt. If rev is given, reads the file at that hg revision; otherwise reads the working-directory copy. """ nspr_version_file = "automation/release/nspr-version.txt" if rev is not None: try: content = check_output(["hg", "cat", "-r", rev, nspr_version_file]).decode() return content.splitlines()[0].strip() except Exception as e: exit_with_failure( f"Could not read {nspr_version_file} at revision {rev}: {e}" ) try: with open(nspr_version_file, "r") as f: return f.readline().strip() except FileNotFoundError: exit_with_failure( f"Could not find {nspr_version_file}. Are you running from the NSS root directory?" ) def get_rtm_tag_date(rtm_tag): """Return the date of the RTM tag as a formatted string, or None if tag doesn't exist.""" try: raw = ( check_output(["hg", "log", "-r", rtm_tag, "--template", "{date|shortdate}"]) .decode() .strip() ) from datetime import datetime dt = datetime.strptime(raw, "%Y-%m-%d") return dt.strftime("%-d %B %Y") except Exception: return None def tag_exists(tag): """Return True if the given Mercurial tag resolves in the current repo.""" try: check_output(["hg", "log", "-r", tag, "--template", "x"]) return True except Exception: return False def default_branch_has_version(major, minor): """Return True if lib/nss/nss.h on the default branch tip has NSS_VMAJOR/VMINOR set to major.minor.""" try: content = check_output(["hg", "cat", "-r", "default", "lib/nss/nss.h"]).decode() return re.search( rf"#define\s+NSS_VMAJOR\s+{re.escape(major)}\b", content ) and re.search(rf"#define\s+NSS_VMINOR\s+{re.escape(minor)}\b", content) except Exception: return False def node_set(revset): """Return the set of short hashes matching revset.""" try: result = ( check_output(["hg", "log", "-r", revset, "--template", "{node|short}\\n"]) .decode() .strip() ) except Exception: return set() return set(result.split()) if result else set() def graft_sources_on_branch(branch): """Return short hashes of default-branch commits grafted onto branch. These are the source= values recorded by hg graft, truncated to 12 chars to match the {node|short} format used elsewhere. """ try: extras = check_output( ["hg", "log", "-r", f"::'{branch}'", "--template", "{extras}\\n"] ).decode() except Exception: return set() return {h[:12] for h in re.findall(r"(?