Expand description
§pmpx-plugin
The pmpx plugin contract: one trait plus a stable C ABI that carries the trait safely across
the dlopen boundary.
A plugin author only implements PackageManager and then uses the one-line
export! to generate the whole C ABI shell:
pub fn create() -> Box<dyn PackageManager> { Box::new(CargoPlugin) }
pmpx_plugin::export!(create);§What a plugin may and may not do
PackageManager::command should only map from its inputs: it does not read files (including
anything under project_root), does not write files, does not read environment variables,
does not spawn child processes, and does not make network requests. That keeps command()
completely pure (unit tests need no fixture directory at all) and stops a plugin from using
file reads to probe things it should not know – “what the project looks like” is decided by
the host’s detect layer and handed to the plugin through matched, a declarative, auditable
allowlist.
Data crossing abi is always #[repr(C)] POD, so the two sides need not share a rustc; see
the module docs of abi.
The contract’s parts live in sibling modules and are re-exported here, so every path that
starts with pmpx_plugin:: is stable: PackageManager and the Context it is called
with, the CommandSpec it answers with, the Verbs, the Family and the
PluginError it may report.
Modules§
- abi
- The wire format across the
dlopenboundary.
Macros§
- export
- Generate the plugin’s entire C ABI shell: the entry symbol, plus the
name/family/command/free_*shims.
Structs§
- Command
Spec - One command waiting to be executed, pure data – a plugin only describes “what to run” and the
actual spawn is done by the host, so stdio, environment, and exit-code handling have exactly
one implementation. Construction is a consuming chain (
self->Self), so it can produce a value directly: - Context
- The context the host passes to the plugin. Read-only.
- Family
- Ecosystem family. Decides the grouping headers of the host’s
plugin ls, the scope ofplugin set, and the key names of[plugin] <family> = "..."in a project’s.pmpx.toml. An open type rather than a closed enum: known ecosystems have constants, unknown ones extend viaFamily::new, and comparison and ordering go by string – a third-party plugin supporting a new ecosystem needs neither a change to this crate nor a host release.
Enums§
- Plugin
Error - The errors a plugin can report. Deliberately only three – because the host only needs to distinguish three: the verb is not supported (so it can degrade to passing through verbatim), the arguments are wrong, and everything else. The human-readable description goes in the payload and the host prints it to stderr as-is.
- Verb
- The verbs pmpx recognizes. A closed set – this is all the command line has.
The numbers correspond one-to-one with the
VERB_*constants inabi, and the order must not change (changing it requiresabi::ABI_VERSION+ 1); a test in theabimodule pins this down.
Traits§
- Package
Manager - An implementation of one package manager backend, a purely synchronous interface: no
async, no callbacks, no I/O – passing aFutureacross thedlopenboundary is the most fragile part of this approach. It should only do mapping; see the crate docs for the constraints.