Dagger TypeScript SDK 中 DirectoryFilterOpts 类型别名详解:用 include / exclude / gitignore 精准裁剪目录快照
【免费下载链接】daggerAutomation engine to build, test and ship any codebase. Runs locally, in CI, or directly in the cloud项目地址: https://gitcode.com/GitHub_Trending/da/dagger
本篇技术指南围绕 Dagger 0.21 版本 TypeScript SDK 参考文档中的DirectoryFilterOpts类型别名展开,系统讲解该类型的三个可选属性(include、exclude、gitignore)的语义、glob 匹配规则与组合用法,并结合仓库源码剖析Directory.filter从 SDK 层到 GraphQL 层再到引擎层(CopyFilter/ layercopy)的完整调用链。读完本文,你将能够在 Dagger 管道中精准地裁剪目录快照——无论是剔除node_modules与密钥文件,还是只保留指定子目录与清单文件,都能以最小代价、可验证的方式落地。
DirectoryFilterOpts 是什么
DirectoryFilterOpts是 Dagger TypeScript SDK 中为Directory.filter方法(即DirectoryID.filterGraphQL 字段)提供的选项对象类型。它的定义位于版本化文档目录 DirectoryFilterOpts.md,对应生成代码 client.gen.ts 中的:
export type DirectoryFilterOpts = { exclude?: string[] gitignore?: boolean include?: string[] }它本身是一个 TypeScriptobject类型别名,所有属性均为可选。调用的本质是:对目录做一次“快照过滤”,生成一个仅包含(或剔除)部分路径的新目录快照,原目录不变(不可变快照模型)。
该类型被Directory.filter方法消费,方法签名与实现见 client.gen.ts:
filter = (opts?: DirectoryFilterOpts): Directory => { const ctx = this._ctx.select("filter", { ...opts }) return new Directory(ctx) }可以看到,选项对象被原样展开为 GraphQL 查询参数,通过_ctx.select("filter", ...)构建惰性查询节点,最终返回一个新的Directory对象——这就是 Dagger 典型的“声明式、惰性求值”调用方式:此处只是登记操作,真正的过滤在引擎执行查询时才发生。
三个可选属性详解
exclude:排除匹配 glob 的路径
- 类型:
string[] - 含义:设置后,匹配其中任一 glob 模式的路径会被从新快照中排除。
- 文档示例:
["node_modules/", ".git*", ".env"]
常见用法是过滤掉依赖目录、版本控制目录和敏感文件。注意 glob 语义:node_modules/带尾部斜杠表示目录;.git*覆盖.git目录及.gitignore等衍生文件;.env用于剔除密钥/环境配置文件。
include:仅保留匹配 glob 的路径
- 类型:
string[] - 含义:设置后,只有匹配其中任一 glob 模式的路径会被保留进新快照,其余一律剔除。
- 文档示例:
["app/", "package.*"]
典型场景是“白名单式”提取:只把应用源码目录与包清单拷进构建上下文,例如["app/", "package.*"]会保留app/目录及其全部子内容,以及package.json、package-lock.json这类以package.开头的文件。
gitignore:应用 .gitignore 规则
- 类型:
boolean - 含义:为
true时,过滤过程会读取目录内的.gitignore规则并据此排除匹配路径。
相当于把仓库已声明“不该提交”的内容(构建产物、缓存、本地配置)一并排除,省去手工罗列exclude模式。
组合语义与匹配规则
- 三者皆可组合:
include与exclude同时给出时,先按include圈定候选集合,再以exclude剔除其中命中的路径;gitignore与exclude的命中结果共同参与剔除。 - 全部省略时的行为:三个属性都缺省时,过滤器为空操作——引擎层对空过滤器的判定见 core/directory.go 的
CopyFilter.IsEmpty():仅当exclude、include均无元素且gitignore为false时返回true,此时filter退化为返回原目录(可推断:IsEmpty是底层跳过过滤逻辑的判据)。 - glob 为空串或以
!开头:从底层解析看,空模式与取反模式会被跳过,不会参与匹配(见 core/directory.goresolveAttemptUnpackMatches中if includePattern == "" || strings.HasPrefix(includePattern, "!")的守卫逻辑)。
底层实现:从 TypeScript 到引擎的调用链
1. TypeScript SDK 层
生成代码 client.gen.ts 中filter方法的 JSDoc 注释与文档完全一致,属性名通过{ ...opts }直接映射为 GraphQL 参数。
2. GraphQL Schema 层(core/schema)
在 core/schema/directory.go 中,Directory.filter被声明为 dagql 节点函数,三个参数分别带文档注释:
dagql.NodeFunc("filter", maintainContentHashing(s.filter)). Doc(`Return a snapshot with some paths included or excluded`). Args( dagql.Arg("exclude").Doc(`If set, paths matching one of these glob patterns is excluded from the new snapshot. Example: ["node_modules/", ".git*", ".env"]`), dagql.Arg("include").Doc(`If set, only paths matching one of these glob patterns is included in the new snapshot. Example: (e.g., ["app/", "package.*"]).`), dagql.Arg("gitignore").Doc(`If set, apply .gitignore rules when filtering the directory.`), )Schema 层的filter实现(core/schema/directory.go)把三个参数打包为FilterArgs(内嵌core.CopyFilter),再以exclude/include/gitignore命名输入的方式转发给内部目录节点——这也解释了为何参数在 GraphQL 中同名可见。
3. 引擎层(core.CopyFilter)
真正承载过滤语义的是核心结构体 core/directory.go:
type CopyFilter struct { Exclude []string `default:"[]"` Include []string `default:"[]"` Gitignore bool `default:"false"` }CopyFilter同时被Directory.WithDirectory(core/directory.go)等复制类操作复用,说明“include/exclude/gitignore”是一套跨 API 统一的过滤原语:filter是它的独立入口,withDirectory合并目录时也走同一套匹配逻辑。
4. 测试佐证
core/schema/workspace_test.go 中的TestWorkspaceFilterWithDirectoryArgs构造core.CopyFilter{Include: []string{"app/**"}, Exclude: []string{".git"}},断言生成的 dagql 参数依次为path、source、include、exclude——证实include/exclude的透传关系与参数顺序,可作为阅读实现时的对照样例。
实战示例:在 Dagger 管道中过滤目录
以下示例展示如何结合 Dagger 的host.directory、Directory.filter与container.withDirectory构建一个“只带源码、不带噪音”的构建上下文:
import { dag, Directory } from "@dagger.io/dagger" // 1. 读取主机目录(本地仓库根) const src = dag.host().directory(".") // 2. 过滤:只保留 app/ 与 package.*,同时剔除 node_modules 与 .git* const filtered: Directory = src.filter({ include: ["app/", "package.*"], exclude: ["node_modules/", ".git*", ".env"], }) // 3. 若目录内有 .gitignore,可直接声明式启用其规则 const withGitignore: Directory = src.filter({ gitignore: true, exclude: [".env"], }) // 4. 将过滤后的目录作为构建上下文挂载进容器 const ctr = dag .container() .from("node:22-alpine") .withDirectory("/work", filtered) .withWorkdir("/work")要点回顾:
filter是惰性声明,返回新的Directory,不会修改原目录;- 单一
include场景下,快照只含匹配项(白名单);exclude与gitignore负责黑名单剔除; - 过滤结果可直接交给
Container.withDirectory、Directory.export或作为后续缓存键参与哈希(Schema 层以maintainContentHashing包装filter,保证内容哈希稳定性); - 该类型同样适用于
withDirectory场景中的DirectoryWithDirectoryOpts(其 Go 运行时对应结构见 dagger.gen.go),同一套过滤语义可复用于目录合并。
相关文档与进一步阅读
- 类型别名官方参考:DirectoryFilterOpts.md
- TypeScript SDK 生成代码中
Directory.filter的实现与 JSDoc:client.gen.ts - GraphQL Schema 层
filter节点定义与实现:core/schema/directory.go - 引擎层过滤原语
CopyFilter及其判空逻辑:core/directory.go - 过滤参数透传的测试样例:core/schema/workspace_test.go
【免费下载链接】daggerAutomation engine to build, test and ship any codebase. Runs locally, in CI, or directly in the cloud项目地址: https://gitcode.com/GitHub_Trending/da/dagger
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考