pmpx_plugin/lib.rs
1//! # pmpx-plugin
2//!
3//! The pmpx plugin contract: one trait plus a stable C ABI that carries the trait safely across
4//! the `dlopen` boundary.
5//!
6//! A plugin author only implements [`PackageManager`] and then uses the one-line
7//! [`export!`](macro@crate::export) to generate the whole C ABI shell:
8//!
9//! ```ignore
10//! pub fn create() -> Box<dyn PackageManager> { Box::new(CargoPlugin) }
11//! pmpx_plugin::export!(create);
12//! ```
13//! # What a plugin may and may not do
14//!
15//! [`PackageManager::command`] should only map from its inputs: it does not read files (including
16//! anything under `project_root`), does not write files, does not read environment variables,
17//! does not spawn child processes, and does not make network requests. That keeps `command()`
18//! completely pure (unit tests need no fixture directory at all) and stops a plugin from using
19//! file reads to probe things it should not know -- "what the project looks like" is decided by
20//! the host's detect layer and handed to the plugin through `matched`, a declarative, auditable
21//! allowlist.
22//! Data crossing [`abi`] is always `#[repr(C)]` POD, so the two sides need not share a rustc; see
23//! the module docs of [`abi`].
24//!
25//! The contract's parts live in sibling modules and are re-exported here, so every path that
26//! starts with `pmpx_plugin::` is stable: [`PackageManager`] and the [`Context`] it is called
27//! with, the [`CommandSpec`] it answers with, the [`Verb`]s, the [`Family`] and the
28//! [`PluginError`] it may report.
29#![deny(missing_docs)]
30#![warn(clippy::all)]
31
32pub mod abi;
33
34mod context;
35mod error;
36mod export;
37mod family;
38mod manager;
39mod spec;
40mod verb;
41
42pub use context::Context;
43pub use error::PluginError;
44pub use family::Family;
45pub use manager::PackageManager;
46pub use spec::CommandSpec;
47pub use verb::Verb;