Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/security/nss/automation/release/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 9 kB image not shown  

Quelle  release_utils.py

  Sprache: Python
 

#!/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[:12for h in re.findall(r"(?<![a-z_])source=([0-9a-f]+)", extras)}


def find_beta_bump_commit(upper, prev_branch, major, minor):
    """Find the commit that first set lib/nss/nss.h to version {major}.{minor} Beta.

    Only searches commits reachable from upper but not from prev_branch, so it
    returns quickly when no beta bump was made.

    Returns the short hash of the commit, or None if not found.
    """
    try:
        cmd = [
            "hg",
            "log",
            "-r",
            f"filelog('lib/nss/nss.h') and ::'{upper}' and not ::'{prev_branch}'",
            "--template",
            "{node|short}\\n",
        ]
        result = check_output(cmd).decode().strip()
    except Exception as e:
        exit_with_failure(f"Failed to get nss.h history: {e}")

    if not result:
        return None

    commits = [c for c in result.split("\n"if c]  # hg log output is newest first

    # Search from oldest to newest to find the first commit showing this version as beta
    for commit in reversed(commits):
        try:
            content = check_output(
                ["hg""cat""-r", commit, "lib/nss/nss.h"]
            ).decode()
        except Exception:
            continue
        if (
            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)
            and re.search(r"#define\s+NSS_BETA\s+PR_TRUE", content)
        ):
            return commit

    return None


def extract_bug_ids(bug_lines):
    """Extract integer bug IDs from formatted 'Bug N - description.' lines."""
    seen = set()
    ids = []
    for line in bug_lines:
        m = re.match(r"Bug\s+(\d+)", line, re.IGNORECASE)
        if m:
            bid = int(m.group(1))
            if bid not in seen:
                seen.add(bid)
                ids.append(bid)
    return ids


def get_bug_list_for_version(version):
    """Extract bug changes from Mercurial log for the given release version.

    For point releases (a.b.c), uses the previous RTM tag (NSS_A_B_RTM for
    3.x.1, NSS_A_B_{C-1}_RTM for later point releases) as the base.

    For regular releases (a.b), finds the commit that bumped lib/nss/nss.h to
    version a.b Beta and collects all commits after it on the release branch.
    Falls back to comparing with NSS_A_(B-1)_BRANCH if no beta bump is found.
    """
    parts = version.split(".")
    if len(parts) < 2:
        exit_with_failure(f"Invalid version format: {version}")

    major, minor = parts[0], parts[1]
    branch_name = f"NSS_{major}_{minor}_BRANCH"

    rtm_tag = version_string_to_RTM_tag(version)
    if tag_exists(rtm_tag):
        upper = rtm_tag
    elif tag_exists(branch_name):
        upper = branch_name
    elif default_branch_has_version(major, minor):
        print(f"Branch {branch_name} not yet created; using default branch.")
        upper = "default"
    else:
        exit_with_failure(
            f"Cannot find branch {branch_name} and default does not contain NSS {version}."
        )

    if len(parts) == 3:
        patch = int(parts[2])
        prev_version = (
            f"{major}.{minor}" if patch == 1 else f"{major}.{minor}.{patch - 1}"
        )
        prev_tag = version_string_to_RTM_tag(prev_version)
        print(f"Point release: collecting commits after {prev_tag} on {upper}.")
        revset = f"descendants('{prev_tag}') and ::'{upper}' and not '{prev_tag}'"
        grafted_away = set()
    else:
        prev_branch = f"NSS_{major}_{int(minor) - 1}_BRANCH"
        revset = f"::'{upper}' and not ::'{prev_branch}'"

        beta_bump = find_beta_bump_commit(upper, prev_branch, major, minor)
        if beta_bump:
            print(f"Found {version} beta version bump at {beta_bump}.")
            # Commits before the beta bump may have been grafted to the previous
            # branch for a point release; those belong to the previous version.
            grafted_to_prev = graft_sources_on_branch(prev_branch)
            pre_bump_nodes = node_set(
                f"::'{beta_bump}' and not ::'{prev_branch}' and not '{beta_bump}'"
            )
            grafted_away = pre_bump_nodes & grafted_to_prev
        else:
            print(f"Warning: No {version} beta version bump found in lib/nss/nss.h.")
            grafted_away = set()

    try:
        command = [
            "hg",
            "log",
            "-r",
            revset,
            "--template",
            "{node|short}\\t{desc|firstline}\\n",
        ]
        log_output = check_output(command).decode("utf-8")
    except Exception as e:
        exit_with_failure(f"Failed to get hg log: {e}")

    commits = []
    for line in log_output.split("\n"):
        if "\t" in line:
            node, title = line.split("\t"1)
            commits.append((node.strip(), title.strip()))

    # Collect hashes that were backed out within this range
    backed_out = set()
    for _node, title in commits:
        m = re.search(r"\bBacked out changeset ([0-9a-f]+)\b", title, re.IGNORECASE)
        if m:
            backed_out.add(m.group(1))

    bug_lines = []
    for node, title in commits:
        if node in backed_out:
            continue  # this commit was backed out; skip it
        if re.search(r"\bBacked out changeset\b", title, re.IGNORECASE):
            continue  # this is a backout commit; skip it
        if node in grafted_away:
            continue  # pre-bump commit grafted to previous branch; belongs to previous version

        if not re.match(r"bug\s+\d+", title, re.IGNORECASE):
            continue

        line = title
        # Remove reviewer info from tail: r=, r?, or r! (with optional leading comma)
        line = re.sub(r",?\s+r[=?!]\S+$""", line).strip()

        # Normalize "Bug N:" to "Bug N -"
        line = re.sub(r"(Bug\s+\d+):", r"\1 -", line, flags=re.IGNORECASE)

        # Ensure "Bug N - description" format (add dash if missing)
        line = re.sub(r"(Bug\s+\d+)\s+([^-])", r"\1 - \2", line, flags=re.IGNORECASE)

        line = line.rstrip(",").strip()

        if line and not line.endswith("."):
            line = line + "."

        if line and line not in bug_lines:
            bug_lines.append(line)

    return list(reversed(bug_lines))

Messung V0.5 in Prozent
C=94 H=86 G=89

¤ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet am  2026-08-26) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

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 und die Messung sind noch experimentell.