forked from 1b-agent/opencadstudio-upstream
feat(plugins): drop plugin API v2
A V2 plugin passed the version gate and then failed silently while registering its ribbon, since the ribbon wire types have moved on. The host now loads V3 and newer, so V2 plugins are rejected up front with a version message. The V2 compatibility fixture crate goes too. Fixes #1085 Fixes #987 Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
c45f22652d
commit
71b300cc44
6 files changed
+25
-110
No files matched your search
@@ -1284,7 +1284,7 @@ fn generate_version_info(out_dir: &Path) {
|
||||
"acadrust_source": opencadcodec.source.as_ref().map(|s| s.to_string()),
|
||||
"rustc_version": rustc_version,
|
||||
"api_version": 7,
|
||||
"api_version_min_supported": 2,
|
||||
"api_version_min_supported": 3,
|
||||
"build_timestamp": build_timestamp,
|
||||
});
|
||||
fs::write(out_dir.join("version_info.json"), info.to_string()).unwrap();
|
||||
|
||||
@@ -26,12 +26,14 @@ pub const API_VERSION: u32 = 7;
|
||||
|
||||
/// Oldest plugin API major the current host still loads. This keeps previously
|
||||
/// compiled cdylibs usable as long as their vtable layout is a prefix of the
|
||||
/// current `HostApi` trait.
|
||||
pub const API_VERSION_MIN_SUPPORTED: u32 = 2;
|
||||
/// current `HostApi` trait. V2 is no longer loaded: its ribbon wire types
|
||||
/// predate the current ones, so a V2 plugin passed the gate and then failed
|
||||
/// silently while registering its ribbon (#1085, #987).
|
||||
pub const API_VERSION_MIN_SUPPORTED: u32 = 3;
|
||||
|
||||
/// Environment variable that caps the API major accepted by the host at
|
||||
/// runtime. Set to `5` to disable V6 plugins, `4` to disable V5, or `2` for
|
||||
/// V2-only mode.
|
||||
/// runtime. Set to `5` to disable V6 plugins, `4` to disable V5, or `3` for
|
||||
/// V3-only mode.
|
||||
pub const MAX_API_VERSION_ENV: &str = "OCS_PLUGIN_MAX_API_VERSION";
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
@@ -112,18 +114,18 @@ mod tests {
|
||||
assert_eq!(effective_max_api_version(), 3);
|
||||
assert!(!host_accepts_plugin_version(4));
|
||||
assert!(host_accepts_plugin_version(3));
|
||||
assert!(host_accepts_plugin_version(2));
|
||||
assert!(!host_accepts_plugin_version(2));
|
||||
std::env::remove_var(MAX_API_VERSION_ENV);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn effective_max_v2_only_mode() {
|
||||
fn effective_max_below_minimum_is_v3_only_mode() {
|
||||
let _guard = ENV_LOCK.lock().unwrap();
|
||||
std::env::set_var(MAX_API_VERSION_ENV, "2");
|
||||
assert_eq!(effective_max_api_version(), 2);
|
||||
assert_eq!(effective_max_api_version(), 3);
|
||||
assert!(!host_accepts_plugin_version(4));
|
||||
assert!(!host_accepts_plugin_version(3));
|
||||
assert!(host_accepts_plugin_version(2));
|
||||
assert!(host_accepts_plugin_version(3));
|
||||
assert!(!host_accepts_plugin_version(2));
|
||||
std::env::remove_var(MAX_API_VERSION_ENV);
|
||||
}
|
||||
|
||||
|
||||
@@ -148,7 +148,10 @@ mod tests {
|
||||
Some(env!("CARGO_PKG_VERSION"))
|
||||
);
|
||||
assert_eq!(value["api_version"].as_i64(), Some(crate::API_VERSION as i64));
|
||||
assert_eq!(value["api_version_min_supported"].as_i64(), Some(2));
|
||||
assert_eq!(
|
||||
value["api_version_min_supported"].as_i64(),
|
||||
Some(crate::API_VERSION_MIN_SUPPORTED as i64)
|
||||
);
|
||||
|
||||
// acadrust_version should have a patch component (e.g. "0.4.0").
|
||||
let opencadcodec = value["acadrust_version"].as_str().expect("acadrust_version string");
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
[package]
|
||||
name = "plugin-template-api2"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
description = "API v2 compatibility fixture for the out-of-process plugin path."
|
||||
license = "GPL-3.0-only"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
ocs_plugin_api = { path = "../ocs_plugin_api", features = ["host"] }
|
||||
acadrust = { git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "8a28c21", features = ["serde"] }
|
||||
@@ -1,79 +0,0 @@
|
||||
//! API v2 compatibility fixture.
|
||||
//!
|
||||
//! Mimics an old plugin compiled against `ocs_plugin_api` v2: it reports API
|
||||
//! major 2 from `ocs_plugin_api_version()` and implements only the v2 surface
|
||||
//! (`HostApi` methods up to `start_interactive`). The current host must still
|
||||
//! be able to load and dispatch it.
|
||||
|
||||
use ocs_plugin_api::host::{BuiltinPlugin, HostApi};
|
||||
use ocs_plugin_api::manifest::{ApiVersion, PluginManifest};
|
||||
use ocs_plugin_api::ribbon::{CadModule, IconKind, ModuleEvent, RibbonGroup, RibbonItem, ToolDef};
|
||||
|
||||
static MANIFEST: PluginManifest = PluginManifest {
|
||||
id: "opencad.my_plugin",
|
||||
name: "My Plugin",
|
||||
version: env!("CARGO_PKG_VERSION"),
|
||||
description: "API v2 fixture plugin.",
|
||||
api_version: ApiVersion { major: 2 },
|
||||
ribbon_order: 60,
|
||||
xdata_apps: &[],
|
||||
command_prefixes: &["MP_"],
|
||||
};
|
||||
|
||||
struct MyModule;
|
||||
|
||||
impl CadModule for MyModule {
|
||||
fn id(&self) -> &'static str {
|
||||
"my_plugin"
|
||||
}
|
||||
fn title(&self) -> &'static str {
|
||||
"My Plugin"
|
||||
}
|
||||
fn ribbon_groups(&self) -> &[RibbonGroup] {
|
||||
static GROUPS: std::sync::OnceLock<Vec<RibbonGroup>> = std::sync::OnceLock::new();
|
||||
GROUPS.get_or_init(|| {
|
||||
vec![RibbonGroup {
|
||||
title: "Tools",
|
||||
tools: vec![RibbonItem::LargeTool(ToolDef {
|
||||
id: "MP_HELLO",
|
||||
label: "Hello",
|
||||
icon: IconKind::Glyph("*"),
|
||||
event: ModuleEvent::Command("MP_HELLO".to_string()),
|
||||
})],
|
||||
}]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct MyPlugin;
|
||||
|
||||
impl BuiltinPlugin for MyPlugin {
|
||||
fn manifest(&self) -> &'static PluginManifest {
|
||||
&MANIFEST
|
||||
}
|
||||
fn ribbon(&self) -> Box<dyn CadModule> {
|
||||
Box::new(MyModule)
|
||||
}
|
||||
fn dispatch(&self, host: &mut dyn HostApi, cmd: &str) -> bool {
|
||||
match cmd {
|
||||
"MP_HELLO" => {
|
||||
host.push_info("Hello from API v2 plugin");
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Custom C-ABI export that reports API v2, emulating an older build of
|
||||
// `ocs_plugin_api::export_plugin!`.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn ocs_plugin_api_version() -> u32 {
|
||||
2
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn ocs_plugin_register() -> *mut Box<dyn BuiltinPlugin> {
|
||||
let plugin: Box<dyn BuiltinPlugin> = Box::new(MyPlugin);
|
||||
Box::into_raw(Box::new(plugin))
|
||||
}
|
||||
@@ -553,16 +553,18 @@ description = "Template plugin"
|
||||
repository = "https://github.com/example/opencad-my-plugin.git"
|
||||
|
||||
[opencad]
|
||||
api_version = 2
|
||||
api_version = 3
|
||||
ribbon_order = 60
|
||||
command_prefixes = ["MP_"]
|
||||
xdata_apps = ["MYPLUGIN_RECORD"]
|
||||
"#;
|
||||
let p = parse_plugin_toml(toml).expect("parsed");
|
||||
assert_eq!(p.api_version, 2);
|
||||
assert_eq!(p.api_version, 3);
|
||||
assert_eq!(p.repository.as_deref(), Some("example/opencad-my-plugin"));
|
||||
assert!(p.command_prefixes.contains(&"MP_".to_string()));
|
||||
assert!(p.api_compatible(), "V2 plugins must be accepted by the V4 host");
|
||||
assert!(p.api_compatible(), "V3 plugins must be accepted by the current host");
|
||||
let v2 = parse_plugin_toml("id=\"old\"\napi_version = 2").expect("parsed");
|
||||
assert!(!v2.api_compatible(), "V2 plugins are no longer loaded");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -710,7 +712,7 @@ rustc_version = "{host}"
|
||||
id = "opencad.test"
|
||||
name = "Test"
|
||||
version = "0.1.0"
|
||||
api_version = 2
|
||||
api_version = 3
|
||||
|
||||
[opencad]
|
||||
rustc_version = "rustc 0.0.0-fake"
|
||||
@@ -720,7 +722,7 @@ rustc_version = "rustc 0.0.0-fake"
|
||||
assert!(p.rustc_declared);
|
||||
assert!(
|
||||
p.rustc_compatible(),
|
||||
"API v2 plugin should bypass rustc gate"
|
||||
"API v3 plugin should bypass rustc gate"
|
||||
);
|
||||
assert!(p.loadable());
|
||||
}
|
||||
@@ -826,7 +828,7 @@ acadrust_source = "{host}"
|
||||
id = "opencad.test"
|
||||
name = "Test"
|
||||
version = "0.1.0"
|
||||
api_version = 2
|
||||
api_version = 3
|
||||
|
||||
[opencad]
|
||||
acadrust_source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=0908da7#0908da7b6e4f702a6c78359a57f53e2b79cf39eb"
|
||||
@@ -836,7 +838,7 @@ acadrust_source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=0908
|
||||
assert!(p.acadrust_declared);
|
||||
assert!(
|
||||
p.acadrust_compatible(),
|
||||
"API v2 plugin should bypass opencadcodec gate"
|
||||
"API v3 plugin should bypass opencadcodec gate"
|
||||
);
|
||||
assert!(p.loadable());
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user