use core::str::FromStr;
use std::path::Path;
use polyplug::loader::ManifestData;
use polyplug::loader::parse_manifest;
use polyplug_abi::types::Version;
use polyplug_codegen::PolyplugcError;
pub fn validate_bundle_dir(dir: &Path) -> Result<(), PolyplugcError> {
if !dir.is_dir() {
return Err(PolyplugcError::ValidationFailed {
message: format!(
"bundle dir `{}` does not exist or is not a directory",
dir.display()
),
});
}
let manifest: ManifestData =
parse_manifest(dir).map_err(|e: polyplug::error::LoaderError| {
PolyplugcError::ValidationFailed {
message: format!("manifest.toml: {e}"),
}
})?;
manifest
.validate()
.map_err(
|e: polyplug::error::LoaderError| PolyplugcError::ValidationFailed {
message: format!("manifest.toml: {e}"),
},
)?;
if !manifest.version.is_empty() && Version::from_str(&manifest.version).is_err() {
return Err(PolyplugcError::ValidationFailed {
message: format!(
"manifest.toml: field `version` = \"{}\" is not a valid version (expected major.minor[.patch])",
manifest.version
),
});
}
let artifact: std::path::PathBuf = dir.join(&manifest.file);
if !artifact.is_file() {
return Err(PolyplugcError::ValidationFailed {
message: format!(
"manifest.toml: field `file` resolves to \"{}\" for this platform, but `{}` does not exist in the bundle dir",
manifest.file,
artifact.display()
),
});
}
check_extension_matches_runtime(&manifest)?;
Ok(())
}
fn check_extension_matches_runtime(manifest: &ManifestData) -> Result<(), PolyplugcError> {
let extension: &str = Path::new(&manifest.file)
.extension()
.and_then(|e: &std::ffi::OsStr| e.to_str())
.unwrap_or("");
let allowed: &[&str] = match manifest.loader.as_str() {
"native" => &["so", "dylib", "dll"],
"lua" => &["lua"],
"python" => &["py"],
"js-quickjs" => &["js"],
"dotnet" => &["dll"],
other => {
return Err(PolyplugcError::UnsupportedLanguage {
lang: other.to_owned(),
});
}
};
if !allowed.contains(&extension) {
return Err(PolyplugcError::ValidationFailed {
message: format!(
"manifest.toml: field `file` = \"{}\" has extension `.{extension}`, which is not valid for loader `{}` (expected one of: {})",
manifest.file,
manifest.loader,
allowed
.iter()
.map(|e: &&str| format!(".{e}"))
.collect::<Vec<String>>()
.join(", ")
),
});
}
Ok(())
}