use crate::Error;
use serde::{
de::{self, Deserializer, Visitor},
Deserialize, Serialize, Serializer,
};
use std::{fmt, str::FromStr};
use time::OffsetDateTime;
use url::Url;
pub const FILE_STEM: &str = "saveoursecrets";
pub const SIG_EXT: &str = "sig.txt";
pub const SHA_EXT: &str = "sha256.txt";
#[derive(Debug, Serialize, Deserialize)]
pub struct Artifact {
pub platform: Platform,
pub arch: Arch,
pub name: String,
pub version: semver::Version,
#[serde(with = "hex::serde")]
pub sha256: Vec<u8>,
pub timestamp: OffsetDateTime,
#[serde(skip_serializing_if = "Option::is_none")]
pub commit: Option<String>,
pub size: u64,
#[serde(skip_serializing_if = "Option::is_none")]
pub artifact: Option<Url>,
#[serde(skip_serializing_if = "Option::is_none")]
pub store: Option<Url>,
}
#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Channel {
Beta,
Stable,
Canary,
}
impl fmt::Display for Channel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
Self::Stable => "stable",
Self::Beta => "beta",
Self::Canary => "canary",
}
)
}
}
impl FromStr for Channel {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"stable" => Self::Stable,
"beta" => Self::Beta,
_ => return Err(Error::UnknownChannel(s.to_owned())),
})
}
}
#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Arch {
Universal,
X86_64,
Aarch64,
}
impl fmt::Display for Arch {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
Self::Universal => "universal",
Self::X86_64 => "x86_64",
Self::Aarch64 => "aarch64",
}
)
}
}
impl FromStr for Arch {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"universal" => Self::Universal,
"x86_64" => Self::X86_64,
"aarch64" => Self::Aarch64,
_ => return Err(Error::UnknownArch(s.to_owned())),
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Collection {
Cli,
Gui,
}
impl fmt::Display for Collection {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
Self::Cli => "cli",
Self::Gui => "gui",
}
)
}
}
impl FromStr for Collection {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"cli" => Self::Cli,
"gui" => Self::Gui,
_ => return Err(Error::UnknownCollection(s.to_owned())),
})
}
}
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub enum Platform {
Linux(Distro),
Windows,
MacOS,
#[allow(non_camel_case_types)]
iOS,
Android,
}
impl fmt::Display for Platform {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
Self::Linux(distro) => match distro {
Distro::Unknown => "linux",
Distro::Debian => "debian",
Distro::RedHat => "redhat",
Distro::Flatpak => "flatpak",
},
Self::Windows => "windows",
Self::MacOS => "macos",
Self::iOS => "ios",
Self::Android => "android",
}
)
}
}
impl FromStr for Platform {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"linux" => Self::Linux(Distro::Unknown),
"debian" => Self::Linux(Distro::Debian),
"redhat" => Self::Linux(Distro::RedHat),
"flatpak" => Self::Linux(Distro::Flatpak),
"windows" => Self::Windows,
"macos" => Self::MacOS,
"ios" => Self::iOS,
"android" => Self::Android,
_ => return Err(Error::UnknownPlatform(s.to_owned())),
})
}
}
impl Serialize for Platform {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
impl<'de> Deserialize<'de> for Platform {
fn deserialize<D>(deserializer: D) -> Result<Platform, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_str(PlatformVisitor)
}
}
struct PlatformVisitor;
impl<'de> Visitor<'de> for PlatformVisitor {
type Value = Platform;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a valid platform identifier")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
let platform: Platform = value.parse().map_err(E::custom)?;
Ok(platform)
}
}
#[derive(
Default, Debug, Hash, Eq, PartialEq, Clone, Serialize, Deserialize,
)]
#[serde(rename_all = "lowercase")]
pub enum Distro {
#[default]
Unknown,
Debian,
RedHat,
Flatpak,
}
impl fmt::Display for Distro {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
Self::Unknown => "linux",
Self::Debian => "debian",
Self::RedHat => "redhat",
Self::Flatpak => "flatpak",
}
)
}
}
impl FromStr for Distro {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"linux" => Self::Unknown,
"debian" => Self::Debian,
"redhat" => Self::RedHat,
"flatpak" => Self::Flatpak,
_ => return Err(Error::UnknownDistro(s.to_owned())),
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Variant {
None,
Musl,
}
impl fmt::Display for Variant {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
Self::None => "none",
Self::Musl => "musl",
}
)
}
}
impl FromStr for Variant {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"none" => Self::None,
"musl" => Self::Musl,
_ => return Err(Error::UnknownVariant(s.to_owned())),
})
}
}