Documentation
¶
Overview ¶
Package workspace holds the shared building blocks for opening a workspace: the WorkspaceRegistry and the project, spell, and target option constructors that a magusfile's register(...) calls produce, plus the Load accumulator for Open/Inspect.
It is a separate package for two reasons:
- Import cycle: package magus imports internal/interp to evaluate magusfiles, and internal/interp's Buzz bindings build project options when Buzz code calls magus.project(...). Those option types cannot live in package magus, and not in project either (the watch-ignore constructors need internal/file/watch, which already imports project).
- Surface: Load and WithLimiter carry internal types (*config.Config, *cache.Limiter). Keeping them here lets the daemon inject a shared limiter without those internals leaking onto the public magus API.
Index ¶
- func AddProvidedProjects(ctx context.Context, ws *types.Workspace, spellNames []string, ...) error
- func ContextWithRegistry(ctx context.Context, reg *WorkspaceRegistry) context.Context
- func IgnoreGlob(pattern string) types.IgnorePattern
- func IgnoreLiteral(pattern string) types.IgnorePattern
- func IgnoreRegex(pattern string) types.IgnorePattern
- func RegisterProviderRunner(fn ProviderRunner)
- type BindingOption
- type Load
- type Option
- func WithLimiter(lim *cache.Limiter) Option
- func WithLoadedConfig(cfg config.Config) Option
- func WithMachineAdmitter(a cache.MachineAdmitter) Option
- func WithMetricsCollection() Option
- func WithTelemetryProvider(p observability.Provider) Option
- func WithVersion(v string) Option
- func WithoutWorkspaceProviders() Option
- type ProjectOption
- func WithDependsOn(paths ...string) ProjectOption
- func WithExclusive() ProjectOption
- func WithName(name string) ProjectOption
- func WithNoLanguage(reason string) ProjectOption
- func WithOutputs(paths ...string) ProjectOption
- func WithRegisteredSpell(name string, opts ...BindingOption) ProjectOption
- func WithReviewRequired(globs ...string) ProjectOption
- func WithSources(paths ...string) ProjectOption
- func WithTarget(name string, opts ...TargetOption) ProjectOption
- func WithToolBounds(bounds map[string]spells.VersionBounds) ProjectOption
- func WithWatchIgnore(patterns ...types.IgnorePattern) ProjectOption
- type ProviderCache
- type ProviderRunner
- type TargetOption
- func Drift(policy types.DriftPolicy, reason string) TargetOption
- func Exclusive() TargetOption
- func IncludeArch(v bool) TargetOption
- func IncludeOS(v bool) TargetOption
- func MemoryMB(n int) TargetOption
- func RetryOnVolatile() TargetOption
- func SkipCache(reason string) TargetOption
- func Slots(n int) TargetOption
- type WorkspaceRegistry
- func (r *WorkspaceRegistry) AddProvider(spellName string)
- func (r *WorkspaceRegistry) Apply(w types.WorkspaceRepository) error
- func (r *WorkspaceRegistry) ProjectPaths() []string
- func (r *WorkspaceRegistry) Providers() []string
- func (r *WorkspaceRegistry) RegisterProject(path string, opts ...ProjectOption)
- func (r *WorkspaceRegistry) RemoteBackend() string
- func (r *WorkspaceRegistry) SetRemoteBackend(spellName string)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AddProvidedProjects ¶ added in v0.4.0
func AddProvidedProjects(ctx context.Context, ws *types.Workspace, spellNames []string, cache ProviderCache) error
AddProvidedProjects runs each wired provider in order and adds the projects it reports to ws. It is a no-op when no provider was wired, which is every workspace that does not have one - so the cost of the mechanism to everyone else is one nil check per open.
cache says where a provider's answer is remembered between commands; a zero value re-runs every provider. See provider_cache.go for what invalidates an entry.
Precedence, in the order the rules apply:
- A path that already carries a magusfile is left alone (MGS1019). The magusfile is the workspace's own definition, the same rule that makes a magusfile target shadow a same-named spell op.
- The FIRST provider to report a path owns it. Two providers claiming one directory is a real configuration (an nx repo with a cargo workspace inside it), and wiring order is the only deterministic tiebreak.
- magus\project("libs/foo", {...}) still layers on top of everything here, because WorkspaceRegistry.Apply runs after this.
A rejected path FAILS the whole load rather than being skipped: a silently dropped project is a target that no longer exists with nothing on screen to say so. ws is mutated in place, so a caller continuing past an error holds a partially folded workspace; every caller today discards it.
func ContextWithRegistry ¶
func ContextWithRegistry(ctx context.Context, reg *WorkspaceRegistry) context.Context
ContextWithRegistry installs reg in ctx so that interpreters can retrieve it via WorkspaceRegistryFromContext.
func IgnoreGlob ¶
func IgnoreGlob(pattern string) types.IgnorePattern
IgnoreGlob constructs a doublestar-glob ignore pattern.
func IgnoreLiteral ¶
func IgnoreLiteral(pattern string) types.IgnorePattern
IgnoreLiteral constructs a literal ignore pattern.
func IgnoreRegex ¶
func IgnoreRegex(pattern string) types.IgnorePattern
IgnoreRegex constructs a Go-regexp ignore pattern.
func RegisterProviderRunner ¶ added in v0.4.0
func RegisterProviderRunner(fn ProviderRunner)
RegisterProviderRunner installs the runner AddProvidedProjects delegates to. Meant to be called once, from the bindings package's init; a second call panics rather than silently shadowing the first.
Types ¶
type BindingOption ¶
BindingOption mutates a spell Binding at registration time.
type Load ¶
type Load struct {
ConfigPath string
Preloaded *config.Config
Limiter *cache.Limiter
Registry *WorkspaceRegistry
// MachineAdmitter injects the machine budget directly, for the ONE process that
// holds it. Every other process finds the daemon over its socket; the daemon
// cannot, because dialing its own socket from inside a request it is serving would
// wait on itself.
MachineAdmitter cache.MachineAdmitter
MetricsCollect bool // build an always-on local metrics collector (daemon dashboard feed)
// Provider injects an already-constructed observability provider so several Magus
// instances share one set of OTel instruments and one metrics collector. When set it
// takes precedence over MetricsCollect (Open skips otlp.New and adopts it).
Provider observability.Provider
// Version is the running build's version, used only to check the workspace's
// required_version floor. Empty disables the check, which is the same escape
// hatch the daemon adoption gate uses (see internal/proc/identity.go): a bare
// library caller that never set a version has no version to be too old.
Version string
// SkipWorkspaceProviders opens the workspace without running its wired workspace
// providers, so it holds only the magusfile-declared projects.
SkipWorkspaceProviders bool
}
Load is the accumulated state of an Open or Inspect call.
type Option ¶
type Option func(*Load)
Option configures Open or Inspect.
func WithLimiter ¶
WithLimiter injects a pre-built concurrency limiter (e.g. shared across daemon workspaces).
func WithLoadedConfig ¶
WithLoadedConfig injects an already-parsed config instead of reading magus.yaml.
func WithMachineAdmitter ¶ added in v0.4.0
func WithMachineAdmitter(a cache.MachineAdmitter) Option
WithMachineAdmitter injects the machine-wide admission budget the daemon holds, so the workspaces it serves arbitrate against the same one every other magus on the host reaches over the socket.
func WithMetricsCollection ¶ added in v0.2.0
func WithMetricsCollection() Option
WithMetricsCollection builds an always-on in-process metrics collector for this workspace so its OTel instruments record even when telemetry export is off, and the daemon can serve OTLP snapshots to the /dashboard. The CLI leaves it unset to keep one-shot runs a true no-op.
func WithTelemetryProvider ¶ added in v0.4.0
func WithTelemetryProvider(p observability.Provider) Option
WithTelemetryProvider injects an already-constructed observability provider so several Magus instances (a daemon's bridge plus each of its per-workspace registry Magus) share ONE set of OTel instruments and one metrics collector. The provider is owned by the caller (the daemon process), not by any single workspace, so workspace eviction never discards accumulated metrics. It supersedes WithMetricsCollection: Open adopts the injected provider instead of constructing its own.
Named Telemetry, not just WithProvider, because "provider" is already taken twice over in this package: ProviderRunner/ProviderCache/RegisterProviderRunner/ WithoutWorkspaceProviders all mean a WORKSPACE provider (magus\workspace.provider), and observability.WithProvider (a different package, same short name) stores a Provider on a context rather than an Option. This is the one that meant something else entirely.
func WithVersion ¶ added in v0.4.0
WithVersion supplies the running build's version so Open and Inspect can check it against the workspace's required_version floor. cmd/magus passes its linker-stamped version; a caller that omits it gets no floor check.
func WithoutWorkspaceProviders ¶ added in v0.4.0
func WithoutWorkspaceProviders() Option
WithoutWorkspaceProviders opens the workspace without running its wired workspace providers (magus\workspace.provider), leaving only the magusfile-declared projects.
It exists for a caller inspecting a tree that is not a working checkout - `magus graph diff --rev` exports a bare revision to a temp dir, with no node_modules, no installed toolchain and no VCS metadata. A provider shells out to a foreign tool that needs all three, so running it there fails the open and takes the whole command with it. The base side of a diff is deliberately narrower rather than broken; a project that only a provider knows about shows up as added.
Unrelated to WithTelemetryProvider above, which injects an observability provider.
type ProjectOption ¶
ProjectOption mutates a Project at registration time; a non-nil error aborts Open.
func WithDependsOn ¶
func WithDependsOn(paths ...string) ProjectOption
WithDependsOn adds upstream project paths as dependencies. Paths may be repo-relative or dot-relative to the project.
This is the one caller that wants ResolveDependsOn.s two-mode reading, because a human hand-writes these entries and both spellings are a deliberate affordance. Paths that come from an `import "project/<path>"` are always dot-relative and use file.ResolveImport instead; do not collapse the two.
func WithExclusive ¶
func WithExclusive() ProjectOption
WithExclusive marks a project as must-not-run-alongside-peers in a RunAll batch.
func WithName ¶ added in v0.4.0
func WithName(name string) ProjectOption
WithName sets the project's declared display name, overriding the path-derived default. See types.Project.Name for why the root needs it.
func WithNoLanguage ¶ added in v0.4.0
func WithNoLanguage(reason string) ProjectOption
WithNoLanguage records why a project binds no toolchain spell deliberately.
func WithOutputs ¶
func WithOutputs(paths ...string) ProjectOption
WithOutputs declares the file globs this project produces (project-relative).
func WithRegisteredSpell ¶
func WithRegisteredSpell(name string, opts ...BindingOption) ProjectOption
WithRegisteredSpell registers a built-in spell by name (wire-layer equivalent of magus.WithSpell).
func WithReviewRequired ¶ added in v0.4.0
func WithReviewRequired(globs ...string) ProjectOption
WithReviewRequired declares the globs where an unread change is worth reporting.
A glob escaping the workspace root is REFUSED, the same way WithSources refuses one, and for a sharper reason: a source glob that escapes merely fails to key a cache entry, while this one silently matches nothing and the project goes on believing it has marked its riskiest paths. A feature whose whole job is to say "read this one" must not fail quiet.
func WithSources ¶ added in v0.2.0
func WithSources(paths ...string) ProjectOption
WithSources declares additional file globs (project-relative) that feed this project's cache key and affected-set membership, alongside whatever its resolved spells already contribute via their own Sources(). Use this when a project's real inputs reach beyond what its spells claim - e.g. non-code assets, sibling proto schemas, or docs a generator target reads.
A glob may REACH OUT of the project ("../proto/**" from docs/); that is what makes this the option for a sibling schema. types.RootGlob resolves the reach when the glob is rooted at the workspace, so the cache key and affected attribution both see "proto/**".
Storing the path.Clean'd spelling is what keeps one glob one string. Every check downstream compares declarations by string equality - Project.DeclaredGlobs dedups that way, MGS1005 asks whether a per-target glob is already project-wide the same way - and "./docs/**" and "docs/**" are one declaration, not two.
A glob reaching PAST the workspace root is rejected here, where it is written, rather than stored and ignored. The source walk starts at the workspace root and yields workspace-relative paths, so a glob outside it can never match a file, never move a cache key, and never mark this project affected - accepting one would record a declaration magus has no way to honor.
func WithTarget ¶
func WithTarget(name string, opts ...TargetOption) ProjectOption
WithTarget attaches a behavioral policy to the named target. name is normalized (see types.DefaultTargetNameNormalizer) so a policy declared under any spelling matches the target under any other.
func WithToolBounds ¶ added in v0.4.0
func WithToolBounds(bounds map[string]spells.VersionBounds) ProjectOption
WithToolBounds sets the project's per-binary version windows, rejecting a bound that is not a version.
Rejecting at load is what keeps VersionBounds.Check's unknown verdict a backstop rather than the normal path: a typo here would otherwise widen the window to everything and report nothing, which is the opposite of what declaring one is for.
func WithWatchIgnore ¶
func WithWatchIgnore(patterns ...types.IgnorePattern) ProjectOption
WithWatchIgnore appends patterns to the project's watch ignore list.
type ProviderCache ¶ added in v0.4.0
type ProviderCache struct {
Dir string
// Immutable mirrors cache.immutable: the workspace may be read but never
// written, so a miss re-runs the provider without storing the result.
Immutable bool
}
ProviderCache says where a provider's answer is remembered between commands. A zero value (empty Dir) disables the cache and re-runs every provider.
type ProviderRunner ¶ added in v0.4.0
type ProviderRunner func(ctx context.Context, spellName, root string) ([]spells.ProvidedProject, error)
ProviderRunner invokes spellName's list_projects contract against the workspace at root and returns the records it reported, undecoded. It returns the wire record (spells.ProvidedProject) rather than options so the result stays serializable - which is what lets AddProvidedProjects cache it instead of shelling out to the foreign tool on every magus command.
type TargetOption ¶
TargetOption sets a per-target execution-policy field on a types.Target at registration time.
func Drift ¶ added in v0.4.0
func Drift(policy types.DriftPolicy, reason string) TargetOption
Drift sets what happens when this target's declared outputs move under a read-only run. The zero policy already gates a target that declares outputs, so this is for stating that out loud, downgrading to a warning, or switching it off with a reason.
func Exclusive ¶
func Exclusive() TargetOption
Exclusive returns a TargetOption that runs the target alone — no other target runs concurrently while it does.
func IncludeArch ¶ added in v0.4.0
func IncludeArch(v bool) TargetOption
IncludeArch overrides whether the host architecture keys this target's entry.
func IncludeOS ¶ added in v0.4.0
func IncludeOS(v bool) TargetOption
IncludeOS overrides whether the host OS keys this target's cache entry.
func MemoryMB ¶ added in v0.4.0
func MemoryMB(n int) TargetOption
MemoryMB returns a TargetOption setting the target's memory budget in megabytes. See types.Target.MemoryMB.
func RetryOnVolatile ¶ added in v0.2.0
func RetryOnVolatile() TargetOption
RetryOnVolatile returns a TargetOption that enables volatility detection and auto-retry.
func SkipCache ¶
func SkipCache(reason string) TargetOption
SkipCache returns a TargetOption that opts the target out of the cache, so magus always runs it and never replays or snapshots it. reason states why REPLAYING the target would be wrong (a fresh signature, a screen capture, a go.mod mutation); it is recorded rather than merely documented so a reader can tell a real opt-out from a workaround, and so `--no-cache`, which only distrusts the cache for one run, is not reached for by mistake.
func Slots ¶
func Slots(n int) TargetOption
Slots returns a TargetOption that makes the target hold n concurrency slots while it runs, throttling parallel work around a resource-heavy step. n is clamped to the run's total slot budget at schedule time; n >= the budget makes the target hold every slot, so no peer runs concurrently with it.
type WorkspaceRegistry ¶
type WorkspaceRegistry struct {
// contains filtered or unexported fields
}
WorkspaceRegistry holds the per-Open project-option overrides for a single workspace open. Create one with NewWorkspaceRegistry, populate it via RegisterProject, then pass it to Inspect or Open via WithWorkspaceRegistry. A fresh WorkspaceRegistry per Open call means there is no shared mutable state between concurrent opens.
func NewWorkspaceRegistry ¶
func NewWorkspaceRegistry() *WorkspaceRegistry
NewWorkspaceRegistry returns an empty WorkspaceRegistry.
func WorkspaceRegistryFromContext ¶
func WorkspaceRegistryFromContext(ctx context.Context) *WorkspaceRegistry
WorkspaceRegistryFromContext returns the per-Open WorkspaceRegistry from ctx, or nil. Used by the Teal magus.project and magus.target bindings.
func (*WorkspaceRegistry) AddProvider ¶ added in v0.4.0
func (r *WorkspaceRegistry) AddProvider(spellName string)
AddProvider records a spell name a magusfile wired as a workspace provider, ignoring a repeat of one already wired so a magusfile that wires the same spell twice does not run it twice. Safe to call concurrently.
func (*WorkspaceRegistry) Apply ¶
func (r *WorkspaceRegistry) Apply(w types.WorkspaceRepository) error
Apply applies the registered project options to every project in w. Paths that do not match any discovered project are errors. Option errors are collected and joined. Spell names are resolved to *spells.Spell values and their declared deps are unioned into each project's DependsOn.
func (*WorkspaceRegistry) ProjectPaths ¶
func (r *WorkspaceRegistry) ProjectPaths() []string
ProjectPaths returns the registered project paths in sorted order.
func (*WorkspaceRegistry) Providers ¶ added in v0.4.0
func (r *WorkspaceRegistry) Providers() []string
Providers returns the workspace-provider spell names in wiring order, or nil when none were wired.
func (*WorkspaceRegistry) RegisterProject ¶
func (r *WorkspaceRegistry) RegisterProject(path string, opts ...ProjectOption)
RegisterProject appends opts for the repo-relative project path. Safe to call concurrently.
func (*WorkspaceRegistry) RemoteBackend ¶
func (r *WorkspaceRegistry) RemoteBackend() string
RemoteBackend returns the remote-cache-backend spell name a magusfile wired, or "" when none was.
func (*WorkspaceRegistry) SetRemoteBackend ¶
func (r *WorkspaceRegistry) SetRemoteBackend(spellName string)
SetRemoteBackend records the spell name a magusfile chose as the remote cache backend. Last writer wins; safe to call concurrently.