use std::{borrow::Cow, collections::BTreeMap};
use serde::{Deserialize, Serialize};
use strum_macros::{EnumCount, VariantArray};
mod package_formats;
#[doc(inline)]
pub use package_formats::*;
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct Meta {
pub binstall: Option<PkgMeta>,
}
#[derive(
Debug,
Copy,
Clone,
Eq,
PartialEq,
Ord,
PartialOrd,
EnumCount,
VariantArray,
Deserialize,
Serialize,
)]
#[serde(rename_all = "kebab-case")]
pub enum Strategy {
CrateMetaData,
QuickInstall,
Compile,
}
impl Strategy {
pub const fn to_str(self) -> &'static str {
match self {
Strategy::CrateMetaData => "crate-meta-data",
Strategy::QuickInstall => "quick-install",
Strategy::Compile => "compile",
}
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case", default)]
pub struct PkgMeta {
pub pkg_url: Option<String>,
pub pkg_fmt: Option<PkgFmt>,
pub bin_dir: Option<String>,
pub signing: Option<PkgSigning>,
pub disabled_strategies: Option<Box<[Strategy]>>,
pub overrides: BTreeMap<String, PkgOverride>,
}
impl PkgMeta {
pub fn merge(&mut self, pkg_override: &PkgOverride) {
if let Some(o) = &pkg_override.pkg_url {
self.pkg_url = Some(o.clone());
}
if let Some(o) = &pkg_override.pkg_fmt {
self.pkg_fmt = Some(*o);
}
if let Some(o) = &pkg_override.bin_dir {
self.bin_dir = Some(o.clone());
}
}
pub fn merge_overrides<'a, It>(&self, pkg_overrides: It) -> Self
where
It: IntoIterator<Item = &'a PkgOverride> + Clone,
{
let ignore_disabled_strategies = pkg_overrides
.clone()
.into_iter()
.any(|pkg_override| pkg_override.ignore_disabled_strategies);
Self {
pkg_url: pkg_overrides
.clone()
.into_iter()
.find_map(|pkg_override| pkg_override.pkg_url.clone())
.or_else(|| self.pkg_url.clone()),
pkg_fmt: pkg_overrides
.clone()
.into_iter()
.find_map(|pkg_override| pkg_override.pkg_fmt)
.or(self.pkg_fmt),
bin_dir: pkg_overrides
.clone()
.into_iter()
.find_map(|pkg_override| pkg_override.bin_dir.clone())
.or_else(|| self.bin_dir.clone()),
signing: pkg_overrides
.clone()
.into_iter()
.find_map(|pkg_override| pkg_override.signing.clone())
.or_else(|| self.signing.clone()),
disabled_strategies: if ignore_disabled_strategies {
None
} else {
let mut disabled_strategies = pkg_overrides
.into_iter()
.filter_map(|pkg_override| pkg_override.disabled_strategies.as_deref())
.flatten()
.chain(self.disabled_strategies.as_deref().into_iter().flatten())
.copied()
.collect::<Vec<Strategy>>();
disabled_strategies.sort_unstable();
disabled_strategies.dedup();
Some(disabled_strategies.into_boxed_slice())
},
overrides: Default::default(),
}
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case", default)]
pub struct PkgOverride {
pub pkg_url: Option<String>,
pub pkg_fmt: Option<PkgFmt>,
pub bin_dir: Option<String>,
pub disabled_strategies: Option<Box<[Strategy]>>,
pub signing: Option<PkgSigning>,
#[serde(skip)]
pub ignore_disabled_strategies: bool,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct BinMeta {
pub name: String,
pub path: String,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct PkgSigning {
pub algorithm: SigningAlgorithm,
pub pubkey: Cow<'static, str>,
#[serde(default)]
pub file: Option<String>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
#[non_exhaustive]
pub enum SigningAlgorithm {
Minisign,
}
#[cfg(test)]
mod tests {
use strum::VariantArray;
use super::*;
#[test]
fn test_strategy_ser() {
Strategy::VARIANTS.iter().for_each(|strategy| {
assert_eq!(
serde_json::to_string(&strategy).unwrap(),
format!(r#""{}""#, strategy.to_str())
)
});
}
}