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

MGS1013: cross-project output glob escapes its owner

The glob in a cross-project ctx.writesFiles is absolute or contains .., so it does not name a path inside the project it is declared against.

[MGS1013] workspace://producer: target "build": ctx.writesFiles glob "../../etc/x"
must be relative to "site" and must not contain ..

Why

A cross-project output has two halves, and they are validated for different reasons:

ctx.writesFiles(site.file("generated.txt"));
//          ^^^^      ^^^^^^^^^^^^^^
//          owner     glob, relative to the OWNER's root

The owner half says which project's tree the file lands in. The glob half is relative to that project's root, not the declaring one - which is exactly why magus can file it on the owner and let clean, watch, ownership lookup and the merge driver all resolve it against a single root.

That only holds if the glob stays inside the owner. An absolute path or a .. escape resolves somewhere else entirely, and every consumer that joins it to the owner's directory then reads a path the declaration never meant. Outputs in magus are confined to a project subtree; this is that rule applied to the glob.

The cache enforces the same rule when it snapshots. Checking at load only moves the failure earlier, and it moves it somewhere much better:

  • Before, the glob was accepted, the target ran, and the error appeared only once work had been done.
  • Worse, magus clean expands output globs for every project in one loop, so a single unexpandable pattern aborted the clean for the whole workspace - a failure in one project's declaration taking out an unrelated command.

Resolution

Write the path as the owner sees it. If site is at site/ and the file belongs at site/gen/api.ts, the owner is site and the glob is gen/api.ts:

ctx.writesFiles(site.file("gen/api.ts"));

If you find yourself reaching for .. to get somewhere, the owner is wrong, not the glob. Import the project that actually contains the destination and declare against that one. If nothing owns it, it is not a tracked output - see MGS1011.

See also

MGS1013magusfileoutputscross-projectglobscontainment
Last updated (3da15dc9)
Earlier changes on this page (1)

Full history ↗ · Blame source ↗

Glossary

Workspace

The magus root directory that owns a set of projects and shared config; the unit magus operates over. See workspace.

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.

Buzz

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

Cache

The content-addressed store magus consults before running a target, so unchanged work is skipped. See cache.

Snapshot

A point-in-time view of live state - the pool's occupancy or a tick of exported metrics - as opposed to accumulated history. See daemon.

Ownership

An insight lens: author concentration - the primary author and their share, the distinct-author count (the bus factor), and abandonment. See insight.

Conventions

This page uses none of the site's convention markers. The full set is on the conventions page.