use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::Path;
use crate::platform::Platform;
use crate::Error;
const BUILTIN_TOML: &str = include_str!("../hyperd-version.toml");
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PinnedRelease {
pub version: String,
pub build_id: String,
#[serde(default)]
pub sha256: HashMap<Platform, String>,
}
impl PinnedRelease {
#[must_use]
pub fn builtin() -> Self {
toml::from_str(BUILTIN_TOML).expect("baked-in hyperd-version.toml must parse")
}
pub fn from_toml_str(s: &str) -> Result<Self, Error> {
toml::from_str(s).map_err(Error::TomlParse)
}
pub fn from_toml_file(path: &Path) -> Result<Self, Error> {
let text = std::fs::read_to_string(path).map_err(|source| {
Error::io(format!("reading version file {}", path.display()), source)
})?;
Self::from_toml_str(&text)
}
#[must_use]
pub fn sha256_for(&self, platform: Platform) -> Option<&str> {
self.sha256
.get(&platform)
.map(|s| s.trim())
.filter(|s| !s.is_empty())
}
#[must_use]
pub fn version_tag(&self) -> String {
format!("{}.{}", self.version, self.build_id)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn builtin_parses() {
let r = PinnedRelease::builtin();
assert!(!r.version.is_empty());
assert!(!r.build_id.is_empty());
}
#[test]
fn empty_sha_is_ignored() {
let toml_str = r#"
version = "0.0.1"
build_id = "rc1"
[sha256]
"macos-arm64" = ""
"linux-x86_64" = "abc"
"#;
let r = PinnedRelease::from_toml_str(toml_str).unwrap();
assert!(r.sha256_for(Platform::MacosArm64).is_none());
assert_eq!(r.sha256_for(Platform::LinuxX86_64), Some("abc"));
}
#[test]
fn version_tag_format() {
let r = PinnedRelease {
version: "0.0.24457".to_string(),
build_id: "rc36858b6".to_string(),
sha256: HashMap::new(),
};
assert_eq!(r.version_tag(), "0.0.24457.rc36858b6");
}
}