1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//! # 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!`](macro@crate::export) to generate the whole C ABI shell:
//!
//! ```ignore
//! 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 [`Verb`]s, the [`Family`] and the
//! [`PluginError`] it may report.
pub use Context;
pub use PluginError;
pub use Family;
pub use PackageManager;
pub use CommandSpec;
pub use Verb;