diff --git a/.gitignore b/.gitignore index 4cfc0f4..c7571c1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.swp */*.swp .vscode/ +__pycache__/ releases/* testing/stubs/local.* build diff --git a/docs/conf.py b/docs/conf.py index 8255c46..748dc6a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -38,6 +38,15 @@ extlinks = { # https://documatt.com/sphinx-reredirects/usage.html # the target should be relative to ensure it works on RTD +# this is a fallback in case the redirects in the RTD settings are lost or no longer work +# RTD redirects should be: +# - Type: page redirect +# - From URL: /old/absolute/path/to/page.html +# - To URL: /new/absolute/path/to/page.html +# - HTTP status code: 301 Permanent +# - Force redirect: yes +# - Enabled: yes +# use manage-redirects.py to copy the config here to RTD redirects = { # source : target "guides/binary-releases": "../../general/binary-releases.html", @@ -90,5 +99,9 @@ man_pages = [ ('man/zfsbootmenu.7', 'zfsbootmenu', 'System Integration', man_author, '7'), ] -if tags.has('manpages'): - exclude_patterns += ['guides/**'] +try: + # tags is set by sphinx when interpreting the config + if tags.has('manpages'): + exclude_patterns += ['guides/**'] +except NameError: + ... diff --git a/docs/manage-redirects.py b/docs/manage-redirects.py new file mode 100644 index 0000000..318066d --- /dev/null +++ b/docs/manage-redirects.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +# Usage: RTD_TOKEN="..." python3 manage-redirects.py +# simple IaC-ish script to set redirects in readthedocs's config +# requires an api token from https://readthedocs.org/accounts/tokens/ + +from os import environ + +import requests + +from conf import redirects + + +SLUG = "zfsbootmenu" + +URL = f"https://readthedocs.org/api/v3/projects/{SLUG}/redirects/" +HEADERS = {"Authorization": f"Token {environ.get('RTD_TOKEN')}"} + + +def transform_redirects(redir: dict[str, str]) -> dict[str, str]: + """transform the redirect dictionary from the reredirects format to what rtd.org will want""" + return { k+".html": "/"+v.lstrip("../") for k, v in redir.items() } + + +if __name__ == "__main__": + # get the existing redirects + existing = [] + req_url = URL + while req_url is not None: + resp = requests.get(req_url, headers=HEADERS) + resp.raise_for_status() + existing += resp.json().get("results", []) + req_url = resp.json().get("next") + + # and delete them all + for redir in existing: + if (rid := redir.get('pk')) is not None: + print(f"=> Deleting redirect {rid}: {redir.get('from_url')} -> {redir.get('to_url')}") + resp = requests.delete(URL+f"{rid}/", headers=HEADERS) + resp.raise_for_status() + + # replace them with the redirects defined in conf.py + for old, new in transform_redirects(redirects).items(): + print(f"=> Creating redirect: {old} -> {new}") + resp = requests.post(URL, headers=HEADERS, data={ + "from_url": old, "to_url": new, "type": "page", "http_status": 301, "force": True, "enabled": True, + }) + resp.raise_for_status()