use anyhow::Result;
use std::path::PathBuf;
use dprint_core::plugins::PluginInfo;
use super::WasmModuleCreator;
use super::process;
use super::wasm;
use crate::environment::Environment;
use crate::plugins::Plugin;
use crate::plugins::PluginCache;
use crate::plugins::PluginCacheItem;
use crate::plugins::PluginSourceReference;
use crate::utils::PathSource;
use crate::utils::PluginKind;
pub struct SetupPluginResult {
pub file_path: PathBuf,
pub plugin_info: PluginInfo,
pub executable_sub_path: Option<String>,
}
pub struct SetupPluginDest {
pub wasm_file_path: PathBuf,
pub process_dir_path: PathBuf,
}
pub struct SetupPluginOptions<'a> {
pub resolved_source: &'a PathSource,
pub file_bytes: Vec<u8>,
pub plugin_kind: PluginKind,
pub pre_resolved_tarball: Option<crate::plugins::npm_resolution::PreResolvedProcessPluginTarball>,
pub dest: &'a SetupPluginDest,
}
pub async fn setup_plugin<TEnvironment: Environment>(options: SetupPluginOptions<'_>, environment: &TEnvironment) -> Result<SetupPluginResult> {
let SetupPluginOptions {
resolved_source,
file_bytes,
plugin_kind,
pre_resolved_tarball,
dest,
} = options;
match plugin_kind {
PluginKind::Wasm => wasm::setup_wasm_plugin(resolved_source, file_bytes, &dest.wasm_file_path, environment).await,
PluginKind::Process => process::setup_process_plugin(resolved_source, &file_bytes, pre_resolved_tarball, &dest.process_dir_path, environment).await,
}
}
pub async fn create_plugin<TEnvironment: Environment>(
plugin_cache: &PluginCache<TEnvironment>,
environment: TEnvironment,
plugin_reference: &PluginSourceReference,
wasm_module_creator: &WasmModuleCreator,
) -> Result<Box<dyn Plugin>> {
let cache_item = match plugin_cache.get_plugin_cache_item(plugin_reference).await {
Ok(cache_item) => cache_item,
Err(err) => {
log_debug!(
environment,
"Error getting plugin from cache. Forgetting from cache and retrying. Message: {}",
err.to_string()
);
plugin_cache.forget_and_recreate(plugin_reference).await?
}
};
match cache_item.plugin_kind {
PluginKind::Wasm => {
let plugin = match create_wasm_plugin(&environment, &cache_item, wasm_module_creator) {
Ok(plugin) => plugin,
Err(err) => {
log_debug!(
environment,
"Error loading Wasm plugin from cache. Forgetting from cache and retrying. Message: {:#}",
err
);
let cache_item = plugin_cache.forget_and_recreate(plugin_reference).await?;
create_wasm_plugin(&environment, &cache_item, wasm_module_creator)?
}
};
Ok(Box::new(plugin))
}
PluginKind::Process => {
let cache_item = if !environment.path_exists(&cache_item.file_path) {
log_debug!(
environment,
"Could not find process plugin at {}. Forgetting from cache and retrying.",
cache_item.file_path.display()
);
plugin_cache.forget_and_recreate(plugin_reference).await?
} else {
cache_item
};
let executable_path = super::process::get_test_safe_executable_path(&cache_item.info.version, cache_item.file_path, &environment);
Ok(Box::new(process::ProcessPlugin::new(environment, executable_path, cache_item.info)))
}
}
}
fn create_wasm_plugin<TEnvironment: Environment>(
environment: &TEnvironment,
cache_item: &PluginCacheItem,
wasm_module_creator: &WasmModuleCreator,
) -> Result<wasm::WasmPlugin<TEnvironment>> {
let file_bytes = environment.read_file_bytes(&cache_item.file_path)?;
wasm::WasmPlugin::new(&file_bytes, cache_item.info.clone(), wasm_module_creator, environment.clone())
}
#[cfg(test)]
mod test {
use super::*;
use crate::environment::TestEnvironment;
use crate::test_helpers::WASM_PLUGIN_BYTES;
#[tokio::test]
async fn should_recompile_when_cached_wasm_module_fails_to_load() {
let environment = TestEnvironment::new();
environment.add_remote_file("https://plugins.dprint.dev/test.wasm", WASM_PLUGIN_BYTES);
let plugin_cache = PluginCache::new(environment.clone());
let wasm_module_creator = WasmModuleCreator::default();
let plugin_reference = PluginSourceReference::new_remote_from_str("https://plugins.dprint.dev/test.wasm");
let cache_item = plugin_cache.get_plugin_cache_item(&plugin_reference).await.unwrap();
assert_eq!(environment.take_stderr_messages(), vec!["Compiling https://plugins.dprint.dev/test.wasm"]);
environment.write_file_bytes(&cache_item.file_path, b"corrupt").unwrap();
let plugin = create_plugin(&plugin_cache, environment.clone(), &plugin_reference, &wasm_module_creator)
.await
.unwrap();
assert_eq!(plugin.info().name, "test-plugin");
assert_eq!(environment.take_stderr_messages(), vec!["Compiling https://plugins.dprint.dev/test.wasm"]);
}
}