GeezerVisonThe World Wide Web, restored to 800 pixels of glory. |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites |
GeezerVison is showing github.com — SimpleLauncher/scripts/sync-wiki.py at master · purelogiccode/SimpleLauncher Expand file tree/ Copy pathsync-wiki.pyMore file actions 241 lines (199 loc) · 9.1 KB / Copy pathsync-wiki.pyFile metadata and controls241 lines (199 loc) · 9.1 KB 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 #!/usr/bin/env python3 """Sync the SimpleLauncher docs folder to the GitHub wiki. The GitHub wiki is a separate git repository (SimpleLauncher.wiki.git). The default GITHUB_TOKEN cannot push to it, so this script is run locally (or in CI with a PAT). Mappings applied: docs/README.md -> Home.md docs/NN-*.md (01..18) -> same filename (wiki page name = filename without .md) docs/parameters.md -> parameters.md (PROTECTED: the app opens this page, https://github.com/purelogiccode/SimpleLauncher/wiki/parameters) docs/manual-tests.md -> manual-tests.md skipped: docs/index.html, docs/_sidebar.md, docs/.nojekyll, DocsPlan.md Link rewriting for the wiki: markdown links to published pages drop the ".md" extension (GitHub wiki resolves plain page names); links to https:// URLs pass through unchanged. Stale wiki pages are deleted, except the protected parameters.md page. Usage: python scripts/sync-wiki.py # full sync: clone/pull, rewrite, commit, push python scripts/sync-wiki.py --dry-run # show the plan without changing anything python scripts/sync-wiki.py --wiki-dir <dir> [--repo-dir <dir>] """ from __future__ import annotations import argparse import os import shutil import subprocess import sys import tempfile WIKI_REPO_URL = "https://github.com/purelogiccode/SimpleLauncher.wiki.git" # Files in the wiki that are never deleted, even if not in the publish set. PROTECTED_WIKI_FILES = {"parameters.md"} # Docs-folder files that are not published to the wiki. WIKI_EXCLUDED = {"index.html", "_sidebar.md", ".nojekyll", "DocsPlan.md"} def run_git(cwd: str, *args: str, check: bool = True) -> subprocess.CompletedProcess[str]: """Run a git command in the given directory.""" result = subprocess.run( ["git", "-C", cwd, *args], capture_output=True, text=True, encoding="utf-8", errors="replace", ) if check and result.returncode != 0: raise RuntimeError(f"git {' '.join(args)} failed: {result.stderr.strip()}") return result def ensure_wiki_clone(wiki_dir: str) -> str: """Clone (or reset) the wiki repository into wiki_dir.""" git_dir = os.path.join(wiki_dir, ".git") if os.path.isdir(git_dir): run_git(wiki_dir, "fetch", "origin") run_git(wiki_dir, "reset", "--hard", "origin/master") else: os.makedirs(wiki_dir, exist_ok=True) run_git(wiki_dir, "clone", WIKI_REPO_URL, ".", check=False) if not os.path.isdir(git_dir): raise RuntimeError( f"Could not clone {WIKI_REPO_URL}. Check network access and that the wiki is enabled." ) return wiki_dir def build_page_map(repo_dir: str) -> dict[str, str]: """Return {wiki_filename: source_file_path} for everything to publish.""" docs_dir = os.path.join(repo_dir, "docs") pages: dict[str, str] = {} readme = os.path.join(docs_dir, "README.md") if os.path.isfile(readme): pages["Home.md"] = readme for name in sorted(os.listdir(docs_dir)): if name in WIKI_EXCLUDED or not name.endswith(".md"): continue if name == "README.md": continue pages[name] = os.path.join(docs_dir, name) return pages def rewrite_wiki_links(text: str, page_names: set[str]) -> str: """Rewrite markdown links so they resolve inside the flat wiki namespace.""" import re def replace(match: re.Match[str]) -> str: label, target = match.group(1), match.group(2) if target.startswith(("http://", "https://", "#", "mailto:")): return match.group(0) page = target.split("#")[0].removesuffix(".md") if page == "README": # docs/README.md is published as the wiki Home page, so links to it must # resolve to Home instead of degrading to plain text. page = "Home" anchor = target.split("#", 1)[1] if "#" in target else "" if page in page_names: return f"[{label}]({page}{('#' + anchor) if anchor else ''})" # Not a published page: drop the link, keep the label as plain text. return label return re.sub(r"\[([^\]]*)\]\(([^)]+)\)", replace, text) def generate_sidebar(page_names: list[str], docs_dir: str) -> str: """Generate a wiki _Sidebar.md. When docs/_sidebar.md exists (the docsify site menu), it is the single source for both menus: its headings, group labels, order and nesting are preserved and only the markdown links are rewritten to the flat wiki namespace, so the GitHub wiki sidebar looks the same as the GitHub Pages one. Otherwise a plain list is built from the published page names. """ sidebar_source = os.path.join(docs_dir, "_sidebar.md") if os.path.isfile(sidebar_source): text = open(sidebar_source, encoding="utf-8").read() text = rewrite_wiki_links(text, page_names) # Keep the menu's headings, group labels, blank separators and indentation. # Links to pages that are not published in the wiki were already degraded to # plain labels by the rewriter, so they cannot point at a missing page. lines = text.splitlines() while lines and not lines[0].strip(): lines.pop(0) while lines and not lines[-1].strip(): lines.pop() if any(line.lstrip().startswith("- [") for line in lines): return "\n".join(lines) + "\n" # Fallback: auto-generate from the published page names. lines = [] if "Home" in page_names: lines.append("- [Home](Home)") for page in page_names: if page == "Home": continue label = page.replace("-", " ").replace("_", " ").title() if page.startswith("manual"): label = "Manual Tests" elif page == "parameters": label = "Parameters" lines.append(f"- [{label}]({page})") return "\n".join(lines) + "\n" def main() -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--dry-run", action="store_true", help="show the plan, change nothing") parser.add_argument("--repo-dir", default=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) parser.add_argument("--wiki-dir", default=os.path.join(tempfile.gettempdir(), "sl_wiki_sync")) args = parser.parse_args() repo_dir = os.path.abspath(args.repo_dir) docs_dir = os.path.join(repo_dir, "docs") if not os.path.isdir(docs_dir): print(f"ERROR: no docs folder at {docs_dir}", file=sys.stderr) return 2 print(f"Using repo: {repo_dir}") print(f"Using wiki: {args.wiki_dir}") wiki_dir = ensure_wiki_clone(args.wiki_dir) print(f"Wiki clone ready at {wiki_dir}") page_map = build_page_map(repo_dir) page_names = {os.path.splitext(name)[0] for name in page_map} # 1. Rewrite + stage new/updated pages plan: list[tuple[str, str]] = [] # (action, file) for wiki_name, source_path in sorted(page_map.items()): text = open(source_path, encoding="utf-8").read() text = rewrite_wiki_links(text, page_names) target = os.path.join(wiki_dir, wiki_name) existing = open(target, encoding="utf-8").read() if os.path.isfile(target) else None if existing != text: if not args.dry_run: with open(target, "w", encoding="utf-8", newline="\n") as fh: fh.write(text) plan.append(("update" if existing is not None else "add", wiki_name)) # 2. Sidebar sidebar = generate_sidebar(sorted(page_names), docs_dir) sidebar_target = os.path.join(wiki_dir, "_Sidebar.md") if not os.path.isfile(sidebar_target) or open(sidebar_target, encoding="utf-8").read() != sidebar: if not args.dry_run: with open(sidebar_target, "w", encoding="utf-8", newline="\n") as fh: fh.write(sidebar) plan.append(("update", "_Sidebar.md")) # 3. Delete stale pages (never the protected parameters page) for name in sorted(os.listdir(wiki_dir)): if not name.endswith(".md") or name.startswith("_"): continue if name in page_map or name in PROTECTED_WIKI_FILES: continue if not args.dry_run: os.remove(os.path.join(wiki_dir, name)) plan.append(("delete", name)) if not plan: print("No changes - wiki is up to date.") return 0 print("\nPlanned changes:") for action, name in plan: print(f" {action:6s} {name}") if args.dry_run: print("\nDry run - nothing was changed.") return 0 run_git(wiki_dir, "add", "-A") run_git(wiki_dir, "commit", "-m", "docs: sync wiki from docs/") print("\nPushing to the wiki...") try: run_git(wiki_dir, "push", "origin", "master") except RuntimeError as ex: print(f"PUSH FAILED: {ex}", file=sys.stderr) print( "The changes are committed locally in the wiki clone at:\n" f" {wiki_dir}\n" "Run 'git -C <that dir> push origin master' after authenticating.", file=sys.stderr, ) return 1 print("Wiki updated.") return 0 if __name__ == "__main__": sys.exit(main()) |
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |