142 lines
4.6 KiB
Python
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())
|