Files
BFR/tools/build_zip.py
M1rsem 4b0eee3eb5 Release PronBox v1.12.0 from NIH TechnoPron.
Rename Magisk branding to PronBox (author: TechnoPron team), stop customize.sh from forcing Box for Magisk, and ship wg-obfuscator plus Manage Profiles templates.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-13 09:09:32 +03:00

94 lines
2.8 KiB
Python

#!/usr/bin/env python3
"""Build Magisk ZIP with LF scripts (Android unzip-safe)."""
from __future__ import annotations
import zipfile
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
EXCLUDE_DIRS = {
".git",
".github",
"docs",
"tools",
"phone_configs",
"__pycache__",
}
EXCLUDE_FILES = {
"CHANGELOG.md",
"update.json",
"build.sh",
".gitignore",
"RELEASE.md",
}
EXCLUDE_GLOBS_SUFFIX = (".zip", ".pyc", ".lf", ".tar.gz", ".bak")
def version() -> str:
for line in (ROOT / "module.prop").read_text(encoding="utf-8").splitlines():
if line.startswith("version="):
return line.split("=", 1)[1].strip()
raise SystemExit("version= missing in module.prop")
def should_skip(rel: Path) -> bool:
parts = rel.parts
if any(p in EXCLUDE_DIRS for p in parts):
return True
if any(p.startswith("phone_") for p in parts):
return True
if rel.name in EXCLUDE_FILES:
return True
if rel.name.endswith(EXCLUDE_GLOBS_SUFFIX):
return True
return False
def normalize_bytes(path: Path, data: bytes) -> bytes:
# Force LF for shell/scripts installed on Android
text_ext = {".sh", ".ini", ".cfg", ".prop", ".md", ".json", ".yaml", ".yml", ".toml", ".example"}
name = path.name
if (
path.suffix.lower() in text_ext
or name in {"sbfr", "box.stealth", "box.sidecar", "box.service", "box.iptables", "box.tool", "box.profile", "customize.sh", "uninstall.sh", "box_service.sh", "service.sh", "post-fs-data.sh"}
or name.startswith("box.")
):
try:
text = data.decode("utf-8")
except UnicodeDecodeError:
return data
return text.replace("\r\n", "\n").replace("\r", "\n").encode("utf-8")
return data
def main() -> None:
ver = version()
out = ROOT / f"pronbox-{ver}.zip"
if out.exists():
out.unlink()
count = 0
with zipfile.ZipFile(out, "w", compression=zipfile.ZIP_DEFLATED) as zf:
for path in sorted(ROOT.rglob("*")):
if not path.is_file():
continue
rel = path.relative_to(ROOT)
if should_skip(rel):
continue
data = normalize_bytes(path, path.read_bytes())
# Unix paths inside zip
arc = rel.as_posix()
info = zipfile.ZipInfo(arc)
info.compress_type = zipfile.ZIP_DEFLATED
info.external_attr = 0o755 << 16 if (
path.parent.name == "scripts"
or path.name in {"sbfr", "customize.sh", "uninstall.sh", "box_service.sh", "service.sh"}
or path.suffix == ".sh"
) else (0o644 << 16)
zf.writestr(info, data)
count += 1
print(f"Wrote {out.name} ({count} files, {out.stat().st_size} bytes)")
if __name__ == "__main__":
main()