Dagger TypeScript SDK API 详解:ContainerWithDirectoryOpts 类型别名的五个写盘选项及其源码级行为
【免费下载链接】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 v0.20 TypeScript SDK 参考文档中的ContainerWithDirectoryOpts类型别名为主线,逐条解析exclude、include、gitignore、owner、expand五个选项的类型、语义与典型取值,并结合当前仓库中sdk/typescript/src/api/client.gen.ts的生成代码与core/schema/container.go的 schema 定义,说明该选项对象如何被Container.withDirectory方法消费、选项之间如何协同过滤写入容器的目录内容。读完后你可以直接照此在 TypeScript 模块中安全地把目录写入容器,并理解每个选项对最终镜像层/容器文件系统产生的实际影响。
一、ContainerWithDirectoryOpts 是什么
在 ContainerWithDirectoryOpts.md 这份 v0.20 参考文档中,ContainerWithDirectoryOpts被定义为一个对象类型别名(Type Alias):
ContainerWithDirectoryOpts=
object
它不是独立使用的类型,而是Container类上withDirectory方法的第三个可选参数(opts)的形状描述。其作用是:当你把一个Directory对象写入容器的指定路径时,控制“写什么、以谁的身份写、路径如何解析”。
在当前仓库的生成源码 client.gen.ts 中,该类型的实际定义(第 751–786 行)与文档一一对应:
export type ContainerWithDirectoryOpts = { /** * Patterns to exclude in the written directory (e.g. ["node_modules/**", ".gitignore", ".git/"]). */ exclude?: string[] /** * Patterns to include in the written directory (e.g. ["*.go", "go.mod", "go.sum"]). */ include?: string[] /** * Apply .gitignore rules when writing the directory. */ gitignore?: boolean /** * A user:group to set for the directory and its contents. * * The user and group can either be an ID (1000:1000) or a name (foo:bar). * * If the group is omitted, it defaults to the same as the user. */ owner?: string /** * Replace "${VAR}" or "$VAR" in the value of path according to the current environment variables defined in the container (e.g. "/$VAR/foo"). */ expand?: boolean permissions?: number }可以看到所有字段都是optional,即全部可省略;省略时按引擎默认行为处理(不做模式过滤、不套用 .gitignore 规则、不改所有权、路径不展开)。
二、五个核心选项逐一解析
2.1 include 与 exclude:白名单与黑名单
| 字段 | 类型 | 含义 |
|---|---|---|
include? | string[] | 要包含进写入目录的模式列表,例如["*.go", "go.mod", "go.sum"] |
exclude? | string[] | 要排除的模式列表,例如["node_modules/**", ".gitignore", ".git/"] |
两者都是 glob 风格模式数组,分别控制写入容器的目录中“保留什么”和“丢弃什么”:
include是白名单语义:只写入匹配任一模式的条目;exclude是黑名单语义:写入时跳过匹配任一模式的条目。
文档给出的官方示例非常典型:拷贝 Go 项目时include: ["*.go", "go.mod", "go.sum"];拷贝前端项目时exclude: ["node_modules/**", ".gitignore", ".git/"],避免把依赖目录和版本库元数据写进容器层。
2.2 gitignore:复用 .gitignore 规则
gitignore?: boolean—— “Apply .gitignore rules when writing the directory.”
设为true时,写入目录前会套用源目录中的.gitignore规则来过滤文件。这对“把 Git 工作区内容作为上下文写进容器”的场景特别有用:Git 认为应忽略的构建产物、日志、缓存,在写入容器时同样被跳过,无需手工维护一份exclude列表。
2.3 owner:写入后的属主
owner?: string的格式为user:group:
- 用户与组都支持ID 形式(
1000:1000)或名字形式(foo:bar); - 若省略组名(如
owner: "foo"),组默认与用户相同; - 该属主会应用到“目录及其全部内容”。
一个常用写法是owner: "1000:1000",保证写入的文件属主与运行阶段的非 root 用户一致,避免后续withExec以该用户执行命令时出现权限拒绝。
2.4 expand:按容器环境变量展开路径
expand?: boolean—— “Replace${VAR}or$VARin the value of path according to the current environment variables defined in the container (e.g./$VAR/foo)”。
启用后,path参数本身可以携带环境变量占位符,比如先用withEnvVariable("APP_DIR", "/opt/app")设置环境变量,再withDirectory("/$APP_DIR/data", source, { expand: true })。这使写入目标路径可以复用容器内已定义的配置,而不是在模块代码里硬编码。
2.5 与同类 Opts 的区分
withDirectory在多个对象上重载出现,但选项类型各不相同,不要混用:
Container.withDirectory使用ContainerWithDirectoryOpts(本文主题);Directory.withDirectory使用DirectoryWithDirectoryOpts(见同目录文档 DirectoryWithDirectoryOpts.md),其字段侧重permissions等目录级权限设置;Workspace.withDirectory无 opts 参数,直接withDirectory(path, source)。
在 client.gen.ts 中可以同时看到这三处重载:Container类约在第 5866 行、Directory类约在第 7168 行、Workspace类约在第 16704 行。
三、调用位置:Container.withDirectory 如何消费 opts
ContainerWithDirectoryOpts的唯一消费点是Container类的withDirectory方法。当前仓库生成代码(client.gen.ts)如下:
/** * Return a new container snapshot, with a directory added to its filesystem * @param path Location of the written directory (e.g., "/tmp/directory"). * @param source Identifier of the directory to write * @param opts.exclude Patterns to exclude in the written directory (e.g. ["node_modules/**", ".gitignore", ".git/"]). * @param opts.include Patterns to include in the written directory (e.g. ["*.go", "go.mod", "go.sum"]). * @param opts.gitignore Apply .gitignore rules when writing the directory. * @param opts.owner A user:group to set for the directory and its contents. * @param opts.inheritOwner Set the owner to the container's current user. * @param opts.expand Replace "${VAR}" or "$VAR" in the value of path according to the current environment variables defined in the container (e.g. "/$VAR/foo"). */ withDirectory = ( path: string, source: Directory, opts?: ContainerWithDirectoryOpts, ): Container => { const ctx = this._ctx.select("withDirectory", { path, source, ...opts }) return new Container(ctx) }三个要点:
- 返回新的
Container快照:withDirectory不修改原容器,而是基于当前状态派生新对象——这是 Dagger 不可变(immutable)DAG 模型的直接体现; - opts 被展开进选择上下文:
{ path, source, ...opts }会把选项平铺为withDirectory字段调用的参数(对应 GraphQL schema 中的withDirectory字段),由引擎在求值时执行实际的目录写入; - 参数顺序固定:
path是写入位置(如/tmp/directory),source是被写入的Directory对象,opts为可选过滤/属主配置。
从源码结构看,SDK 侧仅做参数打包(this._ctx.select(...)),真正的 glob 过滤、gitignore 套用、属主设置发生在引擎端;引擎侧的字段定义可参见 core/schema/container.go,其中withDirectory相关字段的inheritOwner参数带有View(AfterVersion("v1.0.0-0"))的版本门控,说明部分选项是随版本逐步加入 schema 的——阅读参考文档时应留意文档所对应的 SDK 版本。
四、实战示例:写入目录并组合多个选项
import { dagger, Directory } from "@dagger.io/dagger" const client = await dagger.connect() // 1. 准备一个目录对象(例如从 Git 仓库取源码树) const repo = client.git("https://example.com/team/app.git").branch("main").clone() const source = repo.tree() // 2. 写入容器:白名单 + 属主 + 路径变量展开组合使用 const app = client .host() .container() .withEnvVariable("APP_DIR", "/opt/app") .withDirectory( "/$APP_DIR/src", // path,配合 expand 展开 source, { include: ["*.ts", "package.json", "package-lock.json"], exclude: ["node_modules/**"], gitignore: true, owner: "1000:1000", expand: true, }, // ContainerWithDirectoryOpts ) // 3. 在写入之后以该目录工作 const result = await app .withWorkdir("/opt/app/src") .withExec(["node", "--version"]) .stdout()该示例覆盖了文档定义的全部五个选项:include/exclude控制内容范围,gitignore: true叠加.gitignore过滤,owner把写入内容属主设为1000:1000,expand: true让path中的$APP_DIR在求值时替换为环境变量值。
需要注意的适用前提:path必须是容器内绝对路径;include与exclude同时给出时,过滤语义由引擎按两者共同作用决定,建议不要同时指定相互矛盾的模式集合;owner使用名字形式时,名字必须在容器文件系统可解析(基础镜像中存在对应用户/组),使用 ID 形式则无此依赖。
五、相关类型与深入阅读
ContainerWithDirectoryOpts属于api/client.gen下client.gen.ts生成的一组 “With*Opts” 选项类型之一,同类文档与源码位置如下,均位于 client.gen.ts 或版本化文档 type-aliases 目录 内:
- 写单个文件:ContainerWithFileOpts.md(对应
Container.withFile); - 移除目录:ContainerWithoutDirectoryOpts.md(对应
Container.withoutDirectory); - 目录自身写目录:DirectoryWithDirectoryOpts.md;
- 所有权相关的引擎端集成测试(
InheritOwner等属主行为的验证方式)见 core/integration/container_test.go 与 core/integration/ownership_test.go。
小结:ContainerWithDirectoryOpts虽然只是一个对象类型别名,但它集中了“把目录写进容器”这一高频操作的全部控制面——内容过滤(include/exclude/gitignore)、属主(owner)、路径解析(expand)。理解其字段后,可直接对照 client.gen.ts 的类型定义与withDirectory方法实现,在模块代码中编写可复制、可复现的容器构建步骤。
【免费下载链接】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),仅供参考