magus v0.4.2 is out. See what's new
¶ View markdown source · ✎ Suggest an edit
3 min read

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.

See also

MGS1025magusfilemigrationneedstarget-graphcompatibility
Last updated (9edeede5)
Earlier changes on this page (2)

Full history ↗ · Blame source ↗

Glossary

Project

A directory magus recognizes as a unit of work (it has a magusfile); the unit of caching, scheduling, and dependency tracking. See workspace.

Magusfile

The magusfile.buzz that declares a project's targets (as export funs) and binds its spells. See targets.

Target

A named operation (build, test, ...) you invoke with magus run <target>; it may compose a spell's tool-native operations and depend on other targets. See targets.

Op

A single tool-native command a target composes (long form: operation); the middle of the work hierarchy (Spell to Op to Target). See operations.

Spell

A language/runtime adapter (e.g. go, md) that maps generic targets onto a toolchain's real commands. See spells.

Module

A magus stdlib namespace a magusfile imports for host capabilities: filesystem, exec, vcs, and more. See the module reference.

Buzz

The language magusfiles are written in (the .buzz engine). See engines.

Affected

The set of projects touched by a change; magus affected <target> runs a target only over them. See affected.

CI

An ordinary magusfile-defined target you compose yourself with magus\needs - magus does not hardcode its stages. Magus.RunCI treats it specially only in that it strips the rw charm, it is the anchor magus affected ci keys off, and a selected scope with no project declaring it is a load error rather than a silent no-op. See targets.

Insight

The reports magus derives over the graph and history (hotspots, affinity, ownership, trend, volatility, unreferenced). See insight.

Conventions

Placeholders

Angle brackets mark a value you replace with your own - never type the brackets:

magus run <target>
magus completion <shell>    # e.g. bash, zsh, fish

<target>, <path>, <shell>, <name> and the like are stand-ins, not literal text.