Files
aimili-vpngate/scripts/build_release_archives.py

85 lines
2.7 KiB
Python

#!/usr/bin/env python3
from __future__ import annotations
import argparse
import hashlib
import shutil
import tarfile
import tempfile
from pathlib import Path
RELEASE_FILES = [
".dockerignore",
"VERSION",
"README.md",
"RELEASE_NOTES.md",
"LICENSE",
"install.sh",
"vpngate_manager.py",
"vpn_utils.py",
"proxy_server.py",
"snapshot_utils.py",
"Dockerfile",
"compose.yaml",
]
def sha256(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as handle:
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
def build_archive(root: Path, output_dir: Path) -> Path:
version = (root / "VERSION").read_text(encoding="utf-8").strip()
version_parts = version.split(".")
if len(version_parts) not in (2, 3) or any(not part.isdigit() for part in version_parts):
raise ValueError("VERSION 必须是点分隔的数字版本号")
missing = [name for name in RELEASE_FILES if not (root / name).is_file()]
if missing:
raise FileNotFoundError(f"发行文件缺失: {', '.join(missing)}")
if not (root / "mirror").is_dir():
raise FileNotFoundError("发行文件缺失: mirror")
output_dir.mkdir(parents=True, exist_ok=True)
for stale_archive in output_dir.glob("aimilivpn-v*-linux-*.tar.gz"):
stale_archive.unlink()
checksum_path = output_dir / "sha256sums.txt"
checksum_path.unlink(missing_ok=True)
with tempfile.TemporaryDirectory(prefix="aimilivpn-release-") as temp_name:
temp_root = Path(temp_name)
package_name = f"aimilivpn-v{version}-linux-source"
package_root = temp_root / package_name
package_root.mkdir()
for name in RELEASE_FILES:
shutil.copy2(root / name, package_root / name)
shutil.copytree(root / "mirror", package_root / "mirror")
archive_path = output_dir / f"{package_name}.tar.gz"
with tarfile.open(archive_path, "w:gz") as archive:
archive.add(package_root, arcname=package_name)
checksum_lines = [f"{sha256(archive_path)} {archive_path.name}"]
checksum_path.write_text("\n".join(checksum_lines) + "\n", encoding="ascii")
return archive_path
def main() -> int:
parser = argparse.ArgumentParser(description="构建 AimiliVPN Linux 通用 Python 源码发行包")
parser.add_argument("--root", type=Path, default=Path(__file__).resolve().parents[1])
parser.add_argument("--output-dir", type=Path, default=Path("dist"))
args = parser.parse_args()
archive = build_archive(args.root.resolve(), args.output_dir.resolve())
print(archive)
return 0
if __name__ == "__main__":
raise SystemExit(main())