Source code for swh.docs.generate_software_origins_list
# Copyright (C) 2023 The Software Heritage developers
# See the AUTHORS file at the top-level directory of this distribution
# License: GNU General Public License version 3, or any later version
# See top-level LICENSE file for more information
"""Reads :file:`docs/devel/software-origins-support.yml` and generates ReST documents
with tables summarizing the status of loaders ands listers."""
from pathlib import Path
import sys
import textwrap
import tabulate
from .software_origins import parse
PRELUDE = """
.. This file was generated by swh/docs/generate_software_origins_list.py
.. using {source_yml}
.. rst-class:: swh-logos-table
.. table::
  :align: center
"""
[docs]
def write_table(data, file) -> None:
    links = []
    headers = (
        "Software origins",
        "Related links",
        "Current status",
        "Related `grants <https://www.softwareheritage.org/grants/>`_",
    )
    table = []
    for forge_id, forge in sorted(data["forges"].items()):
        logo_cell = (
            f"|{forge_id}_logo|\n\n:ref:`{forge['name']} "
            f"<user-software-origins-{forge_id}>`"
        )
        links.append((f"{forge_id}-loader-source", forge.loader.source))
        links.append((f"{forge_id}-lister-source", forge.lister.source))
        has_loader = forge["loader"]["status"] != "N/A"
        has_lister = forge["lister"]["status"] != "N/A"
        if forge.status == "dev":
            status_cell = "In\N{NBSP}development\n\n"
        elif forge.status in ("staging", "prod"):
            links.append((f"{forge_id}-origins", forge.origins))
            links.append((f"{forge_id}-coverage", forge.coverage))
            if forge.status == "staging":
                status_cell = "In\N{NBSP}staging\n\n"
            else:
                status_cell = "In\N{NBSP}production\n\n"
            if has_loader:
                status_cell += f"`Browse\N{NBSP}origins <{forge_id}-origins_>`__\n\n"
            if has_lister:
                status_cell += f"`See\N{NBSP}coverage <{forge_id}-coverage_>`__\n\n"
        else:
            assert False, f"Unexpected status {forge.status!r} for {forge_id}"
        links_cell = ""
        if has_loader:
            links_cell += (
                f"* `Loader Source Code <{forge_id}-loader-source_>`__\n"
                f"* :mod:`Loader Developer documentation <{forge.loader.package_name}>`"
                f"\n"
            )
        if has_lister:
            links_cell += (
                f"* `Lister Source Code <{forge_id}-lister-source_>`__\n"
                f"* :mod:`Lister Developer documentation <{forge.lister.package_name}>`"
                f"\n"
            )
        loader_issue = forge["loader"].get("issue")
        lister_issue = forge["lister"].get("issue")
        if loader_issue and lister_issue:
            if loader_issue == lister_issue:
                status_cell += f"`Tracking issue <{loader_issue}>`__\n\n"
            else:
                status_cell += (
                    f"`Tracking loader issue <{loader_issue}>`__\n\n"
                    f"`Tracking lister issue <{lister_issue}>`__\n\n"
                )
        elif not loader_issue and not lister_issue:
            pass
        elif lister_issue:
            if has_loader:
                status_cell += f"`Lister Tracking issue <{lister_issue}>`__\n\n"
            else:
                status_cell += f"`Tracking issue <{lister_issue}>`__\n\n"
        elif loader_issue:
            if has_loader:
                status_cell += f"`Loader Tracking issue <{loader_issue}>`__\n\n"
            else:
                status_cell += f"`Tracking issue <{loader_issue}>`__\n\n"
        else:
            assert False, f"The impossible happened for {forge_id}"
        notes = forge.get("notes")
        if notes:
            status_cell = f"{status_cell}\n\n{notes}"
        grant_id = forge.get("grant")
        grant = data["grants"][grant_id] if grant_id else None
        developer_id = forge.get("developer")
        if grant:
            assert developer_id, f"{forge_id} has grant but no developer"
            developer = data["developers"][developer_id]
            grant_cell = (
                f"|{grant_id}|_\n\n"
                f"(awarded to `{developer['name']} <{developer['url']}>`__)"
            )
        else:
            assert not developer_id, f"{forge_id} has developer but no grant"
            grant_cell = ""
        table.append((logo_cell, links_cell, status_cell, grant_cell))
    file.write(
        textwrap.indent(
            tabulate.tabulate(table, headers=headers, tablefmt="grid"),
            prefix="  ",
        )
        + "\n\n"
    )
    for link_name, link_url in links:
        file.write(f".. _{link_name}: {link_url}\n")
    file.write("\n") 
[docs]
def write_toctree(data, file) -> None:
    file.write(".. toctree::\n" "  :maxdepth: 2\n" "  :hidden:\n" "\n")
    for forge_id, forge in sorted(data["forges"].items()):
        file.write(f"  {forge_id}\n")
    file.write("\n") 
[docs]
def write_logos(data, file) -> None:
    for forge_id, forge in sorted(data["forges"].items()):
        file.write(
            f".. |{forge_id}_logo| image:: ../logos/{forge_id}.png\n"
            f"  :target: {forge_id}.html\n"
            f"  :alt: {forge['name']}\n"
            f"\n"
        ) 
[docs]
def write_grants(data, file) -> None:
    for grant_id, grant in data["grants"].items():
        file.write(
            f".. |{grant_id}| replace:: {grant['funder']}\n"
            f".. _{grant_id}: {grant['announcement']}\n"
            f"\n"
        ) 
[docs]
def main(input_path: Path, output_path: Path) -> None:
    data = parse(input_path)
    with output_path.open("wt") as output_file:
        output_file.write(PRELUDE.format(source_yml=input_path))
        write_table(data, output_file)
        write_toctree(data, output_file)
        write_logos(data, output_file)
        write_grants(data, output_file) 
if __name__ == "__main__":
    try:
        (_, input_path, output_path) = sys.argv
    except ValueError:
        print(
            f"Syntax: {sys.argv[0]} docs/devel/forge-support.yml "
            f"docs/user/software-origins/dynamic/table.inc",
            sys.stderr,
        )
        exit(1)
    main(Path(input_path), Path(output_path))