for assorted things
at main 2.0 kB view raw
1#!/usr/bin/env -S uv run --script --quiet 2# /// script 3# requires-python = ">=3.12" 4# /// 5""" 6Update the README.md file with a list of all the scripts in the current directory. 7 8Usage: 9 10```bash 11./update-readme 12``` 13""" 14 15import ast 16import os 17import stat 18from pathlib import Path 19 20 21def get_docstring(path: Path) -> str: 22 try: 23 with open(path) as f: 24 tree = ast.parse(f.read()) 25 if not tree.body: 26 return "" 27 if isinstance(tree.body[0], ast.Expr) and isinstance( 28 tree.body[0].value, ast.Constant 29 ): 30 return str(tree.body[0].value.value).strip() 31 return "" 32 except Exception: 33 return "" 34 35 36def get_scripts() -> list[tuple[Path, str]]: 37 scripts = [] 38 for path in Path(".").iterdir(): 39 if ( 40 path.is_file() 41 and path.suffix in {".py", ""} 42 and not path.name.startswith(".") 43 and is_executable(path) 44 ): 45 doc = get_docstring(path) 46 scripts.append((path, doc)) 47 return sorted(scripts) 48 49 50def is_executable(path: Path) -> bool: 51 # https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_stat.h.html#tag_13_27_03_04 52 return bool(os.stat(path).st_mode & stat.S_IXUSR) 53 54 55def update_readme() -> None: 56 readme = Path("README.md") 57 content = readme.read_text() 58 59 parts = content.split("## scripts", 1) 60 base_content = parts[0].strip() 61 62 scripts = get_scripts() 63 script_list = "\n\n## scripts\n\n" 64 65 for script, _ in scripts: 66 script_list += f"- [`{script.name}`](#{script.name})\n" 67 script_list += "\n---\n\n" 68 69 for i, (script, doc) in enumerate(scripts): 70 script_list += f"### `{script.name}`\n\n{doc or 'no description'}\n\n" 71 if i < len(scripts) - 1: 72 script_list += "---\n\n" 73 74 new_content = base_content + script_list 75 76 if new_content != content: 77 readme.write_text(new_content) 78 79 80if __name__ == "__main__": 81 update_readme()