登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  Golang >  Go教程

go list -json 怎样查看包包含的嵌入文件

来源:17golang原创

时间:2026-10-13 02:10:26 394浏览 收藏

我第一次给静态资源检查器接入 Go 包时,原本想扫描源码里的 //go:embed,很快就遇到两个麻烦:模式不等于最终文件,而且测试包里的资源很容易被漏掉。更稳妥的入口是让 go list -json 直接输出包元数据。

先给结论:EmbedPatterns 记录普通包声明过的嵌入模式,EmbedFiles 记录这些模式实际匹配到的文件;测试代码则分别看 TestEmbed* 和 XTestEmbed*。用字段选择器请求这六组字段,就能把结果交给检查脚本。

官方文档:https://pkg.go.dev/cmd/go

先分清你要找的是模式,还是文件

这两个字段看起来相近,但用途不同。模式回答“源码声明了什么”,文件回答“工具链解析后认为哪些文件被包含”。例如 web/* 是模式,web/index.html 和 web/app.css 才是匹配文件。

go list JSON 中嵌入模式与实际文件清单的关系说明图
图1:从 go:embed 模式到 EmbedFiles 文件清单的字段关系说明图,不是运行截图。

如果检查器只关心“有哪些资源会进入包”,优先读取 EmbedFiles;如果还要提示模式过宽、模式变更或测试覆盖范围,再同时保留 EmbedPatterns。

先准备一个包含普通资源和测试资源的包

为了看清字段分组,可以准备一个很小的目录。普通包、同包测试和外部测试分别放一个嵌入声明:

package assets

import "embed"

// 普通包资源由 embed.FS 持有,供正式代码读取。
//go:embed web/*
var WebFiles embed.FS
package assets

import _ "embed"

// 同包测试资源会进入 TestEmbedPatterns 和 TestEmbedFiles。
//go:embed testdata/internal.txt
var internalFixture string
package assets_test

import _ "embed"

// 外部测试包资源会进入 XTestEmbedPatterns 和 XTestEmbedFiles。
//go:embed testdata/external.txt
var externalFixture string

这里的重点不是变量最后怎样使用,而是三类源文件的边界:普通 Go 文件、包内的 _test.go 文件,以及包外测试包的 _test.go 文件。

用 go list -json 查看普通包的嵌入文件

在模块根目录执行下面的命令。字段选择器让输出聚焦在嵌入信息,避免把依赖列表等无关包元数据一并交给后续脚本:

# 只请求六组嵌入字段,包路径按实际目录替换
go list -json=EmbedPatterns,EmbedFiles,TestEmbedPatterns,TestEmbedFiles,XTestEmbedPatterns,XTestEmbedFiles ./assets

普通包至少会关注下面两组字段。实际 JSON 中没有内容的字段可能不会出现,因此消费端不要把“字段缺失”直接当作错误:

{
  "EmbedPatterns": ["web/*"],
  "EmbedFiles": [
    "web/app.css",
    "web/index.html"
  ]
}

EmbedFiles 是相对包目录的文件名列表,适合做资源清单、许可证扫描或发布前的静态检查。它不是运行时读取结果,也不替代 embed.FS 的访问逻辑。

测试资源要看 TestEmbed 和 XTestEmbed

这是我后来补检查器时最容易漏掉的一点。包内测试文件产生 TestEmbedPatterns 与 TestEmbedFiles;外部测试包产生 XTestEmbedPatterns 与 XTestEmbedFiles。它们不会自动合并到普通包的 EmbedFiles 中。

go list 将普通包、包内测试和外部测试资源分组的结构示意图
图2:普通包、内部测试包和外部测试包对应不同 JSON 字段,是测试资源分组示意图。

想快速确认三组文件,可以把输出保留为 JSON,再按字段读取。不要只搜索所有文件名,因为同名资源可能来自不同测试组:

# 保存包元数据,后续脚本按字段区分正式资源与测试资源
go list -json=EmbedPatterns,EmbedFiles,TestEmbedPatterns,TestEmbedFiles,XTestEmbedPatterns,XTestEmbedFiles ./assets > package-embed.json

如果你的工具只需要打印摘要,也可以用模板减少人工阅读量:

# 只打印三类实际文件,空切片会保持为空
go list -f '{{.EmbedFiles}} {{.TestEmbedFiles}} {{.XTestEmbedFiles}}' ./assets

把 JSON 接入资源检查器时,按字段做三层判断

我会把检查逻辑拆成三步:先判断包是否成功加载,再收集普通包资源,最后按需追加两类测试资源。这样既不会把加载错误伪装成“没有嵌入”,也能让调用方选择是否纳入测试文件。

type EmbedInventory struct {
	EmbedFiles      []string
	TestEmbedFiles  []string
	XTestEmbedFiles []string
}

// mergeFiles 只合并已经由 go list 解析出的文件名,不重新扫描源码。
func mergeFiles(info EmbedInventory, includeTests bool) []string {
	files := append([]string{}, info.EmbedFiles...)
	if !includeTests {
		return files
	}
	files = append(files, info.TestEmbedFiles...)
	files = append(files, info.XTestEmbedFiles...)
	return files
}

上面这个结构只展示消费端的边界。真实调用还应保留 go list 的退出状态和标准错误:包加载失败、嵌入模式找不到匹配文件时,应该报告失败原因,而不是生成一个空清单。

几个容易误判的边界

现象应该怎样理解
只有 EmbedPatterns,没有 EmbedFiles先检查字段是否被请求;若请求了文件字段,再看模式是否匹配到文件。
普通包清单为空可能只是该包没有正式资源,不代表测试资源也为空。
测试文件没有出现在 EmbedFiles读取 TestEmbedFiles 或 XTestEmbedFiles,按测试包类型分别处理。
命令直接失败保留 stderr 和退出码;模式无匹配文件属于输入或包状态问题,不应静默吞掉。

还有一个实际取舍:发布清单通常只收集 EmbedFiles,测试报告则可以把两类测试字段并入结果。把这两个用途分开,输出会更容易读,也不容易把测试夹具误打进正式资源包。

最后的使用判断

如果目标是查看 Go 包到底包含哪些嵌入文件,优先记住这一条命令:

# 让 go 命令负责解析 embed 模式,再输出可供脚本消费的 JSON
go list -json=EmbedPatterns,EmbedFiles,TestEmbedPatterns,TestEmbedFiles,XTestEmbedPatterns,XTestEmbedFiles ./assets

只看正式资源时读 EmbedFiles;要覆盖测试夹具,再读 TestEmbedFiles 和 XTestEmbedFiles。对我来说,这比手工扫描 //go:embed 更稳定,因为“声明的模式”和“实际匹配的文件”都由同一个包加载过程给出。

相关问题:

  • 为什么不能只读取 EmbedPatterns? 因为模式是声明,文件清单才是解析后的具体结果。
  • 测试资源为什么要分两组? Go 区分包内测试文件和外部测试包,列表字段也保持了这个边界。
  • 是否应该把测试文件发布出去? 通常不应该;让检查器用开关决定是否把测试字段纳入分析。
声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>