#!/usr/bin/env python3 import glob import os import re import sys import yaml def get_all_pages(): return [file for file in glob.glob("gdb/*.md") if not file.endswith("/index.md")] def fix_web_path(page): return '/' + page[:-3] def parse_page_data(page): with open(page) as fd: return next(yaml.safe_load_all(fd)) def most_appropriate_title(data): return data.get("linkTitle") or data['title'] def traverse_siblings(pages, start, sibling='next'): page = start while page in pages: yield page page = pages[page]['siblings'].get(sibling) def create_intro_toc(pages, start, offset=2, file=sys.stdout): for num, page in enumerate(traverse_siblings(pages, start)): data = pages[page] title = most_appropriate_title(data) print(f"{num + offset}. [{title}]({page})\n", file=file) def overwrite_info_toc(pages, start, offset=2): old_name = "gdb/index.md" new_name = "gdb/.index.new" with open(old_name) as orig: with open(new_name, 'w') as new: found = False for line in orig: if found and '</div' in line: found = False create_intro_toc(pages, start, offset=offset, file=new) if not found and f'{offset}. [' in line: found = True if not found: new.write(line) os.rename(new_name, old_name) def create_navbar(pages, start, file=sys.stdout): longest_link = max(map(len, traverse_siblings(pages, start))) + 2 for page in traverse_siblings(pages, start): data = pages[page] title = most_appropriate_title(data) linksq = f"'{page}'" linkdq = f'"{page}"' print(f' <a href={linkdq:{longest_link}s} class="{{{{#is meta.url {linksq:{longest_link}s}}}}}active {{{{/is}}}}dropdown-item">{title}</a>', file=file) def overwrite_navbar(pages, start): old_name = "_gdb-menu.hbs" new_name = ".gdb-menu.new" with open(old_name) as orig: with open(new_name, 'w') as new: found = False for line in orig: if found and '</div' in line: found = False create_navbar(pages, start, file=new) if not found: new.write(line) if '="/gdb/"' in line: found = True os.rename(new_name, old_name) def check_nav_consistency(pages): for page in pages: siblings = pages[page]['siblings'] for sibling in 'prev', 'next': sibling_data = pages.get(siblings.get(sibling)) if sibling_data: sibling_title = most_appropriate_title(sibling_data) link_title = siblings[sibling + 'Caption'] if sibling_title != link_title: print(f"{page}: caption mismatch for {sibling}: expected {sibling_title!r}, got {link_title!r}") def overwrite_nav_meta(pages): for page in pages: siblings = pages[page]['siblings'] old_name = page.lstrip("/") + '.md' new_name = ".new.md" with open(old_name) as orig: with open(new_name, "w") as new: for line in orig: match = None for sibling in 'prev', 'next': sibling_data = pages.get(siblings.get(sibling)) if sibling_data: sibling_title = most_appropriate_title(sibling_data) match = re.match(f"( *{sibling}Caption: *).*", line) if match: new.write(match.group(1) + sibling_title + "\n") break if not match: new.write(line) os.rename(new_name, old_name) def check_excluded_pages(pages, first): missing = set(pages.keys()) - set(traverse_siblings(pages, first)) if missing: print(f"Unlinked pages (starting from {first}): {missing}") def main(): os.chdir("../public") pages = {fix_web_path(file): parse_page_data(file) for file in get_all_pages()} *_, first = traverse_siblings(pages, next(iter(pages)), sibling="prev") check_excluded_pages(pages, first) if '--write' in sys.argv: overwrite_info_toc(pages, first) overwrite_navbar(pages, first) overwrite_nav_meta(pages) else: create_intro_toc(pages, first) create_navbar(pages, first) check_nav_consistency(pages) if __name__ == '__main__': main()