mcpField
J
jetson-promote-image

jetson-promote-image

github.com/nvidia云与 DevOps3.8k1.1k 次安装今天更新
代码仓库

关于 jetson-promote-image

jetson-promote-image 将定制和构建产物复制到配置的 bsp_image,供后续刷写或检查。它合并 overlay 与构建清单输入,跳过相同文件,并在内核或模块变化时刷新 initramfs。

主要功能

  1. 01合并 overlay 与构建清单产物
  2. 02跳过内容相同的文件
  3. 03将变更的内核 Image 镜像到 rootfs
  4. 04内核或模块变更后刷新 initramfs
  5. 05检查构建新鲜度和 overlay 冲突

适用场景

  1. 01刷写 Jetson 前暂存 BSP 产物
  2. 02不刷写而更新 bsp_image 以供检查
  3. 03为另一台刷写主机准备镜像

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/nvidia/skills --skill jetson-promote-image

安装后在 Claude Code 中输入/jetson-promote-image确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

BENCHMARK.md
skill-card.md
skill.oms.sig
evals/
evals.json
references/
build-source-freshness-gate.md
copy-pass-snippets.md
kernel-image-and-initramfs.md

详细介绍

提升 BSP 映像

用途

将所有 Customize-* 和 Build 输出暂存到 bsp_image,使其 可用于 /jetson-flash-image。这是 Deploy 的提升阶段—— 它只复制文件,不刷写,也不构建。

