MGS1025: magusfile calls an API that was removed
A magusfile called a function magus no longer binds:
[MGS1025] magus.needs was removed: call ctx.needs(<target>) instead
magus rejects this at load, before any target runs.
Why this needs its own code
Removing a binding does not report itself. Buzz reads a missing member as null
rather than erroring, so a magusfile calling a removed function still parses, still
loads, and still passes magus ls. It breaks when the target finally runs, and only
as:
cause: buzz: null is not callable
That names neither the call nor what replaced it. Nothing in it says the API changed.
magus.needs was worse than a bad message. magus builds the target dependency graph
statically, by reading ctx.needs out of the source, so a magusfile still calling
magus.needs declares its dependencies to nothing:
$ magus explain build
target:.:build target
part of project:.
No depends on line. The edge is simply absent, and magus explain, magus affected, and scheduling all act on that graph. A stale magusfile could run for a
long time building in the wrong order, or skipping a prerequisite entirely, without
ever producing an error.
The removed calls
| Removed | Use instead |
|---|---|
magus.needs(<target>) |
ctx.needs(<target>) |
magus.glob("<pattern>") |
ctx.glob("<pattern>") |
magus.target.literal("<name>") |
pass the target function itself to ctx.needs |
magus.project.register(fun(p, cb) ...) |
magus\project({...}) at the top level |
magus.insightMarkdown([opts]) |
build the document from magus\insight()'s typed report |
The first three moved onto the context that every target now receives, which is what makes the dependency graph readable from the source. See MGS1008 for the signature half of that same change.
Resolution
Take the declarations off the magus module and onto the target's ctx:
// before
export fun build(ctx: magus\Context, args: [str]) > void {
magus.needs(magus.target.literal("format"));
magus.needs(magus.glob("gen-*"));
}
// after
export fun build(ctx: magus\Context, args: [str]) > void {
ctx.needs(format);
ctx.needs(ctx.glob("gen-*"));
}
ctx.needs takes the target function itself, not its name as a string, so a typo is
a load error rather than a dependency that silently never resolves.
Registration moved from a callback to a literal, and is called at the top level of the magusfile rather than from inside a function:
// before
magus.project.register(fun(p, cb) > bool { cb({"spells": [go]}); return true; });
// after
magus\project({ "spells": [go] });
Detection
magus reads the parsed magusfile, so a removed name inside a comment or a string
literal is not a call and does not fire this code. The one exception is a magusfile
that fails to parse at all: magus.project.register predates required parameter
annotations, so it dies in the parser before there is an AST to read, and magus falls
back to a textual scan to explain it. That fallback runs only for a magusfile that is
already failing to load.