Skip to content

Commit

Permalink
fix: analyze Wasm plugin version without instantiating plugins (#857)
Browse files Browse the repository at this point in the history
  • Loading branch information
dsherret committed Jun 8, 2024
1 parent 51bdc8b commit 9e4f75d
Show file tree
Hide file tree
Showing 9 changed files with 477 additions and 399 deletions.
2 changes: 1 addition & 1 deletion crates/core/src/plugins/process/communicator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ impl ProcessPluginCommunicator {
let mut stdout_reader = MessageReader::new(child.stdout.take().unwrap());
let mut stdin_writer = MessageWriter::new(child.stdin.take().unwrap());

let (mut stdout_reader, stdin_writer, schema_version) = tokio::task::spawn_blocking(move || {
let (mut stdout_reader, stdin_writer, schema_version) = crate::async_runtime::spawn_blocking(move || {
let schema_version = get_plugin_schema_version(&mut stdout_reader, &mut stdin_writer)
.context("Failed plugin schema verification. This may indicate you are using an old version of the dprint CLI or plugin and should upgrade")?;
Ok::<_, anyhow::Error>((stdout_reader, stdin_writer, schema_version))
Expand Down
8 changes: 3 additions & 5 deletions crates/dprint/src/plugins/implementations/wasm/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,17 @@ use anyhow::bail;
use anyhow::Result;

use super::create_identity_import_object;
use super::functions::WasmFunctions;
use super::create_wasm_plugin_instance;
use super::load_instance::load_instance;
use super::load_instance::WasmModuleCreator;
use super::InitializedWasmPluginInstance;
use crate::plugins::CompilationResult;

/// Compiles a Wasm module.
pub fn compile(wasm_bytes: &[u8]) -> Result<CompilationResult> {
let wasm_module_creator = WasmModuleCreator::default();
let module = wasm_module_creator.create_from_wasm_bytes(wasm_bytes)?;

let bytes = match module.inner.serialize() {
let bytes = match module.inner().serialize() {
Ok(bytes) => bytes,
Err(err) => bail!("Error serializing wasm module: {:#}", err),
};
Expand All @@ -22,8 +21,7 @@ pub fn compile(wasm_bytes: &[u8]) -> Result<CompilationResult> {
let mut store = wasmer::Store::default();
let imports = create_identity_import_object(&mut store);
let instance = load_instance(&mut store, &module, &imports)?;
let wasm_functions = WasmFunctions::new(store, instance)?;
let mut instance = InitializedWasmPluginInstance::new(wasm_functions)?;
let mut instance = create_wasm_plugin_instance(store, instance)?;

Ok(CompilationResult {
bytes: bytes.into(),
Expand Down
202 changes: 0 additions & 202 deletions crates/dprint/src/plugins/implementations/wasm/functions.rs

This file was deleted.

84 changes: 84 additions & 0 deletions crates/dprint/src/plugins/implementations/wasm/instance/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use std::path::Path;

use anyhow::bail;
use anyhow::Result;
use dprint_core::configuration::ConfigKeyMap;
use dprint_core::configuration::ConfigurationDiagnostic;
use dprint_core::plugins::wasm::PLUGIN_SYSTEM_SCHEMA_VERSION;
use dprint_core::plugins::FileMatchingInfo;
use dprint_core::plugins::FormatResult;
use dprint_core::plugins::PluginInfo;
use v1::InitializedWasmPluginInstanceV1;
use wasmer::Store;

use crate::plugins::FormatConfig;

use super::WasmInstance;

mod v1;

pub trait InitializedWasmPluginInstance {
fn plugin_info(&mut self) -> Result<PluginInfo>;
fn license_text(&mut self) -> Result<String>;
fn resolved_config(&mut self, config: &FormatConfig) -> Result<String>;
fn config_diagnostics(&mut self, config: &FormatConfig) -> Result<Vec<ConfigurationDiagnostic>>;
fn file_matching_info(&mut self, _config: &FormatConfig) -> Result<FileMatchingInfo>;
fn format_text(&mut self, file_path: &Path, file_bytes: &[u8], config: &FormatConfig, override_config: &ConfigKeyMap) -> FormatResult;
}

pub fn create_wasm_plugin_instance(store: Store, instance: WasmInstance) -> Result<Box<dyn InitializedWasmPluginInstance>> {
match instance.version() {
PluginSchemaVersion::V3 => Ok(Box::new(InitializedWasmPluginInstanceV1::new(store, instance)?)),
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum PluginSchemaVersion {
V3,
}

pub fn get_current_plugin_schema_version(module: &wasmer::Module) -> Result<PluginSchemaVersion> {
fn from_exports(module: &wasmer::Module) -> Result<u32> {
for export in module.exports() {
let name = export.name();
if matches!(name, "get_plugin_schema_version") {
// not exactly correct, but practically ok because this has been returning v3 for many years
return Ok(3);
} else if let Some(version) = name.strip_prefix("dprint_plugin_version_") {
// this is what dprint will use in the future
if let Ok(version) = version.parse() {
return Ok(version);
}
}
}
bail!("Error determining plugin schema version. Are you sure this is a dprint plugin? If so, maybe try upgrading dprint.");
}

let plugin_schema_version = from_exports(module)?;
match plugin_schema_version {
PLUGIN_SYSTEM_SCHEMA_VERSION => Ok(PluginSchemaVersion::V3),
version if version > PLUGIN_SYSTEM_SCHEMA_VERSION => {
bail!(
"Invalid schema version: {} -- Expected: {}. Upgrade your dprint CLI ({}).",
plugin_schema_version,
PLUGIN_SYSTEM_SCHEMA_VERSION,
get_current_exe_display(),
);
}
plugin_schema_version => {
bail!(
"Invalid schema version: {} -- Expected: {}. This plugin is too old for your version of dprint ({}). Please update the plugin manually.",
plugin_schema_version,
PLUGIN_SYSTEM_SCHEMA_VERSION,
get_current_exe_display(),
);
}
}
}

fn get_current_exe_display() -> String {
std::env::current_exe()
.ok()
.map(|p| p.display().to_string())
.unwrap_or_else(|| "<unknown path>".to_string())
}
Loading

0 comments on commit 9e4f75d

Please sign in to comment.