use crate::{PackrinthError, PackrinthResult, request_text};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct CratesIoVersions {
pub versions: Vec<CratesIoVersion>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct CratesIoVersion {
pub num: String,
}
impl CratesIoVersions {
pub fn from_crate(crate_name: &str) -> PackrinthResult<Self> {
let endpoint = format!("/crates/{crate_name}/versions");
let full_url = format!("https://crates.io/api/v1/{endpoint}");
let crates_io_response = request_text(&full_url)?;
match serde_json::from_str::<Self>(&crates_io_response) {
Ok(versions) => Ok(versions),
Err(error) => Err(PackrinthError::FailedToParseCratesIoResponseJson {
crates_io_endpoint: endpoint.clone(),
error_message: error.to_string(),
}),
}
}
}
pub fn is_new_version_available() -> PackrinthResult<Option<String>> {
let newest_version = &CratesIoVersions::from_crate(env!("CARGO_PKG_NAME"))?.versions[0].num;
let newest_version = match semver::Version::parse(newest_version) {
Ok(version) => version,
Err(error) => {
return Err(PackrinthError::FailedToParseSemverVersion {
version_to_parse: newest_version.clone(),
error_message: error.to_string(),
});
}
};
let current_version = env!("CARGO_PKG_VERSION");
let current_version = match semver::Version::parse(current_version) {
Ok(version) => version,
Err(error) => {
return Err(PackrinthError::FailedToParseSemverVersion {
version_to_parse: current_version.to_string(),
error_message: error.to_string(),
});
}
};
if newest_version > current_version {
Ok(Some(newest_version.to_string()))
} else {
Ok(None)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn versions_from_crate() {
assert!(CratesIoVersions::from_crate(env!("CARGO_PKG_NAME")).is_ok());
}
#[test]
fn new_version_available() {
assert!(is_new_version_available().is_ok());
}
}