
Dagger TypeScript SDK 中的 Exportable 接口把容器、目录与文件导出到宿主机的统一抽象【免费下载链接】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 参考文档中的Exportable接口页面展开。Dagger 是一个在本地、CI 或云端运行的自动化引擎其 TypeScript SDK 把核心对象统一建模为带id()的 GraphQL 客户端。Exportable接口是其中“从引擎侧向宿主机侧取回数据”的关键抽象凡是实现了该接口的对象Container、Directory、File、Changeset都可以调用export()把自己写入宿主机文件系统的指定路径。读完本文你将掌握Exportable接口的签名语义、各具体类型的export()参数差异、客户端代码生成的内部机制以及在实际 TypeScript 代码中正确使用它的姿势与限制。接口定义两个方法一个契约0.21 版文档 Exportable 接口参考页给出的接口定义非常精炼An object that can be exported to the host.一个可以导出到宿主机的对象。Calling export writes the object to a path on the host filesystem and returns the path that was written.调用 export 会把对象写入宿主机文件系统的某个路径并返回被写入的路径。该接口包含且仅包含两个方法方法签名说明export()export(path: string): Promisestring接收宿主机的目标路径把对象内容写入该路径返回被写入的路径id()id(): PromiseID返回对象的唯一 IDID类型别名定义见 ID 类型参考从源码结构看这段文档并非手写而是与引擎 schema 严格对齐的产物。Exportable接口在引擎侧由 installCoreInterfaces 注册接口名、描述文案即参考页开头那两句英文、id: ID!字段和export(path: String!): String!字段全部在此处以dagql.InterfaceFieldSpec声明。该文件中的注释还点明了 Dagger 的核心机制——这类接口是**结构化匹配structurally matched**的任何字段对得上的对象自动声明实现了该接口无需显式的implements声明。对应的 GraphQL schema 基线base_schema.graphqls为 An object that can be exported to the host. Calling export writes the object to a path on the host filesystem and returns the path that was written. interface Exportable implements Node { export(path: String!): String! id: ID! }Exportable自身继承自Node接口即“可以通过 ID 寻址的对象”同目录另有 Node.md 与 Syncer.md 两个兄弟接口的参考页这也是id()方法出现在接口签名里的原因它不是 Exportable 独有的能力而是继承自Node。谁实现了 Exportable四个具体类型在 0.21 版 schema 中显式声明实现Exportable的类型有四个base_schema.graphqlstype Container implements Exportable Node Syncertype Directory implements Exportable Node Syncertype File implements Exportable Node Syncertype Changeset implements Exportable Node Syncer这四个类型在 TypeScript SDK 中分别对应 Container、Directory、File 类的参考文档每个类文档中都列出了各自的export()方法。需要注意的是具体类型的export()是接口签名的超集各自带有接口语义之外的额外参数且写入行为不同Container.export定义于 container.go把容器写成OCI tarball到宿主机文件路径支持导出 platform 变体。额外参数包括ociMediatype控制 tarball 的 OCI 媒体类型注释说明这是为兼容不支持 OCI 的旧运行时和expand按容器内定义的环境变量展开路径中的${VAR}/$VAR占位符。Directory.export定义于 directory.go把目录内容写入宿主机路径。额外参数wipe决定写入策略为true时先清空宿主机目录再导出保证目标目录与导出内容完全一致为false默认时目录内容会与宿主机已有内容合并不会删除目标路径中已有的其他文件。File.export定义于 base_schema.graphqls把文件写入宿主机文件路径。额外参数allowParentDirPath为true时path允许是目录路径文件将创建在该目录内。Changeset.exportschema 描述为“Applies the diff represented by this changeset to a path on the host.”即把 changeset 表示的 diff 应用到宿主机路径。阅读参考页时应注意的一个细节接口契约中export()的返回值是Promisestring被写入的路径而各具体类型文档中的export()签名以各自类文档为准例如 File 的 schema 层返回类型为Boolean!。接口页描述的是统一契约的最小语义实际参数与返回值细节以具体类型的参考页和 schema 为准。客户端实现接口如何落在生成的 TypeScript 代码中TypeScript SDK 的Exportable不是手工编写的抽象基类而是由 codegen 从 GraphQL introspection 结果生成的。在 sdk/typescript/src/api/client.gen.ts 中可以看到其完整形态export interface Exportable { id(): PromiseID export(path: string): Promisestring } export class _ExportableClient extends BaseClient { private readonly _id?: ID undefined private readonly _export?: string undefined /** * Constructor is used for internal usage only, do not create object from it. */ constructor(ctx?: Context, _id?: ID, _export?: string) { ... } id async (): PromiseID { if (this._id) { return this._id } const ctx this._ctx.select(id) return await ctx.execute() } export async (path: string): Promisestring { if (this._export) { return this._export } const ctx this._ctx.select(export, { path }) return await ctx.execute() } }从这份生成代码可以读出三点实现事实_ExportableClient仅供内部使用。构造函数注释明确写道 “Constructor is used for internal usage only, do not create object from it.” 开发者在业务代码中不会直接实例化它而是拿到Container、Directory等具体类型实例这些实例经由 codegen 机制暴露了Exportable契约所需的方法。方法采用惰性求值。id()与export()都先检查本地缓存字段_id/_export命中则直接返回未命中才通过this._ctx.select(export, { path })构造查询字段并execute()。这与 Dagger 客户端“查询树延迟执行”的整体模型一致。export 是终端操作不走缓存。引擎侧 schema 中各类型的 export 字段都带有DoNotCache(Writes to the local host.)标记如 directory.go、container.go即每次调用都会真实触发一次写入而不像其他字段那样可能被 DAG 缓存命中后跳过。实际使用导出产物的标准姿势Exportable的典型使用场景是在 DAG 执行结束后把构建产物取回宿主机。一个典型的 TypeScript 脚本骨架如下模式参照 getting-started 中的 TS 示例import * as dagger from dagger.io/dagger const client await dagger.connect() const ctx await dagger.Context().withWorkdir(./.) const built client .container() .from(alpine) .withWorkdir(/src) .withDirectory(/src, ctx.directory()) .withExec([sh, -c, echo done /src/result.txt]) // File 实现了 Exportable把容器内文件导出到宿主机 await built.file(/src/result.txt).export(./out/result.txt) // Directory 实现了 Exportable把目录导出到宿主机 const dir built.directory(/src) await dir.export(./out/src, { wipe: true }) // Container 实现了 Exportable把容器导出为 OCI tarball await built.export(./out/image.tar)使用Exportable时需要注意以下边界path是宿主机路径相对于运行 SDK 脚本的进程工作目录引擎运行在独立环境中写入动作由引擎代理到宿主文件系统。写入不幂等、不缓存Directory.export默认是合并式写入除非wipe: true反复执行可能残留旧文件Container 的 tarball 导出会覆盖目标文件。接口层面只有一个path参数但具体类型接受更多参数如expand、wipe、allowParentDirPath按具体类型参考页调用时可用完整参数集。id()来自 Node 契约可用于跨调用引用同一对象它与export()无直接依赖单独调用只会把该对象纳入待求值集合不触发写入。小结Exportable是 Dagger TypeScript SDK 中“引擎侧产物 → 宿主机文件系统”这一方向统一契约接口本体只有export(path)与id()两个方法文档见 Exportable 参考页引擎侧在 core/schema/coreinterfaces.go 以结构化接口方式注册Container、Directory、File、Changeset四个类型在 base_schema.graphqls 中显式实现该接口并各自扩展了与写入行为相关的参数。对 TypeScript 开发者而言记住“实现了Exportable的对象都能export()到宿主机路径”即可进一步查阅具体参数与返回值语义时应对照 Container、Directory、File 三个类的参考页与引擎 schema 定义。【免费下载链接】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),仅供参考