前置条件

  • 已激活的目标平台配置,其中 source: 和 bsp_image: 均已解析(先运行 /jetson-init-source 和 /jetson-init-image)。
  • <source.root_path>/Linux_for_Tegra/ 已初始化为 git 仓库 (覆盖层跟踪器),且工作树干净。
  • <bsp_image.root_path>/Linux_for_Tegra/ 已从 BSP tarball 解压,并已运行 apply_binaries.sh。
  • 主机上已安装 git、yq、cmp 和 sudo(用于 rootfs/* 目标路径)。
  • /jetson-build-source 生成的 <source.root_path>/.build-manifest.yaml 和 .build-state.yaml (内核侧仓库有 customize-* 提交时必需)。

概述

这是 Deploy 的提升阶段——流水线概览请参阅 ../../context/bsp-customization-workflow.md。 此技能会遍历以下两个通道:

通道来源载体所属方
覆盖层跟踪器<source.root_path>/Linux_for_Tegra/(位于 HEAD 的 git 仓库)无需构建的 Customize-* 输出(例如 nvfancontrol.conf、nvpmodel.conf、手动编辑的 BPMP DTB)Customize customize-* 技能在此提交
构建清单<source.root_path>/.build-manifest.yaml重新构建的内核 Image、树内 .ko、OOT .ko、NVIDIA DTBBuild jetson-build-source 在此写入

此技能会计算需要复制的文件并集,并将每个文件写入 <bsp_image.root_path>/Linux_for_Tegra/,同时采用感知差异的 相同文件跳过逻辑。当复制操作涉及内核 Image 或 rootfs/lib/modules/ 下的任何内容时,它还会通过 NVIDIA 的 tools/l4t_update_initrd.sh 重新构建 initramfs,以便刚提升的内核和模块包含在 引导加载程序实际加载的 initrd 中。运行完成后,bsp_image 会包含所有 Customize 和 Build 输出。此技能不会刷写,也 不会修改工作区。

何时调用

  • 典型 Deploy 链的第一阶段: jetson-promote-image → jetson-flash-image → jetson-validate-image。
  • 独立调用:用户希望更新 bsp_image,但尚未准备好刷写时 (例如检查解析后的文件、运行读取 bsp_image 的 带外构建,或将 bsp_image 交给单独的刷写主机)。

步骤

解析激活的目标和路径

按照 ../../context/target-platform-contract.md 中的契约解析激活的配置。

在以下情况下拒绝并转交:

条件拒绝时转交至
没有激活的配置,或 active: NA转交至 /jetson-set-target 或 /jetson-init-target。
配置缺少 bsp_image:转交至 /jetson-init-image。
<bsp_image.root_path>/Linux_for_Tegra/ 不存在转交至 /jetson-init-image。
<source.root_path>/Linux_for_Tegra/ 不存在或不是 git 仓库转交至 /jetson-init-source。

解析路径:

  • <workspace> = 激活配置的 target-platform/ 目录的父目录(在加载时发现)。
  • <bsp_image.root_path> 取自 bsp_image.root_path:(若存在), 否则为 <workspace>/Image。
  • <source.root_path> 取自 source.root_path:(若存在),否则 为 <workspace>/Source。

为本步骤后续部分绑定 Shell 变量:

LFT_SRC="<source.root_path>/Linux_for_Tegra"   # overlay tracker
LFT_DST="<bsp_image.root_path>/Linux_for_Tegra"
MANIFEST="<source.root_path>/.build-manifest.yaml"   # build outputs
验证两个通道

此技能要求至少有一个通道包含内容。如果覆盖层跟踪器有未提交的更改(status --porcelain 非空)、$MANIFEST 存在但无法解析为 YAML,或两个通道都为空,则拒绝执行。记录 OVERLAY_HAS_COMMITS / OVERLAY_HEAD 和 MANIFEST_PRESENT,供后续步骤使用。

Shell 代码片段和拒绝消息请参阅 references/copy-pass-snippets.md。

验证构建源的新鲜度

如果 .build-state.yaml 显示 Source/bsp_sources/ 中有任何内核侧仓库自上次 /jetson-build-source 以来存在未提交更改,则拒绝执行;否则,复制过程可能会悄然发布过时的制品。 检测规则和 shell 片段见 references/build-source-freshness-gate.md。 记录 BUILD_FRESH=1。

提升前冲突检查(仅限 overlay)

当 overlay 跟踪远程仓库时,如果上游存在尚未拉取的提交,则拒绝执行。未配置远程仓库时(jetson-init-source 创建的默认空 git init 跟踪仓库),则优雅跳过。 manifest 通道没有 git 远程仓库的概念——此检查仅适用于 overlay。为 Summary 记录 COLLISION_CHECK。

shell 片段见 references/copy-pass-snippets.md。

枚举源(两个通道)

通道 A — overlay:以针对 $LFT_SRC 执行的 git ls-files 结果为准(当 source.repos.Linux_for_Tegra 被覆盖时,此方式可透明处理符号链接挂载,并排除未跟踪或被 .gitignore 忽略的文件)。每个条目映射为 src = $LFT_SRC/<rel> → dst = $LFT_DST/<rel>。

通道 B — manifest:从 $MANIFEST 解析 artifacts[].{src,dst}。如果磁盘上缺少任何 src,则拒绝执行(构建已中断或 manifest 已过时——请重新运行 /jetson-build-source)。 manifest 架构由 jetson-build-source v0.2.0 编写。

两个 shell 片段和 manifest YAML 架构见 references/copy-pass-snippets.md。

将差异文件复制到 bsp_image

遍历 overlay 文件和 manifest 条目的并集。对于每个 dst:如果字节完全相同,则跳过;否则执行 cp -p(对于 rootfs/* 目标,使用 sudo,因为示例 rootfs 是以 root 身份解压的)。如果写入了任何 rootfs/lib/modules/* 或 kernel/Image,则设置 INITRD_DIRTY=1——“刷新 initramfs”步骤会根据此标志决定是否执行。为 Summary 记录计数 / FIRST / LAST。

快速失败:如果任何 cp 失败,则指出失败路径并停止。bsp_image 可能只更新了一部分——修复原因后重新运行,即可通过差异感知跳过机制继续。通道顺序为先 overlay,后 manifest:如果 dst 冲突,则以 manifest 为准(新构建的制品优先于较旧的 overlay 副本)。

copy_one() 函数和两个驱动循环见 references/copy-pass-snippets.md。

内核发生变化时,将内核 Image 镜像到 rootfs

内核 Image 在 bsp_image 中有两个路径: <LFT_DST>/kernel/Image(刷写工具读取的文件)和 <LFT_DST>/rootfs/boot/Image(rootfs 侧副本,在刷新工具运行所在的 rootfs chroot 环境中可见为 /boot/Image)。构建 manifest 只包含 kernel/Image 的 dst,因此此步骤会将 kernel/Image 镜像到 rootfs/boot/Image(差异感知;已同步时不执行任何操作),确保 chroot 中的刷新工具使用新提升的二进制文件解析内核,而不是过时的 rootfs 副本。镜像操作也会设置 INITRD_DIRTY=1,因此仅提升内核(未写入 rootfs/lib/modules/*)时仍会触发刷新。

shell 片段、此操作可避免的故障模式以及 INITRD_DIRTY 的边缘情况见 references/kernel-image-and-initramfs.md。

刷新 initramfs(内核或模块发生变化时)

每当 INITRD_DIRTY=1(由上方的差异感知复制或镜像步骤设置)时,都要从 <LFT_DST>/ 运行 tools/l4t_update_initrd.sh。该工具会 chroot 进入 rootfs/,运行 NVIDIA 的 nv-update-initrd,并写入 <LFT_DST>/bootloader/l4t_initrd.img(由刷写工具使用)和 <LFT_DST>/rootfs/boot/initrd(DUT 上的 /boot/initrd)。操作具有幂等性;耗时约 30 秒。INITRD_DIRTY=0 时跳过(仅修改 overlay)。DUT 端的变通方案(update-initramfs -u 加手动 cp)不在范围内——应在此处修复缺口,确保刷写时使用一致的镜像。

有关 shell 代码片段、拒绝处理的路径、此重建所解决的“模块遮蔽”和“vermagic 不匹配”故障模式,以及为何不处理 bootloader/initrd(另一个不同的文件),请参阅 references/kernel-image-and-initramfs.md。

摘要

报告:

  • Overlay 范围:overlay HEAD ($OVERLAY_HEAD) 或“(空)”。
  • Manifest 范围:mode=<...>, bsp_version=<...>, rebuilt_at=<...>, N artifacts 或“(不存在)”。
  • 冲突检查:$COLLISION_CHECK。
  • 计数:
    • overlay:$COPIED_OVERLAY copied, $IDENTICAL_OVERLAY identical
    • manifest:$COPIED_MANIFEST copied, $IDENTICAL_MANIFEST identical
  • Kernel Image 镜像:$KIMG_MIRRORED;initramfs:$INITRD_STATUS(由 kernel/Image 或 rootfs/lib/modules/* 写入触发时为 copied … / rebuilt;否则为 skipped …)。
  • 首个 / 最后一个复制的路径(若 COPIED 总数均为 0,则省略)。
  • 解析后的 <source.root_path>、<bsp_image.root_path>。
  • 下一步:/jetson-flash-image(如果用户只想刷新 bsp_image 以供检查 / 静态验证,则为 /jetson-validate-image)。

限制

  • 两个通道,一个目标目录。 两轮操作都会写入 bsp_image/Linux_for_Tegra/。Overlay 承载 customize-* 的输出(仅 Overlay 的修改,例如 nvfancontrol.conf);清单承载重建的二进制文件(kernel/OOT/DT)。两者在设计上互不重叠:构建输出不会进入 Overlay,customize-* 对非构建文件的修改也不会进入清单。
  • 构建清单是追溯到脏源代码的约定。 清单中的所有内容都来自存在未提交更改的源代码仓库(依据 jetson-build-source 的“Write the build manifest”步骤追踪策略)。因此,提升清单内容是安全的:每个条目都是承载自定义内容的构件,而不是工具链差异造成的噪声。该技能不会重新推导追踪结果,而是信任清单。
  • 清单条目可能在构建输出被删除后仍然存在。 如果用户在 jetson-build-source 和 jetson-promote-image 之间清空 Source/.build/ 或 bsp_sources/ 的构建构件,清单将引用不存在的文件。在这种情况下,“Enumerate sources (both channels)”步骤会拒绝继续,并提示用户运行 /jetson-build-source 重新构建。
  • 仅发生 Overlay 修改时,清单缺失没有问题。 纯 Overlay 侧的自定义修改(例如 customize-fan)不会生成构建输出,也不会写入清单——“Enumerate sources (both channels)”步骤将不执行任何操作,“Diff-aware copy into bsp_image”步骤只会提升 Overlay 文件。该技能会在摘要中显示“manifest: (absent)”,然后继续。
  • 感知差异且幂等。 如果自上次提升以来,Overlay 没有新提交且清单没有变化,重新运行不会产生任何操作(所有文件都相同)。可用此方式确认 bsp_image 已同步,且不会产生副作用。
  • 透明处理符号链接挂载。 当 jetson-init-source 中覆盖了 source.repos.Linux_for_Tegra 时,规范挂载点是指向 <source.root_path>/.repos/Linux_for_Tegra/<subdir> 的符号链接。git -C、cp -p 和 cmp -s 都会透明地跟随该链接——此层无需特殊处理。清单中的 src 路径是绝对路径,因此 bsp_sources/ 下的符号链接不会影响清单通道。
  • sudo 仅用于 rootfs/ 目标路径。 rootfs/ 下的文件由 jetson-init-image 使用 sudo tar xpjf 解压,因此具有 root 所有权和烧录工具链读取所需的特殊模式位。sudo cp -p 会保留这些属性。其他所有内容(bootloader/、kernel/、kernel/dtb/、tools/ 等)均归用户所有,无需使用 sudo。这适用于两个通道。
  • 通道重叠时的优先级。 如果同一个 dst 同时出现在 Overlay 和清单中,则以清单为准(它在“Diff-aware copy into bsp_image”步骤的循环中靠后处理)。这符合预期语义——清单条目是最新构建的,而 Overlay 条目可能是较旧状态。不建议手动将二进制文件编辑后放入 Overlay(应由 Build 负责重建);该优先级规则可让此类错误得以恢复。
  • Deploy 之外的 bsp_image 为只读。 在正常流程中,此技能是唯一的写入方(符合工作流不变量)。在 Deploy 之外手动编辑 <bsp_image.root_path>/Linux_for_Tegra/,如果同一路径存在于任一通道中,下次提升运行时这些修改会被静默覆盖;反之,如果没有对应条目覆盖,这些修改则不会被还原。这两种情况都会破坏差异追踪记录——切勿手动修改上游内容。
  • 范围仅限 Overlay 的 HEAD(通道 A)。 指定标签/清单/提交范围的功能暂不支持(见下文)。要提升历史状态,请先运行 git -C $LFT_SRC checkout <ref>,然后重新运行。清单通道没有范围限制——它反映 jetson-build-source 上次运行所生成的内容。
  • 部分失败时不会自动回滚。 如果 cp 中途失败,bsp_image 会处于中间状态。请修复根本原因(通常是权限问题或磁盘空间不足),然后重新运行——“Diff-aware copy into bsp_image”步骤会跳过已提升的文件并从中断处继续。
  • Kernel Image 镜像及 initramfs 刷新。 仅当复制过程中写入了 kernel/Image 或 rootfs/lib/modules/* 时才会触发;镜像会供刷新的 chroot 使用。两者都会感知差异,纯 Overlay 修改时会跳过。bsp_image 中必须存在 tools/l4t_update_initrd.sh(随 apply_binaries.sh 提供);如果缺少该工具,将拒绝继续并引导用户运行 /jetson-init-image。完整约定和失败情况请参阅 references/kernel-image-and-initramfs.md。

故障排除

错误原因解决方案
Overlay has uncommitted changes at <LFT_SRC>promote 前未提交 Customize-* 编辑运行 git -C $LFT_SRC commit(或 stash),然后重新运行。
origin has N unpulled commits on <upstream>远程 overlay 与本地分支不一致运行 git -C $LFT_SRC pull,解决冲突,然后重新运行。
Both overlay and manifest are empty — nothing to promote没有 Customize-* 提交,也没有 Build 清单先运行 customize-* 技能或 /jetson-build-source。
Kernel-side source(s) changed since last /jetson-build-source新鲜度检查发现 Source/bsp_sources/ 下有尚未处理的 customize-* 编辑提交待处理的编辑,运行 /jetson-build-source,然后重新运行 promote。
Manifest entry references missing build output: <src>bsp_sources/ 构建输出已被删除,或清单已过期重新运行 /jetson-build-source 以重新生成。
Build manifest at <MANIFEST> is not valid YAML清单被手动编辑或只写入了一部分重新运行 /jetson-build-source 以重写清单。
cp: permission denied(在 rootfs/ 下)主机缺少 sudo 权限使用可以运行 sudo cp 的账户执行;重新运行后会通过差异感知复制继续操作。
配置文件缺少 bsp_image: / source:工作区尚未完成引导运行 /jetson-init-image 和/或 /jetson-init-source。
tool not found at <LFT_DST>/tools/l4t_update_initrd.shtools/ 已被清理,或 bsp_image 是从非 NVIDIA 的 tarball 解压而来重新运行 /jetson-init-image 以恢复所需文件。
l4t_update_initrd.sh exited non-zerosudo 权限不足、rootfs 损坏(缺少 lib/modules/<ver>/modules.dep)或 /tmp 空间不足先针对 rootfs 运行 depmod -a -b <LFT_DST>/rootfs <ver>;检查 /tmp 的可用空间;重新运行 promote。
promote 后 DUT 启动时使用的是过期内核/模块,模块加载失败并提示 disagrees about version of symbol …,或者刷新运行后 initramfs 仍包含 customize 前的模块镜像/刷新检查未触发(在技能之外手动编辑了 <LFT_DST> 下的文件),或 rootfs/boot/Image 与 kernel/Image 不一致,导致 chroot 中的刷新针对过期内核构建运行 sudo touch <LFT_DST>/kernel/Image 后重新运行 promote,以强制触发检查;或者手动运行以下两个步骤:sudo cp -p <LFT_DST>/kernel/Image <LFT_DST>/rootfs/boot/Image && cd <LFT_DST> && sudo ./tools/l4t_update_initrd.sh。然后重新刷写。请参阅 references/kernel-image-and-initramfs.md。

规范状态

已锁定在 v0.2.0 中:

  • 双通道范围 — overlay HEAD 和构建清单;两者 均支持差异感知,且都会复制到 <bsp_image.root_path>/Linux_for_Tegra/。
  • 通道间重叠优先级 — 当 dst 冲突时,以清单为准。
  • 源代码仓库冲突检查 — 仅适用于 overlay;清单没有 远程概念,且不会获取 bsp_sources/ 下的源代码仓库 (jetson-build-source 写入清单时,其状态已固定)。
  • 原子性 — 失败即停止,不回滚。差异感知复制可自然支持 恢复。
  • 审计记录 — 仅在 promote 时输出到 stdout。overlay 跟踪器的 git 日志是通道 A 的规范记录;清单本身是通道 B 的规范记录。
  • 内核 Image 镜像 + initramfs 刷新。 两者作为配套步骤锁定。每当复制过程触及 kernel/Image,镜像步骤就会将 kernel/Image → rootfs/boot/Image;每当 kernel/Image 或任何 rootfs/lib/modules/* 被提升时,刷新步骤就会运行 tools/l4t_update_initrd.sh,重新构建 bootloader/l4t_initrd.img 和 rootfs/boot/initrd。二者不可分割,因为刷新会 chroot 到 rootfs/ 并通过 /boot/Image 解析内核,因此必须先运行镜像步骤。这可避免模块遮蔽和 vermagic 不匹配两种 故障模式;两者均支持差异感知,且仅修改 overlay 时都会跳过。完整约定见 references/kernel-image-and-initramfs.md。

仍暂缓:

  • overlay 通道的命名标签 / 提交范围。 等出现“提升版本 X”的用例时再重新考虑。
  • 清单历史记录。 目前只保留最近一次构建的清单;如果用户想将 bsp_image 回退到先前的构建状态,则需要在之前的提交上重新运行 /jetson-build-source。 按构建模式或提交保存清单归档,即可无需重新构建而实现回滚。
  • bsp_image 中的旁置清单。 等到在无法访问 overlay 跟踪器仓库(或工作区清单文件)的主机上执行提升时再重新考虑。

参考资料

评论

支持 Markdown