Files
coruna-lab/channel-builder-new/tools/pack_channel.py
T
2026-08-14 02:59:21 +08:00

142 lines
4.6 KiB
Python

#!/usr/bin/env python3
"""Pack a per-channel weifile zip from the already-built staged tree.
Does not rebuild natives or details. Requires `tools/build.py --apply` first.
1. Copy staged weifile (storage/app/channel-builder-new/out/weifile)
2. Replace CACACACA in index.js with the 8-char channel id
3. Zip as {artifact-root}/channel-source-new/{CHANNELID}.zip
"""
from __future__ import annotations
import argparse
import json
import tempfile
from pathlib import Path
from zipfile import ZIP_DEFLATED, ZipFile
import build as xxbb_build
RESULT_MARKER = xxbb_build.RESULT_MARKER
INDEX_CHANNEL_PLACEHOLDER = xxbb_build.INDEX_CHANNEL_PLACEHOLDER
WEIFILE_ROOT = xxbb_build.WEIFILE_ROOT
LAB_SEEDS_NAME = xxbb_build.LAB_SEEDS_NAME
def staged_weifile_dir(state_root: Path) -> Path:
return state_root / "out" / WEIFILE_ROOT
def patch_channel_code(text: str, channel_code: str) -> str:
if INDEX_CHANNEL_PLACEHOLDER not in text:
raise SystemExit(
f"index.js: missing {INDEX_CHANNEL_PLACEHOLDER} placeholder; "
"re-run tools/build.py --apply"
)
return text.replace(INDEX_CHANNEL_PLACEHOLDER, channel_code, 1)
def write_zip(weifile_dir: Path, zip_path: Path) -> Path:
zip_path.parent.mkdir(parents=True, exist_ok=True)
if zip_path.exists():
zip_path.unlink()
skip = {"_bak", "__pycache__", ".DS_Store", "decoded", "mm", "stages"}
with ZipFile(zip_path, "w", compression=ZIP_DEFLATED) as archive:
for path in sorted(weifile_dir.rglob("*")):
if not path.is_file():
continue
if path.name in skip or path.suffix == ".pyc":
continue
if any(part in skip for part in path.relative_to(weifile_dir).parts):
continue
rel = Path(WEIFILE_ROOT) / path.relative_to(weifile_dir)
archive.write(path, rel.as_posix())
return zip_path
def pack_channel(
*,
channel_code: str,
weifile_src: Path,
zip_out: Path,
) -> dict:
code = xxbb_build.normalize_channel_code(channel_code)
index_src = weifile_src / "index.js"
if not index_src.is_file():
raise SystemExit(
f"staged weifile missing ({index_src}). "
"Run: python tools/build.py --apply"
)
with tempfile.TemporaryDirectory() as tmp:
dest = Path(tmp) / WEIFILE_ROOT
xxbb_build.copy_tree(weifile_src, dest)
index_path = dest / "index.js"
index_path.write_text(
patch_channel_code(index_path.read_text(encoding="utf-8"), code),
encoding="utf-8",
)
write_zip(dest, zip_out)
return {
"campaign": "xxbb",
"builder_type": "new",
"channel_code": code,
"zip_path": str(zip_out),
"weifile_src": str(weifile_src),
}
def main() -> int:
parser = argparse.ArgumentParser(
description="Pack staged weifile into public/channel-source-new/{CHANNELID}.zip"
)
parser.add_argument("--channel-code", required=True, help="8-char channel id (e.g. FAFA9988)")
parser.add_argument(
"--state-root",
type=Path,
default=None,
help=f"builder state (default: {xxbb_build.default_state_root()})",
)
parser.add_argument(
"--weifile-src",
type=Path,
default=None,
help="staged weifile directory (default: <state-root>/out/weifile)",
)
parser.add_argument(
"--zip-out",
type=Path,
required=True,
help="output zip path",
)
args = parser.parse_args()
state_root = (args.state_root or xxbb_build.default_state_root()).resolve()
weifile_src = (args.weifile_src or staged_weifile_dir(state_root)).resolve()
zip_out = args.zip_out.resolve()
result = pack_channel(channel_code=args.channel_code, weifile_src=weifile_src, zip_out=zip_out)
seeds_path = state_root / LAB_SEEDS_NAME
if seeds_path.is_file():
try:
seeds = json.loads(seeds_path.read_text())
if isinstance(seeds, dict):
result["seeds"] = {
"deployment_seed": seeds.get("deployment_seed"),
"reporting_seed": seeds.get("reporting_seed"),
"channel_c": seeds.get("channel_c"),
}
result["domains"] = seeds.get("domains") or {"deployment": [], "reporting": []}
except json.JSONDecodeError:
pass
print(f"packed {result['channel_code']} -> {zip_out}")
print(RESULT_MARKER + json.dumps(result, separators=(",", ":")))
return 0
if __name__ == "__main__":
raise SystemExit(main())