Re: git: 46c495e6e8db - main - Tools/scripts/repology-get-maintainer-stats.py: add convenience script
- Reply: Yuri : "Re: git: 46c495e6e8db - main - Tools/scripts/repology-get-maintainer-stats.py: add convenience script"
- In reply to: Yuri Victorovich : "git: 46c495e6e8db - main - Tools/scripts/repology-get-maintainer-stats.py: add convenience script"
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 26 Sep 2026 06:06:58 UTC
Yuri Victorovich wrote:
> The branch main has been updated by yuri:
>
> URL: https://cgit.FreeBSD.org/ports/commit/?id=46c495e6e8dbbba2854a30dac5335c747fe9bdbf
>
> commit 46c495e6e8dbbba2854a30dac5335c747fe9bdbf
> Author: Yuri Victorovich <yuri@FreeBSD.org>
> AuthorDate: 2026-09-25 22:35:18 +0000
> Commit: Yuri Victorovich <yuri@FreeBSD.org>
> CommitDate: 2026-09-25 23:50:05 +0000
>
> Tools/scripts/repology-get-maintainer-stats.py: add convenience script
>
> It retrieves and displays aggregate statistics from Repology, same
> that is displayed on the web site.
> ---
> Tools/scripts/repology-get-maintainer-stats.py | 202 +++++++++++++++++++++++++
> 1 file changed, 202 insertions(+)
>
> diff --git a/Tools/scripts/repology-get-maintainer-stats.py b/Tools/scripts/repology-get-maintainer-stats.py
> new file mode 100755
> index 000000000000..9a59a428f750
> --- /dev/null
> +++ b/Tools/scripts/repology-get-maintainer-stats.py
> @@ -0,0 +1,202 @@
> +#!/usr/bin/env python3
> +#
> +# repology-get-maintainer-stats.py - print aggregate FreeBSD ports maintainer
> +# statistics as reported by repology.org.
> +#
> +# MAINTAINER= yuri@FreeBSD.org
> +#
> +
> +import argparse
> +import getpass
> +import importlib.util
> +import re
> +import sys
> +from urllib.parse import quote
> +
> +REPOLOGY_MAINTAINER_URL = "https://repology.org/maintainer/{maintainer}"
> +USER_AGENT = (
> + "repology-get-maintainer-stats.py "
> + "(FreeBSD ports tools; https://www.freebsd.org/ports/)"
> +)
> +
> +
> +def check_dependencies() -> None:
> + """Verify that all non-stdlib dependencies are available."""
> + missing = []
> + for module, package in (("requests", "requests"), ("bs4", "beautifulsoup4")):
> + if importlib.util.find_spec(module) is None:
> + missing.append(package)
> + if missing:
> + print(
> + "Error: missing required package(s): " + ", ".join(missing),
> + file=sys.stderr,
> + )
> + print(
> + "Install with: sudo pkg install " + " ".join(missing),
> + file=sys.stderr,
This needs a Python package prefix for the command to be correct.
> + )
> + sys.exit(1)
> +
> +
> +def parse_args() -> argparse.Namespace:
> + parser = argparse.ArgumentParser(
> + description="Print FreeBSD ports maintainer statistics from repology.org."
> + )
> + parser.add_argument(
> + "maintainer",
> + nargs="?",
> + default=f"{getpass.getuser()}@FreeBSD.org",
> + help="maintainer e-mail address (default: %(default)s)",
> + )
> + args = parser.parse_args()
> + if len(sys.argv) > 2:
> + parser.error("at most one maintainer argument is allowed")
> + return args
> +
> +
> +def fetch_maintainer_page(maintainer: str) -> str:
> + import requests
> +
> + url = REPOLOGY_MAINTAINER_URL.format(maintainer=quote(maintainer, safe="@"))
> + try:
> + response = requests.get(url, headers={"User-Agent": USER_AGENT}, timeout=30)
> + except requests.RequestException as exc:
> + print(f"Error fetching {url}: {exc}", file=sys.stderr)
> + sys.exit(1)
> + if response.status_code == 404:
> + print(
> + f"Error: maintainer '{maintainer}' was not found on repology.org.",
> + file=sys.stderr,
> + )
> + sys.exit(1)
> + response.raise_for_status()
> + return response.text
> +
> +
> +def _cell_text(cell) -> str:
> + """Return stripped text from a BeautifulSoup table cell."""
> + return " ".join(cell.stripped_strings)
> +
> +
> +def extract_freebsd_stats(html: str) -> dict[str, str]:
> + """Parse the repology maintainer page and return FreeBSD Ports aggregate stats."""
> + from bs4 import BeautifulSoup
> +
> + soup = BeautifulSoup(html, "html.parser")
> +
What is the reason to parse HTML instead of using API as documented on
https://repology.org/api/v1?