# -*- coding: utf-8 -*- r"""数据目录自动回退:写不进程序目录就转 ProgramData。 背景: 原来的 data_dir() 就是 app_dir()/data —— 数据存在 exe 旁边。 绿色版没问题,但**做成安装包装到 Program Files 之后**, 普通用户对那个目录没有写权限,配置会存不下去。 用户选的做法: "能写 exe 旁边就写,不能就转 ProgramData" 这样两种情况都对: * 绿色版 / 装在 D 盘 / 便携 U 盘 -> 还是存在旁边,拔走就带走配置 * 装在 Program Files -> 自动转 C:\ProgramData\ykxmz, 所有用户共用一份(配对码不会因为换 Windows 账号而丢) 顺带加一个 YKXMZ_DATA 环境变量,测试和特殊部署可以强制指定。 """ from __future__ import annotations import ast import sys from pathlib import Path CONFIG = (Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote\windows" r"\lanremote\config.py")) OLD = '''def app_dir() -> Path: """程序所在目录(兼容 PyInstaller 冻结环境)。""" if getattr(sys, "frozen", False): return Path(sys.executable).resolve().parent return Path(__file__).resolve().parent.parent def data_dir() -> Path: return app_dir() / "data"''' NEW = '''def app_dir() -> Path: """程序所在目录(兼容 PyInstaller 冻结环境)。""" if getattr(sys, "frozen", False): return Path(sys.executable).resolve().parent return Path(__file__).resolve().parent.parent # 数据目录只算一次,之后缓存 —— 每个命令都去试写一次太浪费 _DATA_DIR_CACHE: Path | None = None def _can_write(folder: Path) -> bool: """这个目录能不能写(不存在就先建)。""" try: folder.mkdir(parents=True, exist_ok=True) probe = folder / ".write-test" probe.write_text("x", encoding="utf-8") probe.unlink() return True except OSError: return False def data_dir() -> Path: """配置 / 令牌 / 接收文件的存放目录。 优先级: 1. 环境变量 YKXMZ_DATA(测试和特殊部署用) 2. 程序目录下的 data/ —— 绿色版、便携 U 盘,拔走就带走配置 3. %PROGRAMDATA%\\ykxmz\\data —— 装到 Program Files 时用这个 为什么要有第 3 条: 安装包默认装到 C:\\Program Files\\ykxmz, 普通用户对那里**没有写权限**(Windows 的硬规矩,不是 bug)。 不转走的话,配对码和令牌会存不下去,用户会莫名其妙连不上。 ProgramData 是所有用户可写的公共位置,换 Windows 账号也不丢配置。 """ global _DATA_DIR_CACHE if _DATA_DIR_CACHE is not None: return _DATA_DIR_CACHE override = os.environ.get("YKXMZ_DATA") if override: _DATA_DIR_CACHE = Path(override) return _DATA_DIR_CACHE beside = app_dir() / "data" if _can_write(beside): _DATA_DIR_CACHE = beside return _DATA_DIR_CACHE base = os.environ.get("PROGRAMDATA") or r"C:\\ProgramData" common = Path(base) / "ykxmz" / "data" try: common.mkdir(parents=True, exist_ok=True) except OSError: # 兜底:连 ProgramData 都写不了(极罕见),退回用户目录 common = (Path(os.environ.get("LOCALAPPDATA") or Path.home()) / "ykxmz" / "data") common.mkdir(parents=True, exist_ok=True) _DATA_DIR_CACHE = common return _DATA_DIR_CACHE''' def main() -> int: text = CONFIG.read_text(encoding="utf-8") if "YKXMZ_DATA" in text: print(" 已经改过") return 0 if OLD not in text: print(" [失败] 锚点没找到") return 1 text = text.replace(OLD, NEW, 1) # 确认 os 已经 import 了 if "\nimport os" not in text: text = text.replace("import sys\n", "import os\nimport sys\n", 1) print(" 补了 import os") CONFIG.write_text(text, encoding="utf-8", newline="\n") print(" data_dir 加了自动回退(ProgramData)") try: ast.parse(text) print(" config.py 语法 OK") except SyntaxError as exc: print(f" 语法错误: 行 {exc.lineno}: {exc.msg}") return 1 return 0 if __name__ == "__main__": sys.exit(main())