use crate::auditwheel::Policy;
use serde::{Deserialize, Deserializer, Serialize};
use std::fmt;
use std::str::FromStr;
#[derive(Serialize, Debug, Clone, Eq, PartialEq, Copy, Ord, PartialOrd)]
pub enum PlatformTag {
Manylinux {
x: u16,
y: u16,
},
Musllinux {
x: u16,
y: u16,
},
Linux,
}
impl PlatformTag {
pub fn manylinux1() -> Self {
Self::Manylinux { x: 2, y: 5 }
}
pub fn manylinux2010() -> Self {
Self::Manylinux { x: 2, y: 12 }
}
pub fn manylinux2014() -> Self {
Self::Manylinux { x: 2, y: 17 }
}
pub fn aliases(&self) -> Vec<String> {
match self {
PlatformTag::Manylinux { .. } => {
if let Some(policy) = Policy::from_name(&self.to_string()) {
policy.aliases
} else {
Vec::new()
}
}
PlatformTag::Musllinux { .. } => Vec::new(),
PlatformTag::Linux => Vec::new(),
}
}
pub fn is_portable(&self) -> bool {
!matches!(self, PlatformTag::Linux)
}
pub fn is_manylinux(&self) -> bool {
matches!(self, PlatformTag::Manylinux { .. })
}
pub fn is_musllinux(&self) -> bool {
matches!(self, PlatformTag::Musllinux { .. })
}
pub fn is_supported(&self) -> bool {
match self {
PlatformTag::Manylinux { x, y } => (*x, *y) >= (2, 17),
PlatformTag::Musllinux { .. } => true,
PlatformTag::Linux => true,
}
}
}
impl fmt::Display for PlatformTag {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
PlatformTag::Manylinux { x, y } => write!(f, "manylinux_{x}_{y}"),
PlatformTag::Musllinux { x, y } => write!(f, "musllinux_{x}_{y}"),
PlatformTag::Linux => write!(f, "linux"),
}
}
}
impl FromStr for PlatformTag {
type Err = &'static str;
fn from_str(value: &str) -> anyhow::Result<Self, Self::Err> {
let value = value.to_ascii_lowercase();
match value.as_str() {
"off" | "linux" => Ok(PlatformTag::Linux),
"1" | "manylinux1" => Ok(PlatformTag::manylinux1()),
"2010" | "manylinux2010" => Ok(PlatformTag::manylinux2010()),
"2014" | "manylinux2014" => Ok(PlatformTag::manylinux2014()),
_ => {
if let Some(value) = value.strip_prefix("musllinux_") {
let mut parts = value.split('_');
let x = parts
.next()
.and_then(|x| x.parse::<u16>().ok())
.ok_or("invalid musllinux option")?;
let y = parts
.next()
.and_then(|y| y.parse::<u16>().ok())
.ok_or("invalid musllinux option")?;
Ok(PlatformTag::Musllinux { x, y })
} else {
let value = value.strip_prefix("manylinux_").unwrap_or(&value);
let mut parts = value.split('_');
let x = parts
.next()
.and_then(|x| x.parse::<u16>().ok())
.ok_or("invalid manylinux option")?;
let y = parts
.next()
.and_then(|y| y.parse::<u16>().ok())
.ok_or("invalid manylinux option")?;
Ok(PlatformTag::Manylinux { x, y })
}
}
}
}
}
impl<'de> Deserialize<'de> for PlatformTag {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
FromStr::from_str(&s).map_err(serde::de::Error::custom)
}
}