目录

hvisor-build

hvisor-build 是独立的 hvisor 源码取得、构建、产物发布和运行编排工具。默认源码锁定到 edfa0b4e266183d1a1b4938491ced70e2372da66,也可以用本地只读输入覆盖:

cargo build --release
target/release/hvisor-build list
target/release/hvisor-build riscv64-linux plan --hvisor-source ../hvisor --hvisor-tool-source ../hvisor-tool
target/release/hvisor-build riscv64-linux build --hvisor-source ../hvisor --hvisor-tool-source ../hvisor-tool
target/release/hvisor-build riscv64-linux run --hvisor-source ../hvisor --hvisor-tool-source ../hvisor-tool
target/release/hvisor-build riscv64-linux test --hvisor-source ../hvisor --hvisor-tool-source ../hvisor-tool

list 同时显示 profile 声明状态和当前 data root 中最新的本地验证结果;没有 TestRecord 时显示 not-testedplan 只读取 profile 并展示声明式 DAG,不取得源码、不解析镜像且不创建 workspace; doctor 只检查宿主工具、Docker daemon/image 和 KVM。只有 build/run/test 等执行命令才解析完整 Execution Identity 并准备受管源码与 workspace。

不指定 --source 时,工具从固定远端 revision 创建受管快照。.cache/ 保存可重建数据, work/<build-id>/ 是唯一可修改的源码副本,output/<profile>/<build-id>/ 保存 ArtifactSet 和 build-record.json,节点日志写入 logs/。这些目录均带有 ownership marker;用户 hvisor checkout 不会被 reset、clean 或直接构建。

每个 work/<build-id>/workspace-record.json 都明确记录该 workspace 对应的 profile 和 Build ID。新 workspace 在发布前写入记录;旧的受管 workspace 在下次使用时自动补写,已有记录 若与当前身份不一致则拒绝复用。

清理分为当前构建和历史回收两层。clean 删除当前 build identity 的可重建 workspace 与节点 cache stamp,但保留已经发布的 ArtifactSet、日志和共享下载缓存:

target/release/hvisor-build clean --profile riscv64-linux

prune 回收历史 build identity,默认按 profile 保留最近一个,并默认保留发布产物。 prune --all --keep 0 还会清理跨 profile 的 .cache/build-artifacts/ 节点产物缓存;普通 clean 和保留 identity 的 prune 不会删除共享下载、Git 或节点产物缓存。 节点 stamp 按 <profile>/<node-id> 保存;cleanprune --keep 0 会删除该 profile 的 节点 stamp。 建议先用 --dry-run 查看范围;只有显式传入 --delete-outputs 才删除发布产物:

target/release/hvisor-build prune --profile riscv64-linux --dry-run
target/release/hvisor-build prune --profile riscv64-linux --keep 1
target/release/hvisor-build prune --all --keep 1
target/release/hvisor-build prune --profile riscv64-linux --keep 0 --delete-outputs

两种清理都会先校验 hvisor-build ownership marker;日志还会校验所属的受管 profile 目录和 build-id 格式。它们不会清理用户提供的 hvisor/hvisor-tool checkout。prune 不解析或取得 源码,因此不会为了回收历史目录而创建新的 build workspace。

每个 profile 的 [sources.*] 是 zone 构建依赖的来源清单,明确记录 kindurlrevision。Git source 的 revision 必须是完整 40 位 commit;可选 version 保存便于阅读的 tag 名。构建任务直接读取这些字段,不在 Rust 实现中隐藏版本。本地 --hvisor-source--hvisor-tool-source 会覆盖两个仓库的默认获取方式;本地仓库的 commit 与 dirty digest 都会进入 build identity。

Profile schema v5 使用 [[nodes]] 直接声明构建 DAG;每个节点拥有独立的 needsrunnercommandsscriptresourcescachecommands 适合精确 argv, script 适合条件、trap、管道和生成文件,并固定以 bash -euo pipefail -c 执行。两者互斥。 调度器不预设 base、prepare、 zone 或 deploy 等节点名,因此新的构建图不需要修改 Rust 调度代码。

[[zones]] 只描述 zone 拓扑和元数据。systemkernel_sourcerootfs_sourcecontains 均由 profile 声明,调度器不会根据这些值选择 builder、推导文件名或决定部署方式。 Zone0、Zone1 和额外的 ZoneN 都只是 profile 自己定义的 DAG 节点与缓存边界。

Zone0 的构建进一步拆成独立节点和缓存边界:

zone0-system ──┬─> assemble-zone0 ──> hypervisor ──┐
               └─> control-tools ─────────────────┼─> deploy-zone1
zone1-system ──────────────────────────────────────┘

这些只是 shipped profile 采用的节点职责,不是 Rust 识别的 action。每个缓存输出只能由一个 节点声明;会被客户机部署修改的最终 rootfs 归最终部署节点所有,避免部署后反向使上游缓存失效。

