use crate::dep::Dependencies;
use crate::files::Files;
use crate::internal::header::Header;
use crate::{RpmErrorKind, Tag, TagData};
use std::convert::TryFrom;
use std::hash::{Hash, Hasher};
use std::{fmt, path::Path, time};
pub struct Package {
header: Header,
}
impl Package {
pub(crate) fn from_header(h: &Header) -> Self {
Package { header: h.clone() }
}
pub fn from_file(path: &Path) -> Result<Self, RpmErrorKind> {
let header = Header::from_file(path)?;
Ok(Package { header })
}
pub fn get(&self, tag: Tag) -> Option<TagData<'_>> {
self.header.get(tag)
}
pub fn name(&self) -> &str {
self.header
.get(Tag::NAME)
.expect("NAME tag missing")
.as_str()
.expect("NAME tag is not a string")
}
pub fn epoch(&self) -> Option<i32> {
self.header
.get(Tag::EPOCH)
.map(|d| d.as_int32().expect("EPOCH tag is not an int32"))
}
pub fn version(&self) -> &str {
self.header
.get(Tag::VERSION)
.expect("VERSION tag missing")
.as_str()
.expect("VERSION tag is not a string")
}
pub fn release(&self) -> &str {
self.header
.get(Tag::RELEASE)
.expect("RELEASE tag missing")
.as_str()
.expect("RELEASE tag is not a string")
}
pub fn arch(&self) -> Option<&str> {
self.header
.get(Tag::ARCH)
.map(|d| d.as_str().expect("ARCH tag is not a string"))
}
pub fn evr(&self) -> String {
if let Some(epoch) = self.epoch() {
format!("{}:{}-{}", epoch, self.version(), self.release())
} else {
format!("{}-{}", self.version(), self.release())
}
}
pub fn nevra(&self) -> String {
if let Some(arch) = self.arch() {
format!("{}-{}.{}", self.name(), self.evr(), arch)
} else {
format!("{}-{}", self.name(), self.evr())
}
}
pub fn license(&self) -> &str {
self.header
.get(Tag::LICENSE)
.expect("LICENSE tag missing")
.as_str()
.expect("LICENSE tag is not a string")
}
pub fn summary(&self) -> &str {
self.header
.get(Tag::SUMMARY)
.expect("SUMMARY tag missing")
.as_str()
.expect("SUMMARY tag is not a string")
}
pub fn description(&self) -> &str {
self.header
.get(Tag::DESCRIPTION)
.expect("DESCRIPTION tag missing")
.as_str()
.expect("DESCRIPTION tag is not a string")
}
pub fn files(&self) -> Files {
Files::from_header(&self.header)
}
pub fn requires(&self) -> Dependencies {
Dependencies::from_header(&self.header, Tag::REQUIRENAME)
}
pub fn provides(&self) -> Dependencies {
Dependencies::from_header(&self.header, Tag::PROVIDENAME)
}
pub fn conflicts(&self) -> Dependencies {
Dependencies::from_header(&self.header, Tag::CONFLICTNAME)
}
pub fn obsoletes(&self) -> Dependencies {
Dependencies::from_header(&self.header, Tag::OBSOLETENAME)
}
pub fn recommends(&self) -> Dependencies {
Dependencies::from_header(&self.header, Tag::RECOMMENDNAME)
}
pub fn suggests(&self) -> Dependencies {
Dependencies::from_header(&self.header, Tag::SUGGESTNAME)
}
pub fn supplements(&self) -> Dependencies {
Dependencies::from_header(&self.header, Tag::SUPPLEMENTNAME)
}
pub fn enhances(&self) -> Dependencies {
Dependencies::from_header(&self.header, Tag::ENHANCENAME)
}
pub fn buildtime(&self) -> time::SystemTime {
let buildtime = self
.header
.get(Tag::BUILDTIME)
.expect("BUILDTIME tag missing")
.as_int32()
.expect("BUILDTIME tag is not an int32");
let buildtime = u64::try_from(buildtime).expect("negative build time");
time::SystemTime::UNIX_EPOCH + time::Duration::new(buildtime, 0)
}
}
impl Clone for Package {
fn clone(&self) -> Self {
Package {
header: self.header.clone(),
}
}
}
impl fmt::Debug for Package {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Package")
.field("name", &self.name())
.field("epoch", &self.epoch())
.field("version", &self.version())
.field("release", &self.release())
.field("arch", &self.arch())
.finish()
}
}
impl fmt::Display for Package {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.nevra())
}
}
impl PartialEq for Package {
fn eq(&self, other: &Self) -> bool {
self.name() == other.name()
&& self.epoch() == other.epoch()
&& self.version() == other.version()
&& self.release() == other.release()
&& self.arch() == other.arch()
}
}
impl Eq for Package {}
impl Hash for Package {
fn hash<H: Hasher>(&self, state: &mut H) {
self.name().hash(state);
self.epoch().hash(state);
self.version().hash(state);
self.release().hash(state);
self.arch().hash(state);
}
}