#!/usr/bin/env python3 # # This file defines is used in doc/conf.py to setup the version information for # the documentation: # - get_current_version() used in doc/conf.py computes the current version by # trying to guess the approximate versions we're at using git tags and # branches from the repository. # - write_switchers_js() write the switchers.js file used for switching between # versions of the documentation. # # Copyright (c) 2026 Antonin Godard # # SPDX-License-Identifier: MIT # import argparse import itertools import json import os import re import subprocess import sys import textwrap from urllib.request import urlopen, URLError # NOTE: the following variables contain default values in case we are not able to fetch # the releases.json file from https://dashboard.yoctoproject.org/releases.json DEVBRANCH = "2.18" LTSSERIES = ["2.8", "2.0"] ACTIVERELEASES = ["2.16"] + LTSSERIES YOCTO_MAPPING = { "2.18": "wrynose", "2.16": "whinlatter", "2.8": "scarthgap", "2.0": "kirkstone", } RELEASES_FROM_JSON = {} # Use the local releases.json file if found, fetch it from the dashboard otherwise releases_json_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "releases.json") try: with open(releases_json_path, "r") as f: RELEASES_FROM_JSON = json.load(f) except FileNotFoundError: print("Fetching releases.json from https://dashboard.yoctoproject.org/releases.json...", file=sys.stderr) try: with urlopen("https://dashboard.yoctoproject.org/releases.json") as r, \ open(releases_json_path, "w") as f: RELEASES_FROM_JSON = json.load(r) json.dump(RELEASES_FROM_JSON, f) except URLError: print("WARNING: tried to fetch https://dashboard.yoctoproject.org/releases.json " "but failed, using default values for active releases", file=sys.stderr) pass if RELEASES_FROM_JSON: ACTIVERELEASES = [] DEVBRANCH = "" LTSSERIES = [] YOCTO_MAPPING = {} for release in RELEASES_FROM_JSON: bb_ver = release["bitbake_version"] if release["status"] == "Active Development": DEVBRANCH = bb_ver if "LTS until" in release["status"]: LTSSERIES.append(bb_ver) if release["bitbake_version"]: YOCTO_MAPPING[bb_ver] = release["release_codename"] # Find the first non-dev release, which should be displayed as the default # page on the docs website. current_branch = "" for release in RELEASES_FROM_JSON: if release["status"] != "Active Development": current_branch = release["bitbake_version"] break if not current_branch: sys.exit("Unable to find a current release! Exiting...") # make the list of releases unique, there can be duplication when the # current releases is also an LTS ACTIVERELEASES = list(dict.fromkeys([current_branch] + LTSSERIES)) print(f"ACTIVERELEASES calculated to be {ACTIVERELEASES}", file=sys.stderr) print(f"DEVBRANCH calculated to be {DEVBRANCH}", file=sys.stderr) print(f"LTSSERIES calculated to be {LTSSERIES}", file=sys.stderr) BB_RELEASE_TAG_RE = re.compile(r"^[0-9]+\.[0-9]+\.[0-9]+$") def main(): parser = argparse.ArgumentParser( description="Parse https://dashboard.yoctoproject.org/releases.json to get current releases information" ) parser.add_argument("--get-latest-branch", help="Print current latest branch and exit", action="store_true", default=False) args = parser.parse_args() if args.get_latest_branch: print(ACTIVERELEASES[0]) sys.exit(0) def get_current_version(): # Test tags exist and inform the user to fetch if not try: subprocess.run(["git", "show", f"{LTSSERIES[-1]}.0"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True) except subprocess.CalledProcessError: sys.exit("Please run 'git fetch --tags' before building the documentation") # Try and figure out what we are tags = subprocess.run(["git", "tag", "--points-at", "HEAD"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True).stdout for t in tags.split(): if re.match(BB_RELEASE_TAG_RE, t): return t # We're floating on a branch branch = subprocess.run(["git", "branch", "--show-current"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True).stdout.strip() if branch == "" or branch not in list(YOCTO_MAPPING.keys()) + ["master", "master-next"]: # We're not on a known release branch so we have to guess. Compare the # numbers of commits from each release branch and assume the smallest # number of commits is the one we're based off possible_branch = None branch_count = 0 for b in itertools.chain(YOCTO_MAPPING.keys(), ["master"]): result = subprocess.run(["git", "log", "--format=oneline", "HEAD..origin/" + b], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) if result.returncode == 0: count = result.stdout.count('\n') if not possible_branch or count < branch_count: print("Branch %s has count %s" % (b, count)) possible_branch = b branch_count = count if possible_branch: branch = possible_branch else: branch = "master" print("Nearest release branch estimated to be %s" % branch) if branch == "master": return "dev" if branch == "master-next": return "next" ourversion = branch head_commit = subprocess.run(["git", "rev-parse", "--short", "HEAD"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True).stdout.strip() branch_commit = subprocess.run(["git", "rev-parse", "--short", branch], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True).stdout.strip() if head_commit != branch_commit: ourversion += f" ({head_commit})" return ourversion def write_switchers_js(js_in, js_out, current_version): with open(js_in, "r") as r, open(js_out, "w") as w: lines = r.readlines() for line in lines: if "VERSIONS_PLACEHOLDER" in line: if current_version != "dev": w.write(" 'dev': 'Unstable (dev)',\n") for series in ACTIVERELEASES: w.write(f" '{series}': '{series} ({YOCTO_MAPPING[series]})',\n") else: w.write(line) print("switchers.js generated from switchers.js.in") def _release_section(series_version: str, codename: str, bitbake_version: str) -> str: """ Helper function to generate a release section, as: ******************** Release Series xxxxx ******************** - """ section_length = len(series_version) + len(codename) + 18 return textwrap.dedent( f"""\ {'*' * section_length} Release Series {series_version} ({codename}) {'*' * section_length} - :yocto_docs:`BitBake {bitbake_version} User Manual ` """) def write_releases_rst(releases_rst_out: str): """ Generates the releases.rst file automatically, based on what is found in the releases.json file. """ with open(releases_rst_out, "w") as f: f.write(textwrap.dedent("""\ .. SPDX-License-Identifier: CC-BY-2.5 ================================= BitBake Supported Release Manuals ================================= """)) for release in RELEASES_FROM_JSON: if release["status"] == "Active Development": continue if not release["bitbake_version"]: continue if release["series"] == "current": f.write(_release_section( release["series_version"], release["release_codename"], release["bitbake_version"])) f.write(textwrap.dedent("""\ ================================ BitBake Outdated Release Manuals ================================ """)) for release in RELEASES_FROM_JSON: if not release["series"] == "previous": continue if not release["bitbake_version"]: continue f.write(_release_section( release["series_version"], release["release_codename"], release["bitbake_version"])) # old legacy links, which cannot be auto-generated f.write(textwrap.dedent( """\ - :yocto_docs:`3.1.2 BitBake User Manual ` - :yocto_docs:`3.1 BitBake User Manual ` - :yocto_docs:`3.1.1 BitBake User Manual ` - :yocto_docs:`3.1.3 BitBake User Manual ` ************************* Release Series 3.0 (Zeus) ************************* - :yocto_docs:`3.0 BitBake User Manual ` - :yocto_docs:`3.0.1 BitBake User Manual ` - :yocto_docs:`3.0.2 BitBake User Manual ` - :yocto_docs:`3.0.3 BitBake User Manual ` - :yocto_docs:`3.0.4 BitBake User Manual ` **************************** Release Series 2.7 (Warrior) **************************** - :yocto_docs:`2.7 BitBake User Manual ` - :yocto_docs:`2.7.1 BitBake User Manual ` - :yocto_docs:`2.7.2 BitBake User Manual ` - :yocto_docs:`2.7.3 BitBake User Manual ` - :yocto_docs:`2.7.4 BitBake User Manual ` ************************* Release Series 2.6 (Thud) ************************* - :yocto_docs:`2.6 BitBake User Manual ` - :yocto_docs:`2.6.1 BitBake User Manual ` - :yocto_docs:`2.6.2 BitBake User Manual ` - :yocto_docs:`2.6.3 BitBake User Manual ` - :yocto_docs:`2.6.4 BitBake User Manual ` ************************* Release Series 2.5 (Sumo) ************************* - :yocto_docs:`2.5 Documentation ` - :yocto_docs:`2.5.1 Documentation ` - :yocto_docs:`2.5.2 Documentation ` - :yocto_docs:`2.5.3 Documentation ` ************************** Release Series 2.4 (Rocko) ************************** - :yocto_docs:`2.4 BitBake User Manual ` - :yocto_docs:`2.4.1 BitBake User Manual ` - :yocto_docs:`2.4.2 BitBake User Manual ` - :yocto_docs:`2.4.3 BitBake User Manual ` - :yocto_docs:`2.4.4 BitBake User Manual ` ************************* Release Series 2.3 (Pyro) ************************* - :yocto_docs:`2.3 BitBake User Manual ` - :yocto_docs:`2.3.1 BitBake User Manual ` - :yocto_docs:`2.3.2 BitBake User Manual ` - :yocto_docs:`2.3.3 BitBake User Manual ` - :yocto_docs:`2.3.4 BitBake User Manual ` ************************** Release Series 2.2 (Morty) ************************** - :yocto_docs:`2.2 BitBake User Manual ` - :yocto_docs:`2.2.1 BitBake User Manual ` - :yocto_docs:`2.2.2 BitBake User Manual ` - :yocto_docs:`2.2.3 BitBake User Manual ` **************************** Release Series 2.1 (Krogoth) **************************** - :yocto_docs:`2.1 BitBake User Manual ` - :yocto_docs:`2.1.1 BitBake User Manual ` - :yocto_docs:`2.1.2 BitBake User Manual ` - :yocto_docs:`2.1.3 BitBake User Manual ` *************************** Release Series 2.0 (Jethro) *************************** - :yocto_docs:`1.9 BitBake User Manual ` - :yocto_docs:`2.0 BitBake User Manual ` - :yocto_docs:`2.0.1 BitBake User Manual ` - :yocto_docs:`2.0.2 BitBake User Manual ` - :yocto_docs:`2.0.3 BitBake User Manual ` ************************* Release Series 1.8 (Fido) ************************* - :yocto_docs:`1.8 BitBake User Manual ` - :yocto_docs:`1.8.1 BitBake User Manual ` - :yocto_docs:`1.8.2 BitBake User Manual ` ************************** Release Series 1.7 (Dizzy) ************************** - :yocto_docs:`1.7 BitBake User Manual ` - :yocto_docs:`1.7.1 BitBake User Manual ` - :yocto_docs:`1.7.2 BitBake User Manual ` - :yocto_docs:`1.7.3 BitBake User Manual ` ************************** Release Series 1.6 (Daisy) ************************** - :yocto_docs:`1.6 BitBake User Manual ` - :yocto_docs:`1.6.1 BitBake User Manual ` - :yocto_docs:`1.6.2 BitBake User Manual ` - :yocto_docs:`1.6.3 BitBake User Manual ` """)) if __name__ == "__main__": main()