#[derive(Debug)]
pub enum RepositoryError {
InvalidFormat,
InvalidUri,
MissingUri,
InvalidType,
InvalidSignature,
YesNoForceFieldInvalid,
YesNoFieldInvalid,
UnrecognizedFieldName(String),
Lossy(deb822_fast::Error),
Io(std::io::Error),
Url(url::ParseError),
}
#[derive(Debug)]
pub enum LoadError {
Io {
path: std::path::PathBuf,
error: std::io::Error,
},
Parse {
path: std::path::PathBuf,
error: String,
},
DirectoryRead {
path: std::path::PathBuf,
error: std::io::Error,
},
#[cfg(not(feature = "legacy"))]
UnsupportedLegacyFormat,
}
impl From<std::io::Error> for RepositoryError {
fn from(e: std::io::Error) -> Self {
Self::Io(e)
}
}
impl From<url::ParseError> for RepositoryError {
fn from(e: url::ParseError) -> Self {
Self::Url(e)
}
}
impl std::fmt::Display for RepositoryError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
const YNFERRMSG: &str = "The field requiring only `Yes`/`No`/`Force` values is incorrect";
const YNERRMSG: &str = "The field requiring only `Yes`/`No` values is incorrect";
match self {
Self::InvalidFormat => write!(f, "Invalid repository format"),
Self::InvalidUri => write!(f, "Invalid repository URI"),
Self::MissingUri => write!(f, "Missing repository URI"),
Self::InvalidType => write!(f, "Invalid repository type"),
Self::InvalidSignature => write!(f, "The field `Signed-By` is incorrect"),
Self::YesNoForceFieldInvalid => f.write_str(YNFERRMSG),
Self::YesNoFieldInvalid => f.write_str(YNERRMSG),
Self::UnrecognizedFieldName(name) => write!(
f,
"Unrecognized field name: {name} (check `man sources.list`)"
),
Self::Lossy(e) => write!(f, "Lossy parser error: {e}"),
Self::Io(e) => write!(f, "IO error: {e}"),
Self::Url(e) => write!(f, "URL parse error: {e}"),
}
}
}
impl std::fmt::Display for LoadError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
Self::Io { path, error } => write!(f, "Failed to read {}: {}", path.display(), error),
Self::Parse { path, error } => {
write!(f, "Failed to parse {}: {}", path.display(), error)
}
Self::DirectoryRead { path, error } => {
write!(f, "Failed to read directory {}: {}", path.display(), error)
}
#[cfg(not(feature = "legacy"))]
Self::UnsupportedLegacyFormat => {
write!(
f,
"The support for `legacy` format hadn't been enabled at build time"
)
}
}
}
}
impl std::error::Error for RepositoryError {}
impl std::error::Error for LoadError {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_repository_error_display() {
assert_eq!(
RepositoryError::InvalidFormat.to_string(),
"Invalid repository format"
);
assert_eq!(
RepositoryError::InvalidUri.to_string(),
"Invalid repository URI"
);
assert_eq!(
RepositoryError::MissingUri.to_string(),
"Missing repository URI"
);
assert_eq!(
RepositoryError::InvalidType.to_string(),
"Invalid repository type"
);
assert_eq!(
RepositoryError::InvalidSignature.to_string(),
"The field `Signed-By` is incorrect"
);
assert_eq!(
RepositoryError::UnrecognizedFieldName("foo-bar".to_string()).to_string(),
"Unrecognized field name: foo-bar (check `man sources.list`)"
);
let lossy_err = deb822_fast::Error::UnexpectedEof;
let repo_err = RepositoryError::Lossy(lossy_err);
assert!(repo_err.to_string().contains("Lossy parser error:"));
let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
let repo_err = RepositoryError::from(io_err);
assert!(repo_err.to_string().contains("IO error:"));
}
#[test]
fn test_load_error_display() {
use std::path::PathBuf;
let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
let load_err = LoadError::Io {
path: PathBuf::from("/test/path"),
error: io_err,
};
assert!(load_err.to_string().contains("Failed to read /test/path"));
assert!(load_err.to_string().contains("file not found"));
let parse_err = LoadError::Parse {
path: PathBuf::from("/test/file.list"),
error: "Invalid format".to_string(),
};
assert!(parse_err
.to_string()
.contains("Failed to parse /test/file.list"));
assert!(parse_err.to_string().contains("Invalid format"));
let dir_err = std::io::Error::new(std::io::ErrorKind::PermissionDenied, "access denied");
let load_err = LoadError::DirectoryRead {
path: PathBuf::from("/test/dir"),
error: dir_err,
};
assert!(load_err
.to_string()
.contains("Failed to read directory /test/dir"));
assert!(load_err.to_string().contains("access denied"));
}
}