use crate::packer::PackToml;
use crate::packer::pack_toml::{PartialPackToml, parse_validate_pack_toml};
use crate::support::zip;
use crate::{Error, Result};
use lazy_regex::regex;
use semver::Version;
use simple_fs::SPath;
pub fn extract_pack_toml_from_pack_file(path_to_aipack: &SPath) -> Result<PackToml> {
let toml_content = zip::extract_text_content(path_to_aipack, "pack.toml").map_err(|e| Error::FailToInstall {
aipack_ref: path_to_aipack.as_str().to_string(),
cause: format!("Failed to extract pack.toml: {}", e),
})?;
let pack_toml =
parse_validate_pack_toml(&toml_content, &format!("pack.toml for {}", path_to_aipack)).map_err(|e| {
Error::FailToInstall {
aipack_ref: path_to_aipack.as_str().to_string(),
cause: format!("Invalid pack.toml: {}", e),
}
})?;
Ok(pack_toml)
}
#[allow(unused)]
pub fn extract_partial_pack_toml_from_pack_file(path_to_aipack: &SPath) -> Result<PartialPackToml> {
let toml_content = zip::extract_text_content(path_to_aipack, "pack.toml").map_err(|e| Error::FailToInstall {
aipack_ref: path_to_aipack.as_str().to_string(),
cause: format!("Failed to extract pack.toml: {}", e),
})?;
let partial_pack_toml = toml::from_str(&toml_content).map_err(|e| Error::FailToInstall {
aipack_ref: path_to_aipack.as_str().to_string(),
cause: format!("Failed to parse pack.toml: {}", e),
})?;
Ok(partial_pack_toml)
}
pub fn validate_aipack_file(aipack_file: &SPath, reference: &str) -> Result<()> {
if !aipack_file.exists() {
return Err(Error::FailToInstall {
aipack_ref: reference.to_string(),
cause: "aipack file does not exist".to_string(),
});
}
if aipack_file.ext() != "aipack" {
return Err(Error::FailToInstall {
aipack_ref: reference.to_string(),
cause: format!("aipack file must be '.aipack' file, but was {}", aipack_file.name()),
});
}
Ok(())
}
pub fn validate_version_update(installed_version: &str, new_version: &str) -> Result<()> {
let installed = installed_version.trim_start_matches('v');
let new = new_version.trim_start_matches('v');
match (Version::parse(installed), Version::parse(new)) {
(Ok(installed_semver), Ok(new_semver)) => {
if installed_semver > new_semver {
return Err(Error::InstallFailInstalledVersionAbove {
installed_version: installed_version.to_string(),
new_version: new_version.to_string(),
});
}
}
_ => {}
}
Ok(())
}
pub fn validate_version_for_install(version: &str) -> Result<()> {
let version_str = version.trim_start_matches('v');
if let Some(hyphen_idx) = version_str.find('-') {
let prerelease = &version_str[hyphen_idx + 1..];
let prerelease_ending_with_number = regex!(r"\.[0-9]+$");
if !prerelease_ending_with_number.is_match(prerelease) {
return Err(Error::InvalidPrereleaseFormat {
version: version.to_string(),
});
}
}
Ok(())
}
pub fn get_file_size(file_path: &SPath, reference: &str) -> Result<usize> {
let metadata = std::fs::metadata(file_path.path()).map_err(|e| Error::FailToInstall {
aipack_ref: reference.to_string(),
cause: format!("Failed to get file metadata: {}", e),
})?;
Ok(metadata.len() as usize)
}
pub fn calculate_directory_size(dir_path: &SPath) -> Result<usize> {
use walkdir::WalkDir;
let total_size = WalkDir::new(dir_path.path())
.into_iter()
.filter_map(|entry| entry.ok())
.filter_map(|entry| entry.metadata().ok())
.filter(|metadata| metadata.is_file())
.map(|metadata| metadata.len() as usize)
.sum();
Ok(total_size)
}
#[cfg(test)]
mod tests {
type Result<T> = core::result::Result<T, Box<dyn std::error::Error>>;
use super::*;
use crate::Error;
#[test]
fn test_validate_version_update() -> Result<()> {
assert!(validate_version_update("1.0.0", "1.0.1").is_ok());
assert!(validate_version_update("1.0.0", "1.1.0").is_ok());
assert!(validate_version_update("1.0.0", "2.0.0").is_ok());
assert!(validate_version_update("1.0.0", "1.0.0").is_ok());
let err = validate_version_update("1.0.1", "1.0.0").unwrap_err();
match err {
Error::InstallFailInstalledVersionAbove {
installed_version,
new_version,
} => {
assert_eq!(installed_version, "1.0.1");
assert_eq!(new_version, "1.0.0");
}
_ => panic!("Expected InstallFailInstalledVersionAbove error"),
}
assert!(validate_version_update("v1.0.0", "1.0.1").is_ok());
assert!(validate_version_update("1.0.0", "v1.0.1").is_ok());
assert!(validate_version_update("invalid", "1.0.0").is_ok());
assert!(validate_version_update("1.0.0", "invalid").is_ok());
assert!(validate_version_update("invalid", "invalid").is_ok());
Ok(())
}
#[test]
fn test_validate_version_for_install() -> Result<()> {
assert!(validate_version_for_install("0.1.0").is_ok());
assert!(validate_version_for_install("1.0.0").is_ok());
assert!(validate_version_for_install("0.1.1-alpha.1").is_ok());
assert!(validate_version_for_install("0.1.1-beta.123").is_ok());
assert!(validate_version_for_install("0.1.1-rc.1.2").is_ok());
assert!(validate_version_for_install("v1.0.0-alpha.1").is_ok());
let err = validate_version_for_install("0.1.1-alpha").unwrap_err();
match err {
Error::InvalidPrereleaseFormat { version } => {
assert_eq!(version, "0.1.1-alpha");
}
_ => panic!("Expected InvalidPrereleaseFormat error"),
}
let err = validate_version_for_install("0.1.1-alpha.text").unwrap_err();
match err {
Error::InvalidPrereleaseFormat { version } => {
assert_eq!(version, "0.1.1-alpha.text");
}
_ => panic!("Expected InvalidPrereleaseFormat error"),
}
let err = validate_version_for_install("0.1.1-alpha.1.some").unwrap_err();
match err {
Error::InvalidPrereleaseFormat { version } => {
assert_eq!(version, "0.1.1-alpha.1.some");
}
_ => panic!("Expected InvalidPrereleaseFormat error"),
}
Ok(())
}
}