pub type Result<T, E = Error> = core::result::Result<T, E>;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("asset not found")]
AssetNotFound,
#[error("asset hash not found for asset '{0}'")]
AssetHashNotFound(String),
#[error("Archive hash [{archive_hash}] does not match expected hash [{hash}]")]
ArchiveHashMismatch { archive_hash: String, hash: String },
#[error("version '{0}' is invalid")]
InvalidVersion(String),
#[error(transparent)]
IoError(anyhow::Error),
#[error(transparent)]
ParseError(anyhow::Error),
#[error("poisoned lock '{0}'")]
PoisonedLock(String),
#[error("{0}")]
RepositoryFailure(String),
#[error("{0}")]
Unexpected(String),
#[error("unsupported extractor for '{0}'")]
UnsupportedExtractor(String),
#[error("unsupported hasher for '{0}'")]
UnsupportedHasher(String),
#[error("unsupported matcher for '{0}'")]
UnsupportedMatcher(String),
#[error("unsupported repository for '{0}'")]
UnsupportedRepository(String),
#[error("version not found for '{0}'")]
VersionNotFound(String),
}
impl From<regex::Error> for Error {
fn from(error: regex::Error) -> Self {
Error::ParseError(error.into())
}
}
impl From<reqwest::Error> for Error {
fn from(error: reqwest::Error) -> Self {
Error::IoError(error.into())
}
}
impl From<reqwest_middleware::Error> for Error {
fn from(error: reqwest_middleware::Error) -> Self {
Error::IoError(error.into())
}
}
impl From<std::io::Error> for Error {
fn from(error: std::io::Error) -> Self {
Error::IoError(error.into())
}
}
impl From<std::time::SystemTimeError> for Error {
fn from(error: std::time::SystemTimeError) -> Self {
Error::IoError(error.into())
}
}
impl From<std::num::ParseIntError> for Error {
fn from(error: std::num::ParseIntError) -> Self {
Error::ParseError(error.into())
}
}
impl From<semver::Error> for Error {
fn from(error: semver::Error) -> Self {
Error::IoError(error.into())
}
}
impl From<std::path::StripPrefixError> for Error {
fn from(error: std::path::StripPrefixError) -> Self {
Error::ParseError(error.into())
}
}
impl From<anyhow::Error> for Error {
fn from(error: anyhow::Error) -> Self {
Error::Unexpected(error.to_string())
}
}
impl From<url::ParseError> for Error {
fn from(error: url::ParseError) -> Self {
Error::ParseError(error.into())
}
}
#[cfg(test)]
mod test {
use super::*;
use anyhow::anyhow;
use semver::VersionReq;
use std::ops::Add;
use std::path::PathBuf;
use std::str::FromStr;
use std::time::{Duration, SystemTime};
#[test]
fn test_from_regex_error() {
let regex_error = regex::Error::Syntax("test".to_string());
let error = Error::from(regex_error);
assert_eq!(error.to_string(), "test");
}
#[tokio::test]
async fn test_from_reqwest_error() {
let result = reqwest::get("https://a.com").await;
assert!(result.is_err());
if let Err(error) = result {
let error = Error::from(error);
assert!(error.to_string().contains("https://a.com"));
}
}
#[tokio::test]
async fn test_from_reqwest_middeleware_error() {
let reqwest_middleware_error =
reqwest_middleware::Error::Middleware(anyhow!("middleware error: test"));
let error = Error::from(reqwest_middleware_error);
assert!(error.to_string().contains("middleware error: test"));
}
#[test]
fn test_from_io_error() {
let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, "test");
let error = Error::from(io_error);
assert_eq!(error.to_string(), "test");
}
#[test]
fn test_from_parse_int_error() {
let parse_int_error = u64::from_str("test").expect_err("parse int error");
let error = Error::from(parse_int_error);
assert_eq!(error.to_string(), "invalid digit found in string");
}
#[test]
fn test_from_semver_error() {
let semver_error = VersionReq::parse("foo").expect_err("semver error");
let error = Error::from(semver_error);
assert_eq!(
error.to_string(),
"unexpected character 'f' while parsing major version number"
);
}
#[test]
fn test_from_strip_prefix_error() {
let path = PathBuf::from("test");
let stip_prefix_error = path.strip_prefix("foo").expect_err("strip prefix error");
let error = Error::from(stip_prefix_error);
assert_eq!(error.to_string(), "prefix not found");
}
#[test]
fn test_from_system_time_error() {
let future_time = SystemTime::now().add(Duration::from_secs(300));
let system_time_error = SystemTime::now()
.duration_since(future_time)
.expect_err("system time error");
let error = Error::from(system_time_error);
assert_eq!(
error.to_string(),
"second time provided was later than self"
);
}
#[test]
fn test_from_anyhow_error() {
let anyhow_error = anyhow::Error::msg("test");
let error = Error::from(anyhow_error);
assert_eq!(error.to_string(), "test");
}
#[test]
fn test_from_url_parse_error() {
let parse_error = url::ParseError::EmptyHost;
let error = Error::from(parse_error);
assert_eq!(error.to_string(), "empty host");
}
}