delete_old_aos.iso
· 3.2 KiB · Text
Raw
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
按分支(1.0、1.1、1.2、1.3…)仅保留该分支中“最高版本目录”的 .iso 文件,删除其余版本目录中的 .iso。
- 仅删除 .iso,不动 .sha256 / .torrent / 目录结构。
- 支持 --dry-run 仅打印计划删除项。
- 版本比较使用语义数字比较:x.y.z -> (x,y,z),保证 1.3.10 > 1.3.4。
"""
from __future__ import annotations
import argparse
import logging
from pathlib import Path
import re
from typing import List, Tuple
BRANCH_RE = re.compile(r"^\d+\.\d+$") # e.g. "1.3"
VERSION_RE = re.compile(r"^\d+\.\d+\.\d+$") # e.g. "1.3.4"
def parse_version_tuple(s: str) -> Tuple[int, int, int]:
try:
a, b, c = s.split(".")
return int(a), int(b), int(c)
except Exception:
raise ValueError(f"非法版本号: {s}")
def find_branches(root: Path) -> List[Path]:
return sorted([p for p in root.iterdir() if p.is_dir() and BRANCH_RE.match(p.name)])
def find_versions(branch_dir: Path) -> List[Path]:
# 仅考虑该分支下的直接子目录,且匹配 x.y.z
return sorted([p for p in branch_dir.iterdir() if p.is_dir() and VERSION_RE.match(p.name)],
key=lambda p: parse_version_tuple(p.name))
def delete_old_isos(root: Path, dry_run: bool = True) -> int:
"""
返回计划/删除的 .iso 数量。
"""
total = 0
for branch in find_branches(root):
versions = find_versions(branch)
if not versions:
logging.info("分支 %s 无版本子目录,跳过。", branch)
continue
latest = versions[-1] # 最高版本
logging.info("分支 %s => 保留最新版本目录: %s", branch.name, latest.name)
# 其它版本目录中的 .iso 需要删除
to_clean = [v for v in versions if v != latest]
for vdir in to_clean:
for iso in vdir.glob("*.iso"):
total += 1
if dry_run:
logging.info("[DRY-RUN] 将删除: %s", iso)
else:
try:
iso.unlink()
logging.info("已删除: %s", iso)
except Exception as e:
logging.error("删除失败: %s (%s)", iso, e)
return total
def main():
ap = argparse.ArgumentParser(
description="按分支仅保留最新版本目录中的 .iso 文件,其余版本目录的 .iso 将被删除。"
)
ap.add_argument("root", nargs="?", default=".", help="根目录(默认为当前目录)")
ap.add_argument("--dry-run", "-n", action="store_true", help="只演练,不真正删除")
ap.add_argument("--quiet", "-q", action="store_true", help="安静模式,仅报错")
args = ap.parse_args()
log_level = logging.ERROR if args.quiet else logging.INFO
logging.basicConfig(level=log_level, format="%(message)s")
root = Path(args.root).resolve()
if not root.exists() or not root.is_dir():
logging.error("无效目录:%s", root)
raise SystemExit(2)
count = delete_old_isos(root, dry_run=args.dry_run)
if args.dry_run:
print(f"[DRY-RUN] 计划删除 .iso 数量: {count}")
else:
print(f"已删除 .iso 数量: {count}")
if __name__ == "__main__":
main()
| 1 | #!/usr/bin/env python3 |
| 2 | # -*- coding: utf-8 -*- |
| 3 | |
| 4 | """ |
| 5 | 按分支(1.0、1.1、1.2、1.3…)仅保留该分支中“最高版本目录”的 .iso 文件,删除其余版本目录中的 .iso。 |
| 6 | - 仅删除 .iso,不动 .sha256 / .torrent / 目录结构。 |
| 7 | - 支持 --dry-run 仅打印计划删除项。 |
| 8 | - 版本比较使用语义数字比较:x.y.z -> (x,y,z),保证 1.3.10 > 1.3.4。 |
| 9 | """ |
| 10 | |
| 11 | from __future__ import annotations |
| 12 | import argparse |
| 13 | import logging |
| 14 | from pathlib import Path |
| 15 | import re |
| 16 | from typing import List, Tuple |
| 17 | |
| 18 | BRANCH_RE = re.compile(r"^\d+\.\d+$") # e.g. "1.3" |
| 19 | VERSION_RE = re.compile(r"^\d+\.\d+\.\d+$") # e.g. "1.3.4" |
| 20 | |
| 21 | def parse_version_tuple(s: str) -> Tuple[int, int, int]: |
| 22 | try: |
| 23 | a, b, c = s.split(".") |
| 24 | return int(a), int(b), int(c) |
| 25 | except Exception: |
| 26 | raise ValueError(f"非法版本号: {s}") |
| 27 | |
| 28 | def find_branches(root: Path) -> List[Path]: |
| 29 | return sorted([p for p in root.iterdir() if p.is_dir() and BRANCH_RE.match(p.name)]) |
| 30 | |
| 31 | def find_versions(branch_dir: Path) -> List[Path]: |
| 32 | # 仅考虑该分支下的直接子目录,且匹配 x.y.z |
| 33 | return sorted([p for p in branch_dir.iterdir() if p.is_dir() and VERSION_RE.match(p.name)], |
| 34 | key=lambda p: parse_version_tuple(p.name)) |
| 35 | |
| 36 | def delete_old_isos(root: Path, dry_run: bool = True) -> int: |
| 37 | """ |
| 38 | 返回计划/删除的 .iso 数量。 |
| 39 | """ |
| 40 | total = 0 |
| 41 | for branch in find_branches(root): |
| 42 | versions = find_versions(branch) |
| 43 | if not versions: |
| 44 | logging.info("分支 %s 无版本子目录,跳过。", branch) |
| 45 | continue |
| 46 | |
| 47 | latest = versions[-1] # 最高版本 |
| 48 | logging.info("分支 %s => 保留最新版本目录: %s", branch.name, latest.name) |
| 49 | |
| 50 | # 其它版本目录中的 .iso 需要删除 |
| 51 | to_clean = [v for v in versions if v != latest] |
| 52 | for vdir in to_clean: |
| 53 | for iso in vdir.glob("*.iso"): |
| 54 | total += 1 |
| 55 | if dry_run: |
| 56 | logging.info("[DRY-RUN] 将删除: %s", iso) |
| 57 | else: |
| 58 | try: |
| 59 | iso.unlink() |
| 60 | logging.info("已删除: %s", iso) |
| 61 | except Exception as e: |
| 62 | logging.error("删除失败: %s (%s)", iso, e) |
| 63 | |
| 64 | return total |
| 65 | |
| 66 | def main(): |
| 67 | ap = argparse.ArgumentParser( |
| 68 | description="按分支仅保留最新版本目录中的 .iso 文件,其余版本目录的 .iso 将被删除。" |
| 69 | ) |
| 70 | ap.add_argument("root", nargs="?", default=".", help="根目录(默认为当前目录)") |
| 71 | ap.add_argument("--dry-run", "-n", action="store_true", help="只演练,不真正删除") |
| 72 | ap.add_argument("--quiet", "-q", action="store_true", help="安静模式,仅报错") |
| 73 | args = ap.parse_args() |
| 74 | |
| 75 | log_level = logging.ERROR if args.quiet else logging.INFO |
| 76 | logging.basicConfig(level=log_level, format="%(message)s") |
| 77 | |
| 78 | root = Path(args.root).resolve() |
| 79 | if not root.exists() or not root.is_dir(): |
| 80 | logging.error("无效目录:%s", root) |
| 81 | raise SystemExit(2) |
| 82 | |
| 83 | count = delete_old_isos(root, dry_run=args.dry_run) |
| 84 | if args.dry_run: |
| 85 | print(f"[DRY-RUN] 计划删除 .iso 数量: {count}") |
| 86 | else: |
| 87 | print(f"已删除 .iso 数量: {count}") |
| 88 | |
| 89 | if __name__ == "__main__": |
| 90 | main() |
| 91 |