Skip to content

Commit 842e489

Browse files
committed
python-sdk: report only what generation produced
Workspace.changes(from:) reads a file that exists only on the sparse host base as newly added, so generate(ws).changes(ws) described the workspace base as well as the generated context: every generate claimed to add the module's own dagger.json, which the engine owns and had not touched. Traced to workspaceChangesBetween in core/schema/workspace.go, where the `from` side carries no overlay; the engine fix is in flight. Take the generated context straight from the engine, which computes it correctly, and re-root it at the caller's cwd by hand. Generation stages its own local dependency closure again, since generatedContextChangeset does not resolve it the way generate(ws) did, and generateAll merges each module's changeset rather than threading one workspace through all of them. Re-rooting cannot express a path outside the cwd, so a changeset holding one raises instead of silently dropping it and leaving that module ungenerated. Revert to the native idiom once the engine reports a sparse base correctly. Signed-off-by: Yves Brissaud <yves@dagger.io>
1 parent 9e9df21 commit 842e489

3 files changed

Lines changed: 65 additions & 7 deletions

File tree

.dagger/modules/e2e/main.dang

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,31 @@ type E2e {
253253
Generating an existing module should produce generated files rooted at that
254254
module without touching unrelated paths.
255255
"""
256+
"""
257+
Generation should report only what generation produced.
258+
259+
A module's own config is engine-owned and already on disk, so a changeset that
260+
claims to add it is describing the workspace base rather than the generated
261+
context.
262+
"""
263+
pub generateSkipsEngineConfigCheck(ws: Workspace!): Void @check {
264+
let config = generateModulePath + "/dagger.json"
265+
266+
let single = pythonSdk.mod(ws, path: generateModulePath).generate
267+
assert(
268+
contains(single.addedPaths, config) == false,
269+
"generate reported the engine-owned dagger.json as added",
270+
)
271+
272+
let all = pythonSdk.generateAll(ws)
273+
assert(
274+
contains(all.addedPaths, config) == false,
275+
"generateAll reported the engine-owned dagger.json as added",
276+
)
277+
278+
null
279+
}
280+
256281
pub generateCheck(ws: Workspace!): Void @check {
257282
let changes = pythonSdk.mod(ws, path: generateModulePath).generate
258283

mod.dang

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,41 @@ type Mod {
5858
if (skipGenerate) {
5959
ws.changes(ws)
6060
} else {
61-
ws.moduleSource("/" + rootPath).generate(ws).changes(ws)
61+
# Stage the local dependency closure so this module's codegen sees
62+
# up-to-date dependency bindings. The staged workspace is only an input:
63+
# the generated context is diffed against the base it was generated from,
64+
# so the dependencies' own codegen does not ride along.
65+
let stagedWs = ws.withChanges(ws.moduleSource("/" + rootPath).generateLocalDependencies(ws))
66+
atCwd(stagedWs.moduleSource("/" + rootPath).generatedContextChangeset)
67+
}
68+
}
69+
70+
"""
71+
Re-root a workspace-rooted changeset at the client's cwd.
72+
73+
The engine roots a generated context at the workspace, but a returned
74+
changeset is applied relative to the caller's cwd, so without this every path
75+
would land nested under the cwd a second time.
76+
77+
`Workspace.changes(from:)` is the native API for this. On v1.0.0-beta.10 it
78+
reads a file that exists only on the sparse host base as newly added, so a
79+
module's own `dagger.json` is reported as something generation produced, and
80+
the rooting stays explicit here until the engine side is fixed.
81+
"""
82+
let atCwd(changes: Changeset!): Changeset! {
83+
let cwd = ws.cwd.trimPrefix("/").trimSuffix("/")
84+
if (cwd == "" or cwd == ".") {
85+
changes
86+
} else {
87+
# A cwd-relative changeset cannot express a path outside the cwd — a
88+
# module found above it, say — and re-rooting would silently drop it,
89+
# leaving that module never regenerated. Fail loudly instead.
90+
let outside = (changes.addedPaths + changes.modifiedPaths + changes.removedPaths)
91+
.filter { p => p != cwd and p.trimPrefix(cwd + "/") == p }
92+
if (outside.length > 0) {
93+
raise "generated changes fall outside the current directory " + cwd + ": " + outside.join(", ")
94+
}
95+
changes.after.directory(cwd).changes(changes.before.directory(cwd))
6296
}
6397
}
6498
}

python-sdk.dang

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -216,11 +216,10 @@ type PythonSdk {
216216
Modules with the generate skip marker are skipped.
217217
"""
218218
pub generateAll(ws: Workspace!): Changeset! @generate {
219-
modules(ws)
220-
.filter { mod => mod.skipGenerate == false }
221-
.reduce(ws) { stagedWs, mod =>
222-
stagedWs.moduleSource("/" + mod.rootPath).generate(stagedWs)
223-
}
224-
.changes(ws)
219+
changeset.withChangesets(
220+
modules(ws)
221+
.filter { mod => mod.skipGenerate == false }
222+
.map { mod => mod.generate },
223+
)
225224
}
226225
}

0 commit comments

Comments
 (0)