Spaces:
Running
Running
| # startup.py | |
| import os, pathlib, json, shutil | |
| BASE = pathlib.Path(__file__).parent # 通常是 /app | |
| # 可选显式指定源码目录(绝对路径),若不设会自动发现: | |
| APP_SOURCE_DIR = os.getenv("APP_SOURCE_DIR") | |
| # 入口文件候选名(可覆盖) | |
| ENTRY_HINTS = [s.strip() for s in os.getenv( | |
| "APP_ENTRY_HINTS", "script.py,app.py,main.py,server.py" | |
| ).split(",") if s.strip()] | |
| def find_source_dir() -> pathlib.Path | None: | |
| # 1) 环境变量优先 | |
| if APP_SOURCE_DIR: | |
| p = pathlib.Path(APP_SOURCE_DIR) | |
| if p.is_dir(): return p | |
| # 2) 常见候选根 | |
| candidates = [BASE, BASE / "src"] | |
| for d in BASE.iterdir(): | |
| if d.is_dir(): | |
| candidates.append(d) | |
| if (d / "src").is_dir(): | |
| candidates.append(d / "src") | |
| # 3) 在候选根里按入口名搜索 | |
| for root in candidates: | |
| for entry in ENTRY_HINTS: | |
| for path in root.rglob(entry): | |
| if "site-packages" in str(path): | |
| continue | |
| return path.parent | |
| return None | |
| SRC_READONLY = find_source_dir() | |
| if not SRC_READONLY: | |
| # 打印部分目录树帮助定位 | |
| listing = "\n".join([str(p) for p in BASE.rglob("*")][:200]) | |
| raise FileNotFoundError( | |
| f"找不到源码目录,请设置 APP_SOURCE_DIR。已尝试在 {BASE} 下自动发现。\n" | |
| f"以下为部分目录树(截断):\n{listing}" | |
| ) | |
| # 选择可写运行目录(优先 /data,失败回退 /tmp) | |
| pref = pathlib.Path(os.getenv("APP_RUNTIME_DIR", "/data/grade_query_app")) | |
| RUNTIME = pref | |
| try: | |
| RUNTIME.mkdir(parents=True, exist_ok=True) | |
| (RUNTIME / ".probe").write_text("ok", encoding="utf-8") | |
| (RUNTIME / ".probe").unlink(missing_ok=True) | |
| except Exception: | |
| RUNTIME = pathlib.Path("/tmp/grade_query_app") | |
| RUNTIME.mkdir(parents=True, exist_ok=True) | |
| # 把源码复制到可写目录,保持相对路径语义(templates 等) | |
| shutil.copytree(SRC_READONLY, RUNTIME, dirs_exist_ok=True) | |
| # 把 Secrets 写成运行期文件 | |
| cookies_txt = os.getenv("COOKIES_TXT", "").strip() | |
| students_json = os.getenv("STUDENTS_JSON", "").strip() | |
| if cookies_txt: | |
| (RUNTIME / "cookies.txt").write_text(cookies_txt, encoding="utf-8") | |
| print(f"✅ cookies.txt -> {RUNTIME/'cookies.txt'}") | |
| if students_json: | |
| try: | |
| data = json.loads(students_json) | |
| (RUNTIME / "students.json").write_text( | |
| json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8" | |
| ) | |
| print(f"✅ students.json (parsed JSON) -> {RUNTIME/'students.json'}") | |
| except Exception: | |
| (RUNTIME / "students.json").write_text(students_json, encoding="utf-8") | |
| print(f"✅ students.json (raw text) -> {RUNTIME/'students.json'}") | |
| # 暴露给 wsgi.py 使用 | |
| os.environ["APP_RUNTIME_DIR_RESOLVED"] = str(RUNTIME) | |
| for hint in ENTRY_HINTS: | |
| if (RUNTIME / hint).exists(): | |
| os.environ["APP_ENTRY_FILE_RESOLVED"] = hint | |
| break | |
| print(f"ℹ️ Using runtime dir: {RUNTIME}, entry: {os.environ.get('APP_ENTRY_FILE_RESOLVED','(auto)')}") |