diff --git a/crates/ocs_plugin_api/build.rs b/crates/ocs_plugin_api/build.rs index 91f5a9aee..382754826 100644 --- a/crates/ocs_plugin_api/build.rs +++ b/crates/ocs_plugin_api/build.rs @@ -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(); diff --git a/crates/ocs_plugin_api/src/manifest.rs b/crates/ocs_plugin_api/src/manifest.rs index 8bf2ee892..849e63a94 100644 --- a/crates/ocs_plugin_api/src/manifest.rs +++ b/crates/ocs_plugin_api/src/manifest.rs @@ -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); } diff --git a/crates/ocs_plugin_api/src/version_info.rs b/crates/ocs_plugin_api/src/version_info.rs index 177a05a86..da14db317 100644 --- a/crates/ocs_plugin_api/src/version_info.rs +++ b/crates/ocs_plugin_api/src/version_info.rs @@ -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"); diff --git a/crates/plugin-template-api2/Cargo.toml b/crates/plugin-template-api2/Cargo.toml deleted file mode 100644 index b1794533c..000000000 --- a/crates/plugin-template-api2/Cargo.toml +++ /dev/null @@ -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"] } diff --git a/crates/plugin-template-api2/src/lib.rs b/crates/plugin-template-api2/src/lib.rs deleted file mode 100644 index ee26e847c..000000000 --- a/crates/plugin-template-api2/src/lib.rs +++ /dev/null @@ -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> = 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 { - 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 { - let plugin: Box = Box::new(MyPlugin); - Box::into_raw(Box::new(plugin)) -} diff --git a/src/plugin/external.rs b/src/plugin/external.rs index d32648fc2..b63050e2a 100644 --- a/src/plugin/external.rs +++ b/src/plugin/external.rs @@ -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()); }