首页/新闻资讯/正文详情

Substrate 仓库 hack/update 更新脚本体系解析:代码生成、格式整理与依赖维护的一体化工作流

发布时间:2026/9/24 12:40:56 来源:云帆数科 栏目:资讯中心
Substrate 仓库 hack/update 更新脚本体系解析:代码生成、格式整理与依赖维护的一体化工作流
人工智能AI AgentAgent 沙箱云原生容器运行时零信任【免费下载链接】substrateAgent Substrate: the core system项目地址https://gitcode.com/GitHub_Trending/substrate7/substrate点击查看免费下载本文以 SubstrateAgent Substrate仓库中 hack/update/README.md 为骨架系统讲解该目录下全部更新脚本的作用、执行顺序与底层实现并结合仓库源码剖析每条脚本的工作机制。读完本文你将掌握 Substrate 仓库一键更新工具链的完整脉络如何通过update-all.sh串联代码生成Go/Protobuf/Python/校验代码、依赖整理go mod、格式统一gofmt/clang-format与第三方许可证归档以及与之配套的 verify 校验脚本如何保证生成结果与仓库一致。一、hack/update 目录是什么原文档对目录的定位非常简洁明确This directory holds simple scripts which update the current tree in some way (e.g. generated code). Every script in this directory should have a corresponding entry in../update-all.sh.翻译过来即该目录存放以某种方式更新当前代码树的简单脚本典型如生成代码且目录中的每个脚本都必须在hack/update-all.sh中有对应入口。这个一个脚本、一个入口的约定保证了统一入口的存在开发者无需逐个记忆脚本名只要运行update-all.sh即可串行执行全部更新步骤。当前目录下共包含 5 个脚本与 1 个说明文档脚本职责对应验证脚本codegen.sh生成 Go/Protobuf/Python/校验代码verify/codegen.shgo-modules.shgo mod tidygo mod vendorverify/go-modules.shgofmt.sh对 Go 源码统一 gofmt 格式verify/gofmt.shlicenses.sh汇总第三方依赖许可证到_LICENSES/verify/licenses.shproto-fmt.sh用 clang-format 统一.proto格式verify/proto-fmt.sh可以看到仓库同时提供了对应的 hack/verify 校验脚本——更新脚本负责把代码树变成正确状态校验脚本负责检查当前代码树是否已是正确状态二者构成 CI 中的闭环。这也是 Kubernetes 等大型 Go 仓库的常见工程实践Substrate 沿用了这一模式。二、统一入口update-all.sh 如何串起全部脚本hack/update-all.sh是整个更新体系的入口其核心逻辑只有一段循环#!/usr/bin/env bash set -o errexit -o nounset -o pipefail ROOT$(git rev-parse --show-toplevel) cd ${ROOT} export LC_ALLC # for sorting to be consistent across locales # shellcheck disable2044 # for-loop over find output is intentional for F in $(find ./hack/update -name *.sh | sort); do echo Running ${F} ${F} $ done几个值得注意的实现细节严格错误处理脚本开头声明set -o errexit -o nounset -o pipefail任何一个子脚本失败都会立即终止整个更新流程避免半更新的脏状态。仓库根目录锚定通过git rev-parse --show-toplevel定位仓库根目录并cd进入因此无论从仓库哪个子目录调用脚本都能正确工作。这个模式被目录内每个脚本重复使用。排序确定性export LC_ALLC保证find结果在不同 locale 环境下排序一致避免 CI 与本地环境因排序差异产生不同的执行顺序。动态发现不是硬编码脚本清单而是用find ./hack/update -name *.sh | sort自动发现——这正是原文档每个脚本都要有对应入口约定的实现机制只要把脚本放进该目录就会自动被纳入统一更新流程。三、codegen.sh四阶段代码生成管线hack/update/codegen.sh是更新体系中最复杂的脚本内部以函数为单位组织了 4 个代码生成阶段。脚本开头注释明确强调The order of these matters - some of the codegen tools depend on the output of others顺序至关重要部分生成工具依赖其他工具的产物因此调用顺序不能随意调整。3.1 codegen::go_generateGo 通用生成function codegen::go_generate() { echo Running go generate go generate ./... } codegen::go_generate直接执行go generate ./...触发仓库中所有通过//go:generate指令标注的生成逻辑。这是 Go 生态标准的代码生成入口。3.2 codegen::protobufProtobuf 代码生成这一阶段负责把仓库内全部.proto文件编译为 Go 代码其关键逻辑包括候选文件收集使用git ls-files -cm --exclude-standard找出被 git 跟踪cached或新增未跟踪others的.proto文件同时通过:!:路径排除规则明确剔除vendor/*、third_party/*、_LICENSES/*——这些目录要么是第三方依赖要么是许可证归档都不应参与代码生成。按目录去重将每个 proto 文件路径dirname后sort | uniq得到需要执行 protoc 的目录列表。工具链版本钉死通过hack/run-tool.sh获取protoc-gen-go与protoc-gen-go-grpc的可执行路径。run-tool.sh将工具名映射到hack/tools/下各自的独立 Go module 目录如code-generator、protoc-gen-go再用go tool -n解析出实际二进制路径——这样每个生成工具的版本都由仓库内的 go.mod 精确锁定保证任何机器生成结果一致。protoc 调用在 proto 文件所在目录内执行hack/protoc.sh生成参数为${ROOT}/hack/protoc.sh \ -I ${ROOT} -I . \ --pluginprotoc-gen-go${protoc_gen_go} \ --pluginprotoc-gen-go-grpc${protoc_gen_go_rpc} \ --go_outpathssource_relative:. \ --go-grpc_outpathssource_relative:. \ ./*.protopathssource_relative意味着生成的.pb.go与源.proto放在同一目录保持仓库布局整洁。仓库中通过该流程维护的 proto 包括 pkg/proto/ateapipb、pkg/proto/credproviderpb、internal/proto 等目录下的定义。关于 protoc 本身hack/protoc.sh做了值得借鉴的可复现性处理钉死 protoc 版本当前为 25.3并对四个平台linux-x86_64、linux-aarch_64、osx-x86_64、osx-aarch_64的发布包硬编码 SHA-256 校验值。首次运行时下载 protoc 压缩包并校验哈希不匹配则直接失败退出之后复用本地bin/protoc-install/bin/protoc避免 CI 与开发者机器上 protoc 版本漂移导致的生成结果不一致。3.3 codegen::pythonPython gRPC 客户端生成Substrate 的负载测试benchmarking/locust需要 Python 版的 proto 客户端这一阶段用grpc_tools.protoc生成function python_proto() { local out_dir$1 proto_path$2 proto_base$3 python3 -m grpc_tools.protoc \ -I${proto_path} \ --python_out${out_dir}/ \ --grpc_python_out${out_dir}/ \ ${proto_path}/${proto_base}.proto ... } codegen::python # 依次生成 pkg/proto/ateapipb 的 ateapi 与 internal/proto/glutton 的 glutton这里有两个值得展开的实现细节独立虚拟环境脚本注释明确解释了原因——compiling a .proto needs only grpcio-tools, and the runtime list would drag in locust, the opentelemetry exporters and google-cloud-storage for nothing编译 proto 只需要 grpcio-tools运行时依赖列表会把 locust、OpenTelemetry 导出器、google-cloud-storage 等无谓地拖进来。因此编译环境放在benchmarking/locust/codegen/venv与负载测试的运行时依赖隔离。虚拟环境的创建与同步复用hack/util/venv.sh中的ensure_venv与venv_sync_requirements辅助函数。许可证头与导入重写生成出的_pb2.py/_pb2_grpc.py会拼接hack/boilerplate/sh.txt的许可证头同时用sed把import foo_pb2 as foo__pb2改写为from . import foo_pb2 as foo__pb2使相对导入在common包下可解析。脚本特意通过临时文件完成替换因为注释指出sed -i在 GNU 与 BSD 下写法不同这是跨平台兼容性的细节考量。3.4 codegen::validation校验代码生成最后一段通过git grep -l k8s:validation-gen在**/doc.go中搜索带有该标记的包对每个命中目录运行仓库自带的validation-gen工具./hack/run-tool.sh validation-gen \ --go-header-file${GO_BOILERPLATE} \ --output-filezz_generated.validation.go \ --readonly-pkggoogle.golang.org/protobuf/types/known/timestamppb \ --readonly-pkggoogle.golang.org/protobuf/types/known/fieldmaskpb \ --readonly-pkggoogle.golang.org/protobuf/types/known/emptypb \ ./${dir}生成结果统一写入zz_generated.validation.go并使用hack/boilerplate/go.txt作为 Go 代码许可证头。--readonly-pkg声明的 protobuf 已知类型timestamppb、fieldmaskpb、emptypb在生成校验逻辑时会被当作只读外部类型处理。四、go-modules.sh依赖图的收敛hack/update/go-modules.sh全脚本只有三行有效逻辑go mod vendor go mod tidy先go mod tidy根据当前源码中的 import 关系增删go.mod/go.sum条目再go mod vendor把依赖源码物化到vendor/目录。注意顺序是先 vendor 后 tidy——这与多数人的直觉相反但脚本注释并未说明原因从仓库结构看vendor/被 codegen.sh、gofmt.sh、proto-fmt.sh 统一排除在文件收集范围之外说明项目对 vendor 目录采取了不参与生成、不参与格式化的隔离策略。仓库同时提供了对应的 verify/go-modules.sh 用于 CI 中校验依赖状态。五、gofmt.shGo 代码格式统一hack/update/gofmt.sh负责格式化所有 Go 源码有三个实现要点gofmt 版本与工具链一致脚本注释专门指出 GOTOOLCHAIN has no effect on the version of gofmtGOTOOLCHAIN 环境变量不影响 gofmt 版本因此通过go env GOROOT定位与当前 Go 工具链绑定的 gofmtgofmt$(go env GOROOT)/bin/gofmt if [[ ! -x ${gofmt} ]]; then echo Failed to find $gofmt 2 exit 1 fi避免 PATH 中的旧 gofmt 与当前 Go 版本行为不一致。文件收集与 codegen 一致同样使用git ls-files -cmo --exclude-standard收集**/*.go并排除vendor/*、third_party/*、_LICENSES/*按目录去重后逐个执行gofmt -s -w。-s启用简化模式simplify-w直接写回文件。目录级执行以目录为单位批量格式化减少进程启动开销。六、proto-fmt.shProtobuf 格式统一hack/update/proto-fmt.sh使用clang-format统一.proto文件格式。脚本先检查clang-format是否在 PATH 中不在则报错退出。随后用与 gofmt.sh 相同的git ls-files收集逻辑获取全部 proto 文件执行${clangfmt} \ -i \ --style{BasedOnStyle: LLVM, ColumnLimit: 0} \ ${files[]}两个值得注意的细节基于 LLVM 风格但ColumnLimit: 0表示不重排长行。脚本注释解释了原因Dont reflow long lines, since those tend to be comments which then require re-running the proto generators, which makes update-all awkward——长行通常是注释重排它们会改变注释内容进而触发 proto 代码重新生成破坏 update-all 的幂等性。与 gofmt 不同这里直接使用 PATH 中的 clang-format 而非仓库内钉死版本是一个相对宽松的前提脚本也明确提示请确保它在你的 PATH 中。七、licenses.sh第三方许可证的机器可读归档hack/update/licenses.sh是合规性保障的关键脚本将全部第三方依赖的许可证汇总到仓库根目录的_LICENSES/environment 中可见该目录下按github.com/...、k8s.io/...、golang.org/x/...等模块路径组织的完整归档树。其工作流程分为两大部分7.1 go-licenses 扫描模块依赖脚本通过hack/run-tool.sh获取go-licenses工具并对 4 个发布目标平台分别扫描targets( linux/amd64 linux/arm64 darwin/amd64 darwin/arm64 )因为不同 GOOS/GOARCH 组合实际编译引入的依赖集合可能不同多目标扫描保证所有发布形态的许可证都被覆盖。每次扫描使用mktemp创建的临时输出目录trap ... EXIT确保异常退出时清理。其中有一个值得注意的工程 hackgo-licenses 工具较老无法正确处理 Go module replacement 等场景脚本通过临时创建go.work并设置GOWORK环境变量来规避该问题对应注释 This trick somehow overcomes that。此外还处理了 go-licenses 的一个已知 bug——扫描结果中把本仓库自身github.com/agent-substrate/substrate也纳入循环引用需要手动删除rm -rf ${tmp_out}/github.com/agent-substrate/substrate7.2 third_party 内嵌源码的许可证镜像go-licenses 只覆盖 module 依赖而仓库third_party/下内嵌的第三方源码例如 hack/third_party/csi-driver-host-path、hack/third_party/kubernetes被视为 first-party不会被扫描到。为此脚本用git ls-files找出所有路径匹配(licen[sc]e|notice|copying)的文件将其镜像到_LICENSES/third_party/相对路径下例如_LICENSES/third_party/kata/agentpb/LICENSE。注释说明该做法参考了 Kubernetes 的hack/update-vendor-licenses.sh最终再find -type d -empty -delete清理空目录。八、更新与验证的闭环verify 脚本如何保证一致性原文档强调 update 脚本的对应入口在update-all.sh而仓库对称地提供了 hack/verify-all.sh 及 hack/verify 目录作为校验侧。以 verify/codegen.sh 为例./hack/third_party/kubernetes/verify-generated.sh codegen $它复用 Kubernetes 社区的verify-generated.sh模式在临时副本中执行 codegen 更新再与当前工作树对比若存在差异则报错从而在 CI 中强制要求代码生成产物必须已提交。类似地verify 目录下还有 go-modules.sh、gofmt.sh、licenses.sh、proto-fmt.sh、boilerplate.sh 等校验脚本见 hack/verify/README.md与 update 侧一一对应。九、开发者实操指南基于以上源码分析日常开发中与更新体系相关的高频操作如下全量更新代码树提交 PR 前推荐./hack/update-all.sh该命令会按顺序执行 codegen → go-modules → gofmt → licenses → proto-fmt 全部更新脚本。注意 prerequisites需要 Go 工具链、clang-format位于 PATHproto-fmt 使用、网络可访问protoc 首次下载、pip 安装 grpcio-tools。仅执行单个更新步骤./hack/update/codegen.sh # 只重新生成代码 ./hack/update/gofmt.sh # 只格式化 Go 代码 ./hack/update/proto-fmt.sh # 只格式化 proto 文件 ./hack/update/go-modules.sh # 只整理依赖 ./hack/update/licenses.sh # 只重新归档许可证验证代码树是否处于已更新状态CI 也会执行./hack/verify-all.sh修改 proto 后手动运行./hack/update/codegen.sh重新生成 Go/Python 客户端生成产物提交入库protoc版本由 hack/protoc.sh 钉死为 25.3 并做 SHA-256 校验。十、总结这套更新体系的设计启示从源码结构看Substrate 的 hack/update 体系体现了几个可复用的工程原则单一入口 自动发现update-all.sh通过find自动发现脚本新增更新步骤只需放一个.sh文件进目录无需修改入口脚本生成结果确定性protoc 版本与 SHA 校验、go env GOROOT定位 gofmt、hack/tools独立 module 锁定 codegen 工具版本、LC_ALLC保证排序稳定层层保障任何机器上跑出的结果一致更新与校验对称每个 update 脚本都有对应 verify 脚本使 CI 能以生成后对比差异的廉价方式拦截未提交的生成产物依赖隔离vendor、third_party、_LICENSES 被统一排除在格式化与代码生成的文件收集之外避免工具互相干扰。这套更新脚本 验证脚本的目录约定正是大型 Go 仓库中维护代码生成产物、依赖与许可证一致性的典型范本值得在类似规模的工程中借鉴。赞分享人工智能AI AgentAgent 沙箱云原生容器运行时零信任【免费下载链接】substrateAgent Substrate: the core system项目地址https://gitcode.com/GitHub_Trending/substrate7/substrate点击查看免费下载相关推荐Kubernetes 源码贡献指南hack 目录脚本体系与 make verify / make update 校验工作流深度解析Kubernetes 源码贡献指南hack 目录脚本体系与 make verify / make update 校验工作流深度解析 本文以 Kubernete云原生容器编排集群管理微服务lazygit 依赖库 sys/unix 代码生成体系解析从构建脚本到 z 开头生成文件的完整链路lazygit 依赖库 sys/unix 代码生成体系解析从构建脚本到 z 开头生成文件的完整链路 本文以 lazygit 仓库中 vendor 的 gola开发工具CLI版本控制K3s 依赖自动化升级体系基于 Updatecli 的多仓库版本维护实践K3s 依赖自动化升级体系基于 Updatecli 的多仓库版本维护实践 Updatecli 是 K3s 项目用来自动化编排安全相关更新与版本升级的核心工具。云原生容器编排集群管理边缘计算容器运行时创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