runner 会原样执行 profile 声明的 commands 或内联 script,不存在 @task、recipe、 内部 action 或 PlatformBackend 分派。平台、系统、Zone、镜像布局和启动策略全部位于单个 profile TOML 中;不允许 profile 依赖额外的编排 .sh 文件。重复脚本优先于把策略抽回 Rust。

内联脚本可调用两个通用且不含平台策略的源码原语:

hvisor-build source fetch <source-name> <destination>
hvisor-build source fetch <source-name> --extract-to <directory> [--strip-components N]
hvisor-build source checkout <source-name> <destination>

fetch 保留 SHA-256 校验、共享缓存锁、损坏删除重下、.download 续传和重试;checkout 通过 .cache/git/ 中按仓库 URL 寻址的共享 bare cache 浅获取锁定 revision,再物化独立 checkout; 它也会纠正 origin、递归初始化 submodule,并识别受管本地源码快照。 归档只需展开时使用 --extract-to;工具直接从共享缓存读取 tar.xz、tar.gz 或 zip,不在 workspace 中保留归档副本。内容先展开到同目录临时树,成功后才替换目标;失败时保留原目录。 归档的展开目录和可选 --strip-components 仍由 profile 明确声明。

执行准备阶段会把 profile 中的 Docker tag 解析为不可变 image ID;该映射进入 build identity、 节点缓存 key 和 BuildRecord,后续 Docker 命令也直接使用解析后的 ID,避免可变 tag 在解析后漂移。 缓存验证需要在源码、profile、镜像和 data root 不变时连续执行两次相同的 build。每次 build 都会进入 DAG 并执行发布流程;第一次生成产物和 stamp,第二次各构建节点应打印 cache hit。缓存是透明的执行优化,不提供手动绕过选项;修改本地源码或更换 Docker 镜像会 生成新的 build identity。节点成功后还会把声明的文件产物发布到 .cache/build-artifacts/<input-digest>/;另一个 profile 或新 workspace 的节点具有相同输入、 命令、runner、依赖和源码锁时,可校验并恢复这些产物,打印 shared cache hit。 shared 节点产物和 ArtifactSet 在恢复或使用前始终校验 SHA-256。

ZoneN 不使用调度器内置的命名约定。profile 需要显式声明它的构建、部署命令和缓存路径,例如 zone2-system -> deploy-zone2rootfs3.ext4zone2.json 或其他名称只是该 profile 的选择。 因此新增 Zone2、其他系统或其他平台无需修改 Rust 调度代码。

仓库内的 .claude/skills/designing-profile-driven-builds/ 固化了这一职责边界。修改 profile、 平台配方、ZoneN、runner 或缓存声明时,可用该 skill 检查是否把策略重新写回调度器。

固定工具链和 rootfs 压缩包保存在 .cache/downloads/,由不同 build identity 共享;下载使用 .download 断点文件,成功后才发布到缓存。普通 fetch 会物化归档文件,--extract-to 则直接 从缓存展开。受管 workspace、发布产物、下载物化和节点缓存恢复的文件复制统一使用 reflink 优先、普通复制兜底。 Docker runner 还将 Cargo registry/git 数据和 rustup 下载、toolchain 分别保存在 .cache/cargo/.cache/rustup/,避免隔离容器在重试或新 identity 中重复下载 Rust 依赖。

ArtifactSet 先在 workspace 的 staging/ 中完整复制并校验,随后按 build identity 原子发布; 同一 build identity 再次构建成功时会原子更新对应 ArtifactSet。 BuildRecord schema v5 记录完整 SourceLock、zone/contains 拓扑、hvisor 与本地 hvisor-tool 源码、dirty digest、工具二进制摘要、节点命令、环境 白名单、输入/输出摘要以及 Docker image ID。run 不依赖易变的 build cache,只接受匹配当前 identity 且摘要有效的发布集;受管 workspace 产物损坏时会从发布集恢复。

test 同样只使用经过验证的发布集,并按 profile 的串口步骤自动等待启动标志、发送命令和 检查 guest 输出。完整控制台日志与 run-verified/failed JSON 记录保存在 logs/<profile>/<build-id>/tests/;无论成功、超时或匹配失败都会强制清理测试容器。

hvisor 和 hvisor-tool 使用相同的源码策略:本地构建直接反映本地仓库修改,远程构建严格使用 profile 锁定的 revision。hvisor-build 不对这两个仓库应用隐式兼容补丁;需要的修复必须进入对应 源码仓库,并由 profile 更新到包含修复的 revision。

开发检查:

cargo test
cargo clippy --all-targets -- -D warnings
关于
670.0 KB
邀请码
    Gitlink(确实开源)
  • 加入我们
  • 官网邮箱:gitlink@ccf.org.cn
  • QQ群
  • QQ群
  • 公众号
  • 公众号

版权所有:中国计算机学会技术支持:开源发展技术委员会
京ICP备13000930号-9 京公网安备 11010802047560号