# -*- coding: utf-8 -*- r'''修我自己 scrub 时弄坏的 3 个文件。 == 怎么坏的 == scrub_old_password.py 里对这个模式: {"password": "<六位数字>"} 做了个"聪明"的替换: {"password": "" # 见下方注释:不再写死} —— 把 `"<六位数字>"` 换成了带注释的东西,**塞进了字典字面量中间**, 于是 `{` 永远不闭合,三个文件全语法错。 教训:**批量替换不能往表达式中间塞注释**。 这次改成把整行替换掉,并在文件顶部加一个读密码的辅助函数。 (同一批被改的其它文件只是字符串内容变了,语法没坏, 这里只修真正语法出错的三个。) == 顺带 == 这个脚本本身也演示了"怎么在运维脚本里拿密码而不写死": 从环境变量或 _build/.admin_password 读(后者已 gitignore)。 ''' from __future__ import annotations import re import sys from pathlib import Path ROOT = Path(__file__).resolve().parent.parent BROKEN_LINE = re.compile( r'^(\s*)form = urllib\.parse\.urlencode\(\{"password": ""' r'\s*# 见下方注释:不再写死\}\)\.encode\(\)\s*$') # ⚠ 不要手写文件列表。 # # 第一版我列了三个文件名(照语法检查的输出抄的), # 结果一跑发现还有两个同样的坏文件没修 —— 列表是**观察到的**, # 不是**穷尽的**。改成全仓库扫这个模式,漏不掉。 SCAN_DIRS = ("_build", "_tests", "windows", "relay", "installer") REPLACEMENT = ( '{indent}form = urllib.parse.urlencode(' '{{"password": _admin_password()}}).encode()') HELPER = ''' # ⚠ 不再把密码写死在脚本里。 # # 这个仓库是公开的,密码写进来就等于公开(2026-10-08 踩过: # 旧密码曾被写进安装包的许可页,每个装软件的人都能看到)。 # 现在从环境变量或 _build/.admin_password(已 gitignore)读 —— # 读不到就直接报错,别偷偷用一个默认值。 def _admin_password() -> str: import os env = os.environ.get("YKXMZ_ADMIN_PASSWORD", "").strip() if env: return env f = Path(__file__).resolve().parent / ".admin_password" if f.is_file(): return f.read_text(encoding="utf-8").strip() raise SystemExit( "没拿到管理密码:设 YKXMZ_ADMIN_PASSWORD," "或把密码写进 _build/.admin_password") ''' def main() -> int: print("=" * 58) print(" 修被 scrub 弄坏的 3 个文件") print("=" * 58) fixed = 0 # 全仓库找坏模式,而不是照抄一份文件名列表 targets = [] for d in SCAN_DIRS: for p in sorted((ROOT / d).rglob("*.py")): try: if BROKEN_LINE.search(p.read_text(encoding="utf-8-sig")): targets.append(p) except (OSError, UnicodeDecodeError): continue print(" 扫到 %d 个待修文件" % len(targets)) print() for path in targets: rel = path.relative_to(ROOT).as_posix() raw = path.read_bytes() bom = raw.startswith(b"\xef\xbb\xbf") text = raw.decode("utf-8-sig") lines = text.splitlines() hit = False for i, line in enumerate(lines): m = BROKEN_LINE.match(line) if m: lines[i] = REPLACEMENT.format(indent=m.group(1)) hit = True if not hit: continue text = "\n".join(lines) + "\n" # 顶部加辅助函数(放在 `import` 全部结束之后) if "_admin_password" not in text.split("def _admin_password")[0]: m2 = None for m in re.finditer(r"^(?:import|from)\s+\S+.*$", text, re.M): m2 = m if m2: text = text[:m2.end()] + "\n" + HELPER + text[m2.end():] else: text = HELPER + text path.write_bytes((b"\xef\xbb\xbf" if bom else b"") + text.encode("utf-8")) print(" ✓ %s" % rel) fixed += 1 print() print(" 修了 %d 个" % fixed) return 0 if __name__ == "__main__": sys.exit(main())