SoC天梯图:多维动态建模的手机芯片性能评估方法
SoC天梯图:多维动态建模的手机芯片性能评估方法

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 12:40:56

信道预算与均衡设计:通信链路的信号能量账本与波形整形术
信道预算与均衡设计:通信链路的信号能量账本与波形整形术

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 12:40:50

AI公司现金流建模:大模型研发成本测算与财务预测方法
AI公司现金流建模:大模型研发成本测算与财务预测方法

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 12:40:50

非接触式生命体征监测技术全景解析:从雷达到IPPG的工程实践
非接触式生命体征监测技术全景解析:从雷达到IPPG的工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 13:12:31

如何把云边协同讲透:从云计算定义到边缘计算案例的PPT讲解指南
如何把云边协同讲透:从云计算定义到边缘计算案例的PPT讲解指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 13:12:31

模拟芯片ESD防护版图设计实战指南
模拟芯片ESD防护版图设计实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 13:12:31

perf与strace实战:高效定位生产环境性能瓶颈
perf与strace实战:高效定位生产环境性能瓶颈

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 13:12:25

VSCode+EIDE:国产MCU嵌入式开发新范式
VSCode+EIDE:国产MCU嵌入式开发新范式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 13:12:19

为什么智能对话设备离不开STM32
为什么智能对话设备离不开STM32

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 13:12:19

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码