use crate::error::ExtensionError;
pub const DUCKDB_PLATFORMS: &[&str] = &[
"linux",
"linux_amd64",
"linux_amd64_musl",
"linux_arm64",
"linux_arm64_musl",
"osx",
"osx_amd64",
"osx_arm64",
"wasm",
"wasm_eh",
"wasm_mvp",
"wasm_threads",
"windows",
"windows_amd64",
"windows_amd64_mingw",
"windows_amd64_rtools",
"windows_arm64",
];
pub const DUCKDB_CI_PLATFORMS: &[&str] = &[
"linux_amd64",
"linux_amd64_musl",
"linux_arm64",
"linux_arm64_musl",
"osx_amd64",
"osx_arm64",
"wasm_eh",
"wasm_mvp",
"wasm_threads",
"windows_amd64",
"windows_amd64_mingw",
"windows_arm64",
];
pub const DUCKDB_PLATFORM_GROUPS: &[&str] = &["linux", "osx", "wasm", "windows"];
pub const DUCKDB_OPT_IN_PLATFORMS: &[&str] =
&["linux_amd64_musl", "linux_arm64_musl", "windows_arm64"];
#[must_use]
pub fn is_opt_in_platform(platform: &str) -> bool {
DUCKDB_OPT_IN_PLATFORMS.contains(&platform)
}
pub fn validate_platform(platform: &str) -> Result<(), ExtensionError> {
if platform.is_empty() {
return Err(ExtensionError::new("platform identifier must not be empty"));
}
if DUCKDB_PLATFORMS.contains(&platform) {
return Ok(());
}
if platform == "linux_amd64_gcc4" {
return Err(ExtensionError::new(
"platform 'linux_amd64_gcc4' no longer exists; DuckDB retired the legacy \
CXX ABI target and no longer builds it. Remove it from excluded_platforms.",
));
}
Err(ExtensionError::new(format!(
"platform '{platform}' is not a recognized DuckDB build target; valid targets: {}",
DUCKDB_PLATFORMS.join(", ")
)))
}
pub fn validate_excluded_platforms(platforms: &[&str]) -> Result<(), ExtensionError> {
let mut seen = std::collections::HashSet::new();
for &platform in platforms {
if platform.is_empty() {
continue;
}
validate_platform(platform)?;
if !seen.insert(platform) {
return Err(ExtensionError::new(format!(
"duplicate excluded platform: '{platform}'"
)));
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn all_platforms_valid() {
for &platform in DUCKDB_PLATFORMS {
assert!(
validate_platform(platform).is_ok(),
"expected '{platform}' to be valid"
);
}
}
#[test]
fn linux_amd64_valid() {
assert!(validate_platform("linux_amd64").is_ok());
}
#[test]
fn osx_arm64_valid() {
assert!(validate_platform("osx_arm64").is_ok());
}
#[test]
fn wasm_valid() {
assert!(validate_platform("wasm_mvp").is_ok());
assert!(validate_platform("wasm_eh").is_ok());
assert!(validate_platform("wasm_threads").is_ok());
}
#[test]
fn empty_rejected() {
assert!(validate_platform("").is_err());
}
#[test]
fn unknown_platform_rejected() {
let err = validate_platform("freebsd_amd64").unwrap_err();
assert!(err.as_str().contains("not a recognized"));
}
#[test]
fn retired_gcc4_platform_says_why() {
let err = validate_platform("linux_amd64_gcc4").unwrap_err();
assert!(
err.as_str().contains("no longer exists"),
"a stale name deserves a better message than \"not recognized\": {err}"
);
}
#[test]
fn musl_platforms_are_recognised() {
assert!(validate_platform("linux_amd64_musl").is_ok());
assert!(validate_platform("linux_arm64_musl").is_ok());
assert!(validate_excluded_platforms(&["linux_arm64_musl"]).is_ok());
}
#[test]
fn opt_in_platforms_are_a_subset() {
for &platform in DUCKDB_OPT_IN_PLATFORMS {
assert!(
DUCKDB_PLATFORMS.contains(&platform),
"{platform} is opt-in but not a known platform"
);
assert!(is_opt_in_platform(platform));
}
assert!(!is_opt_in_platform("linux_amd64"));
}
#[test]
fn platform_list_has_no_duplicates() {
let unique: std::collections::HashSet<_> = DUCKDB_PLATFORMS.iter().collect();
assert_eq!(unique.len(), DUCKDB_PLATFORMS.len());
}
#[test]
fn validate_excluded_platforms_valid() {
assert!(validate_excluded_platforms(&["wasm_mvp", "wasm_eh"]).is_ok());
}
#[test]
fn validate_excluded_platforms_empty() {
assert!(validate_excluded_platforms(&[]).is_ok());
}
#[test]
fn validate_excluded_platforms_invalid() {
assert!(validate_excluded_platforms(&["invalid"]).is_err());
}
#[test]
fn validate_excluded_platforms_duplicate() {
let err = validate_excluded_platforms(&["linux_amd64", "linux_amd64"]).unwrap_err();
assert!(err.as_str().contains("duplicate"));
}
}