Files
iOSAI/Utils/DevDiskImageDeployer.py
2025-08-28 20:01:01 +08:00

112 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# support_deployer.py
import os
import re
import shutil
from pathlib import Path
from dataclasses import dataclass, field
from typing import Iterable, Optional
VERSION_RE = re.compile(r"^\d+(?:\.\d+)*$") # 15 / 15.6 / 16.7 / 16.7.1
def _find_support_root(hint: Optional[Path]) -> Optional[Path]:
"""
1) 优先:显式传入的 hint
2) 其次:环境变量 SUPPORT_DDI_DIR
3) 再次:从 __file__ 所在目录向上搜索 3 层,找名为 'SupportFiles' 的目录
"""
# 1) 显式参数
if hint and hint.exists():
return hint.resolve()
# 2) 环境变量
env = os.environ.get("SUPPORT_DDI_DIR")
if env:
p = Path(env).expanduser()
if p.exists():
return p.resolve()
# 3) 向上搜索
here = Path(__file__).resolve().parent
for i in range(4): # 当前目录 + 向上 3 层
cand = here / "SupportFiles"
if cand.exists():
return cand.resolve()
here = here.parent
return None
@dataclass
class DevDiskImageDeployer:
"""
同步 SupportFiles/<version>/... 到 ~/.tidevice/device-support/<version>/...
- 自动定位 SupportFiles显式参数/环境变量/向上搜索)
- 已存在则跳过,不存在才复制
- 详细日志
"""
project_support_root: Optional[Path] = None # 可不传,自动发现
cache_root: Optional[Path] = None # 默认 ~/.tidevice/device-support
verbose: bool = True
dry_run: bool = False
overwrite: bool = False
_src_dir: Path = field(init=False, repr=False)
_cache_dir: Path = field(init=False, repr=False)
def __post_init__(self):
src = _find_support_root(self.project_support_root)
if src is None:
raise FileNotFoundError(
"未找到 SupportFiles 目录。"
"可传入 project_support_root或设置环境变量 SUPPORT_DDI_DIR"
"或确保在当前文件上层 3 级目录内存在名为 'SupportFiles' 的目录。"
)
self._src_dir = src
if self.cache_root is None:
self._cache_dir = Path.home() / ".tidevice" / "device-support"
else:
self._cache_dir = Path(self.cache_root).expanduser().resolve()
self._cache_dir.mkdir(parents=True, exist_ok=True)
if self.verbose:
print(f"[INFO] resolved SupportFiles = {self._src_dir}")
print(f"[INFO] cache_dir = {self._cache_dir}")
# 打印一眼能看见的兄弟目录,防路径误判
parent = self._src_dir.parent
try:
siblings = ", ".join(sorted(p.name for p in parent.iterdir() if p.is_dir()))
print(f"[INFO] SupportFiles parent = {parent}")
print(f"[INFO] siblings = {siblings}")
except Exception:
pass
def deploy_all(self):
candidates = list(self._iter_version_dirs(self._src_dir))
copied = skipped = 0
for ver_dir in candidates:
dst = self._cache_dir / ver_dir.name
if dst.exists() and not self.overwrite:
skipped += 1
continue
if dst.exists() and self.overwrite:
if not self.dry_run:
shutil.rmtree(dst)
if self.verbose:
print(f"[COPY] {ver_dir} -> {dst}")
if not self.dry_run:
shutil.copytree(ver_dir, dst)
copied += 1
if self.verbose:
print(f"[SUMMARY] copied={copied}, skipped={skipped}, total={copied+skipped}")
# -------- helpers --------
def _iter_version_dirs(self, root: Path) -> Iterable[Path]:
for p in sorted(root.iterdir()):
if p.is_dir() and VERSION_RE.match(p.name):
yield p