Source code for swh.docs.generate_lister_loader_lists

# 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 docs/devel/forge-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 typing_extensions import Literal

from .software_origins import parse

LISTERS_PRELUDE = """
.. This file was generated by swh/docs/generate_forge_list.py using {source_yml}

.. rst-class:: swh-logos-table

.. table::
  :align: center

"""


LOADERS_PRELUDE = """
.. This file was generated by swh/docs/generate_forge_list.py using {source_yml}

.. rst-class:: swh-logos-table

.. table::
  :align: center

"""


[docs] def write_table(data, lister_or_loader: Literal["lister", "loader"], file) -> None: links = [] headers = ( f"{lister_or_loader.capitalize()} name", "Related links", "Current status", "Related `grants <https://www.softwareheritage.org/grants/>`_", ) table = [] for forge_id, forge in sorted(data["forges"].items()): package_name = forge[lister_or_loader].package_name links.append( ( f"{forge_id}-source", forge[lister_or_loader].source, ) ) logo_cell = f"|{forge_id}_logo|\n\n:ref:`user-software-origins-{forge_id}`" if forge_id in ("cran", "gnu"): # FIXME: swh-web coverage should have them lowercased, like everything else id_in_swh_web_coverage = forge_id.upper() else: id_in_swh_web_coverage = forge_id status = forge[lister_or_loader].status if status == "N/A": # No lister or loader for this forge, skipping continue elif status == "dev": status_cell = "In development" links_cell = ( f"* `Source Code <{forge_id}-source_>`__\n" f"* :mod:`Developer documentation <{package_name}>`" ) elif status == "staging": status_cell = "In staging" if lister_or_loader == "loader": links.append( ( f"{forge_id}-origins", "https://webapp.staging.swh.network/browse/search/" f"?with_visit=true&with_content=true&visit_type={forge_id}", ) ) links_cell = ( f"* `Source Code <{forge_id}-source_>`__\n" f"* :mod:`Developer documentation <{package_name}>`\n" f"* `Browse origins <{forge_id}-origins_>`__" ) else: links.append( ( f"{forge_id}-coverage", "https://webapp.staging.swh.network/coverage/" f"?focus={id_in_swh_web_coverage}#{id_in_swh_web_coverage}", ) ) links_cell = ( f"* `Source Code <{forge_id}-source_>`__\n" f"* :mod:`Developer documentation <{package_name}>`\n" f"* `See coverage <{forge_id}-coverage_>`__" ) elif status == "prod": status_cell = "In production" if lister_or_loader == "loader": links.append( ( f"{forge_id}-origins", f"https://archive.softwareheritage.org/browse/search/" f"?with_visit=true&with_content=true&visit_type={forge_id}", ) ) links_cell = ( f"* `Source Code <{forge_id}-source_>`__\n" f"* :mod:`Developer documentation <{package_name}>`\n" f"* `Browse origins <{forge_id}-origins_>`__" ) else: links.append( ( f"{forge_id}-coverage", f"https://archive.softwareheritage.org/coverage/" f"?focus={id_in_swh_web_coverage}#{id_in_swh_web_coverage}", ) ) links_cell = ( f"* `Source Code <{forge_id}-source_>`__\n" f"* :mod:`Developer documentation <{package_name}>`\n" f"* `See coverage <{forge_id}-coverage_>`__" ) else: assert False, f"Unexpected status {status!r} for {forge_id}" issue = forge[lister_or_loader].get("issue") if issue: links_cell += f"\n* `Tracking issue <{forge[lister_or_loader].issue}>`__" 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_logos(data, lister_or_loader: Literal["lister", "loader"], file) -> None: for forge_id, forge in sorted(data["forges"].items()): if forge[lister_or_loader]["status"] != "N/A": file.write( f".. |{forge_id}_logo| image:: logos/{forge_id}.png\n" f" :width: 50%\n" f" :target: software-origins/{forge_id}.html\n" f" :alt: {forge.name} {lister_or_loader}\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, lister_output_path: Path, loader_output_path: Path) -> None: data = parse(input_path) with ( lister_output_path.open("wt") as listers_file, loader_output_path.open("wt") as loaders_file, ): listers_file.write(LISTERS_PRELUDE.format(source_yml=input_path)) loaders_file.write(LOADERS_PRELUDE.format(source_yml=input_path)) write_table(data, "lister", listers_file) write_table(data, "loader", loaders_file) write_logos(data, "lister", listers_file) write_logos(data, "loader", loaders_file) write_grants(data, listers_file) write_grants(data, loaders_file)
if __name__ == "__main__": try: (_, input_path, lister_output_path, loader_output_path) = sys.argv except ValueError: print( f"Syntax: {sys.argv[0]} docs/devel/forge-support.yml " f"docs/user/software-origins/dynamic/lister_table.inc " f"docs/user/software-origins/dynamic/loader_table.inc", sys.stderr, ) exit(1) main(Path(input_path), Path(lister_output_path), Path(loader_output_path))