- build.sh 改轻量:Ubuntu Minimal 底座、apt 精简(git/ssh/cloud-init/
python3/pip/curl/ca-certificates/xz-utils/fonts-wqy-microhei)、
Playwright + chromium-headless-shell、去 B-16 +12G 扩盘;
加 git + gt 1.0.0(官方 install.sh + SHA256 校验,GITEA_CLI_VERSION
钉 1.0.0)与 chv-sync 启动钩子(cloud-init runcmd)
- B-19(新发现):dpkg freeze 的 ${Package} 会被客机 shell 展开
成空,284 行全空白;加反斜杠转义,探针实测已出真实版本
- buildinfo.py:轻量 contents、chromium-headless-shell、gt_version
- generate/check_lockfile.py:gt/chv-sync 声明来源、headless-shell 映射
- chv-sync.sh(新):boot/pull/push/status,分叉/脏树失败关闭,
凭证走 seed 盘 guest-env,不进镜像
- README §1/§2/§3/§4 改轻量口径,新增 §7 Gitea 双向同步
- tests:ChvSyncTest 6 项(本地 bare 仓当远端);针对性测试 144 项全过
135 lines
4.6 KiB
Python
135 lines
4.6 KiB
Python
#!/usr/bin/env python3
|
||
"""生成 CHV 客机镜像的 BUILDINFO.json(build.sh 调用)。
|
||
|
||
从 build.sh 抽出(B-02),使其可独立单元测试。输入全部是
|
||
已落盘的构建产物与读回文件,不编造版本号:versions 来自
|
||
客机读回的 dpkg-query / pip freeze(Playwright=1 时另有
|
||
ms-playwright 缓存目录名作 chromium 标识);artifacts 的
|
||
sha256/size 是对产物文件实测的;image_sha256 即 disk.raw
|
||
的 sha256,供 generate_lockfile.py 沿用。
|
||
|
||
用法:
|
||
python3 buildinfo.py OUT_DIR TAG UBUNTU CODEX_VERSION \\
|
||
REPO_COMMIT UBUNTU_IMAGE_SHA256 PLAYWRIGHT(0|1)
|
||
"""
|
||
import hashlib
|
||
import json
|
||
import os
|
||
import re
|
||
import sys
|
||
import time
|
||
|
||
# 轻量口径(2026-11-06 用户定):Ubuntu Minimal 底座,只装
|
||
# codex + Python + SSH + cloud-init + 薄 agent + git + gt +
|
||
# 最小中文字体;已裁剪 pandoc/texlive/python-docx 等文档工具
|
||
# 与 qemu-guest-agent。chv-sync 是仓库内脚本,版本随 repo_commit。
|
||
BASE_CONTENTS = [
|
||
"git", "openssh-server", "cloud-init",
|
||
"python3", "python3-pip", "curl", "ca-certificates",
|
||
"xz-utils", "fonts-wqy-microhei", "codex",
|
||
"codex-code-mode-host", "codex-resources/bwrap",
|
||
"/app/host.py", "gt", "chv-sync",
|
||
]
|
||
|
||
# 执行器默认内核 cmdline(config.py),构建产物须与它一起记录(B-12),
|
||
# 否则换宿主/换执行器配置时无法复现。
|
||
KERNEL_CMDLINE = "console=hvc0 root=/dev/vda1 rw"
|
||
|
||
|
||
def _read_lines(path):
|
||
try:
|
||
with open(path) as fh:
|
||
return [line.strip() for line in fh if line.strip()]
|
||
except OSError:
|
||
return []
|
||
|
||
|
||
def _sha256_size(path):
|
||
digest = hashlib.sha256()
|
||
size = 0
|
||
with open(path, "rb") as fh:
|
||
for chunk in iter(lambda: fh.read(1 << 20), b""):
|
||
digest.update(chunk)
|
||
size += len(chunk)
|
||
return digest.hexdigest(), size
|
||
|
||
|
||
def build(outdir, tag, ubuntu, codex_version, repo_commit,
|
||
ubuntu_image_sha256, playwright):
|
||
disk_path = os.path.join(outdir, "disk.raw")
|
||
vmlinux_path = os.path.join(outdir, "vmlinux")
|
||
disk_sha, disk_size = _sha256_size(disk_path)
|
||
vmlinux_sha, vmlinux_size = _sha256_size(vmlinux_path)
|
||
contents = list(BASE_CONTENTS)
|
||
versions = {
|
||
"dpkg": _read_lines(
|
||
os.path.join(outdir, "guest-versions-dpkg.txt")),
|
||
"pip": _read_lines(
|
||
os.path.join(outdir, "guest-versions-pip.txt")),
|
||
"gt": _read_lines(
|
||
os.path.join(outdir, "guest-versions-gt.txt")),
|
||
}
|
||
gt_version = ""
|
||
for line in versions["gt"]:
|
||
m = re.search(r"(\d+\.\d+\.\d+)", line)
|
||
if m:
|
||
gt_version = m.group(1)
|
||
break
|
||
if playwright:
|
||
contents += ["playwright", "chromium-headless-shell"]
|
||
versions["chromium"] = _read_lines(
|
||
os.path.join(outdir, "guest-versions-chromium.txt"))
|
||
info = {
|
||
"tag": tag,
|
||
"ubuntu": ubuntu,
|
||
"codex_version": codex_version,
|
||
"repo_commit": repo_commit,
|
||
"gt_version": gt_version,
|
||
"built_at": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
|
||
"contents": contents,
|
||
"versions": versions,
|
||
"ubuntu_image_sha256": ubuntu_image_sha256,
|
||
"ubuntu_image_sha256_set": True,
|
||
"kernel_cmdline": KERNEL_CMDLINE,
|
||
"playwright": bool(playwright),
|
||
"image_sha256": disk_sha,
|
||
"artifacts": {
|
||
"disk.raw": {"sha256": disk_sha, "size": disk_size},
|
||
"vmlinux": {"sha256": vmlinux_sha, "size": vmlinux_size},
|
||
},
|
||
}
|
||
path = os.path.join(outdir, "BUILDINFO.json")
|
||
with open(path, "w") as fh:
|
||
json.dump(info, fh, indent=2)
|
||
fh.write("\n")
|
||
return info
|
||
|
||
|
||
def main(argv):
|
||
if len(argv) != 8:
|
||
print("用法:buildinfo.py OUT TAG UBUNTU CODEX_VERSION "
|
||
"REPO_COMMIT UBUNTU_IMAGE_SHA256 PLAYWRIGHT",
|
||
file=sys.stderr)
|
||
return 2
|
||
_, outdir, tag, ubuntu, codex_version, repo_commit, \
|
||
ubuntu_image_sha256, playwright = argv
|
||
info = build(outdir, tag, ubuntu, codex_version, repo_commit,
|
||
ubuntu_image_sha256, playwright == "1")
|
||
if not info["versions"]["dpkg"]:
|
||
print("BUILDINFO versions.dpkg 为空", file=sys.stderr)
|
||
return 1
|
||
if not info["versions"]["pip"]:
|
||
print("BUILDINFO versions.pip 为空", file=sys.stderr)
|
||
return 1
|
||
if not info["gt_version"]:
|
||
print("BUILDINFO gt_version 为空(gt 未装好)", file=sys.stderr)
|
||
return 1
|
||
if info["tag"] != tag:
|
||
print("BUILDINFO tag 不一致", file=sys.stderr)
|
||
return 1
|
||
return 0
|
||
|
||
|
||
if __name__ == "__main__":
|
||
raise SystemExit(main(sys.argv))
|