use semver::Version;
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct ParsedQtManifest {
pub(crate) schema_version: u8,
pub(crate) artifacts: Vec<ParsedQtArtifact>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub(crate) struct ParsedQtArtifact {
pub(crate) version: Version,
pub(crate) arch: String,
pub(crate) os: String,
pub(crate) url: String,
sha256: String,
pub(crate) content: Vec<String>,
}
impl ParsedQtArtifact {
pub fn download_and_extract(&self, target_path: &Path) -> PathBuf {
let http_client = reqwest::blocking::Client::builder()
.timeout(None)
.build()
.expect("Http client failed to build");
let temp_dir = tempfile::TempDir::new().expect("Could not create temporary directory");
let archive_path =
super::download::download_from_url(&self.url, &self.sha256, &temp_dir, &http_client)
.expect("Could not download url");
self.verify(&super::checksum::hash_file(&archive_path).expect("Could not hash file"))
.expect("Could not verify sha256 hash");
let archive_format = if self.url.ends_with(".tar.gz") {
super::extract::ArchiveFormat::TarGz
} else if self.url.ends_with(".zip") {
super::extract::ArchiveFormat::Zip
} else {
panic!("Unknown archive format to decompress: {}", self.url);
};
super::extract::extract_archive(&archive_path, target_path, archive_format)
.expect("Could not extract archive into target");
target_path.to_path_buf()
}
pub fn new(
version: Version,
arch: String,
os: String,
url: String,
content_type: String,
) -> Self {
Self {
version,
arch,
os,
url,
sha256: "".to_string(),
content: vec![content_type],
}
}
pub fn verify(&self, hash: &[u8]) -> anyhow::Result<()> {
let mut hash_string = String::new();
for byte in hash {
let formatted = format!("{:02x}", byte);
hash_string.push_str(&formatted);
}
if self.sha256 != hash_string {
return Err(anyhow::anyhow!(
"sha256 does not match for: {}, expected: {}, actual: {}",
&self.url,
self.sha256,
hash_string
));
}
Ok(())
}
}