Dagger TypeScript SDK 中的 CurrentModuleWorkdirOpts 详解:模块工作目录的过滤与读取
【免费下载链接】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 是面向构建、测试与交付任意代码库的自动化引擎,可在本地、CI 或云端直接运行。本文聚焦 Dagger 0.21 版本 TypeScript SDK 中用于控制模块临时工作目录(scratch working directory)读取行为的CurrentModuleWorkdirOpts类型别名,讲解其三个可选属性的语义与用法,并结合仓库源码剖析从 GraphQL 到引擎实现的完整链路,帮助你在编写 Dagger 模块时精准控制目录内容的读取范围。
类型别名概览
CurrentModuleWorkdirOpts是 Dagger TypeScript SDK 自动生成的 API 类型之一,定义在 sdk/typescript/src/api/client.gen.ts。它作为CurrentModule.workdir()方法的可选参数类型,用于在模块函数执行期间,从模块的"临时工作目录"(scratch working directory)加载一个目录,并对其内容施加过滤规则。
其类型签名如下:
export type CurrentModuleWorkdirOpts = { /** * Exclude artifacts that match the given pattern (e.g., ["node_modules/", ".git*"]). */ exclude?: string[] /** * Include only artifacts that match the given pattern (e.g., ["app/", "package.*"]). */ include?: string[] /** * Apply .gitignore filter rules inside the directory */ gitignore?: boolean }三个属性均为可选(optional),这意味着当你调用workdir()而不传入任何选项时,引擎会返回临时工作目录的全部内容。
三个过滤选项的语义
exclude:排除匹配模式的文件
exclude接受字符串数组,数组中的每个元素是一个匹配模式,用于排除符合条件的文件与目录。官方示例给出了两种典型场景:
"node_modules/":排除依赖安装目录,避免把庞大的第三方依赖带入构建上下文;".git*":排除所有以.git开头的文件或目录(如.git/、.gitignore、.gitmodules),防止版本库元数据被读取。
该模式与 Dagger 目录过滤使用的 pattern 语法一致,支持目录后缀(/)与通配符(*)。需要特别注意的是,exclude与include不是简单的"先排除再包含"关系,二者是同一过滤器的两个维度,使用时需结合具体场景设计,避免规则互相冲突导致结果与预期不符。
include:仅保留匹配模式的文件
include同样接受字符串数组,语义与exclude相反——只保留与给定模式匹配的内容。官方示例:
"app/":只保留app目录;"package.*":只保留以package.开头的文件(如package.json、package-lock.json)。
当需要从工作目录中挑选特定子集(例如只读取配置文件,忽略源码)时,include比exclude更高效、更安全,因为它天然限制了暴露范围。
gitignore:应用 .gitignore 过滤规则
gitignore是布尔开关,默认不启用。置为true后,引擎会在目录内部应用.gitignore中定义的过滤规则,读取结果将自动剔除被忽略的文件。
在真实模块场景中,node_modules/、dist/、build/、日志文件等通常都已被写进.gitignore,因此启用该选项往往可以一劳永逸地完成大部分过滤工作,再配合exclude补充规则即可覆盖全部需求。
实战:在 Dagger 模块函数中使用 workdir
CurrentModuleWorkdirOpts的消费方是CurrentModule.workdir()方法,其签名定义于 sdk/typescript/src/api/client.gen.ts:
/** * Load a directory from the module's scratch working directory, including any changes that may have been made to it during module function execution. * @param path Location of the directory to access (e.g., "."). * @param opts.exclude Exclude artifacts that match the given pattern (e.g., ["node_modules/", ".git*"]). * @param opts.include Include only artifacts that match the given pattern (e.g., ["app/", "package.*"]). * @param opts.gitignore Apply .gitignore filter rules inside the directory */ workdir = (path: string, opts?: CurrentModuleWorkdirOpts): Directory => { const ctx = this._ctx.select("workdir", { path, ...opts }) return new Directory(ctx) }该方法返回一个Directory对象,可以继续链式调用 Dagger 的目录 API。一个典型的使用场景是:模块函数执行过程中在临时工作目录里生成了构建产物,随后需要把这些产物读取出来交给后续容器使用。
import { dag, Directory } from "@dagger.io/dagger" export function collectOutputs(): Directory { // 读取临时工作目录下的 "dist" 目录, // 只保留构建产物,忽略调试文件与版本库元数据 return dag.currentModule() .workdir("dist", { include: ["app/", "package.*"], exclude: ["*.map", ".git*"], gitignore: true, }) }与之配套的还有workdirFile()方法(client.gen.ts),用于直接以File形式读取临时工作目录中的单个文件,适合读取如README.md、package.json这类已知路径的文件。
值得注意的是,workdir()与workdirFile()读取的是模块的临时工作目录,其中包含模块函数执行期间对该目录所做的改动;这与CurrentModule.source()(模块源码目录)是两回事,后者只反映加载进引擎的模块源码。
底层原理:从 GraphQL 到引擎实现
GraphQL Schema 定义
Dagger 的所有 SDK API 都由统一 GraphQL Schema 生成。workdir字段在 schema 中的定义见 core/schema/testdata/base_schema.graphqls:
""" Load a directory from the module's scratch working directory, including any changes that may have been made to it during module function execution. """ workdir( """Location of the directory to access (e.g., ".").""" path: String! """ Exclude artifacts that match the given pattern (e.g., ["node_modules/", ".git*"]). """ exclude: [String!] = [] """ Include only artifacts that match the given pattern (e.g., ["app/", "package.*"]). """ include: [String!] = [] """Apply .gitignore filter rules inside the directory""" gitignore: Boolean = false ): Directory!这里给出了两个关键默认值:exclude、include默认均为空数组[],gitignore默认为false。也就是说,不带任何选项调用workdir()时,读取的是过滤前的完整目录内容。
引擎端实现与安全校验
服务端由currentModuleWorkdir函数处理,实现在 core/schema/module.go:
func (s *moduleSchema) currentModuleWorkdir( ctx context.Context, curMod dagql.ObjectResult[*core.CurrentModule], args struct { Path string core.CopyFilter }, ) (inst dagql.Result[*core.Directory], err error) { ... if !filepath.IsLocal(args.Path) { return inst, fmt.Errorf("workdir path %q escapes workdir", args.Path) } args.Path = filepath.Join(sdk.RuntimeWorkdirPath, args.Path) ... }这段实现揭示了三个重要细节:
- 安全边界:传入的
path必须先通过filepath.IsLocal()校验,任何试图逃逸临时工作目录的路径(如../、绝对路径)都会被拒绝,并返回workdir path "..." escapes workdir错误; - 路径拼接:合法的相对路径会被拼接在
sdk.RuntimeWorkdirPath之下,定位到引擎为当前模块建立的运行时工作目录; - 过滤参数直通:
exclude、include、gitignore三个参数通过core.CopyFilter结构体接收(core/directory.go),其 Go 定义与 TypeScript 类型一一对应,并再次确认默认值为Exclude: []、Include: []、Gitignore: false,最终转发给host.directory完成实际的目录挂载与过滤。
使用建议与注意事项
综合类型定义、schema 默认值与引擎实现,以下几点在实际使用中值得留意:
- 默认行为:不传
opts时读取完整目录,若工作目录内容庞大(含node_modules等),会显著增加引擎 IO 与内存开销,建议始终显式传入过滤选项; - 优先
include:当只需要少量明确文件时,用include白名单比exclude黑名单更安全,可有效防止意外泄露或误读无关内容; - 善用
gitignore:对于遵循.gitignore约定的项目,gitignore: true是最省力的基线过滤,再叠加exclude补充未纳入 gitignore 的临时产物; - 路径安全:
path只接受workdir内的相对路径,绝对路径或含..的路径会被引擎拒绝,调用前可在代码中自行校验; - 配套方法:读取单个文件优先使用
workdirFile(),避免为单文件读取挂载整个目录。
参考资源
- 类型定义与调用方法:sdk/typescript/src/api/client.gen.ts
- GraphQL Schema:core/schema/testdata/base_schema.graphqls
- 引擎端实现:core/schema/module.go
- 过滤参数结构体:core/directory.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),仅供参考