use std::ffi::CStr;
use std::fmt;
use crate::Tag;
use crate::internal::header::Header;
pub struct Dependencies {
entries: Vec<Dependency>,
}
impl Dependencies {
pub(crate) fn from_header(header: &Header, tag: Tag) -> Self {
let ds = unsafe { librpm_sys::rpmdsNew(header.as_ptr(), tag as librpm_sys::rpmTagVal, 0) };
if ds.is_null() {
return Dependencies {
entries: Vec::new(),
};
}
let count = unsafe { librpm_sys::rpmdsCount(ds) };
let mut entries = Vec::with_capacity(count.max(0) as usize);
unsafe { librpm_sys::rpmdsInit(ds) };
while unsafe { librpm_sys::rpmdsNext(ds) } >= 0 {
let name = unsafe {
let p = librpm_sys::rpmdsN(ds);
assert!(!p.is_null());
CStr::from_ptr(p)
.to_str()
.expect("dependency name is not UTF-8")
.to_owned()
};
let evr_raw = unsafe {
let p = librpm_sys::rpmdsEVR(ds);
assert!(!p.is_null());
CStr::from_ptr(p)
.to_str()
.expect("dependency EVR is not UTF-8")
};
let evr = if evr_raw.is_empty() {
None
} else {
Some(evr_raw.to_owned())
};
let flags = DepFlags(unsafe { librpm_sys::rpmdsFlags(ds) });
entries.push(Dependency { name, evr, flags });
}
unsafe { librpm_sys::rpmdsFree(ds) };
Dependencies { entries }
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn iter(&self) -> std::slice::Iter<'_, Dependency> {
self.entries.iter()
}
}
impl fmt::Debug for Dependencies {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Dependencies")
.field("len", &self.len())
.finish()
}
}
impl<'a> IntoIterator for &'a Dependencies {
type Item = &'a Dependency;
type IntoIter = std::slice::Iter<'a, Dependency>;
fn into_iter(self) -> std::slice::Iter<'a, Dependency> {
self.iter()
}
}
impl IntoIterator for Dependencies {
type Item = Dependency;
type IntoIter = std::vec::IntoIter<Dependency>;
fn into_iter(self) -> std::vec::IntoIter<Dependency> {
self.entries.into_iter()
}
}
#[derive(Debug, Clone)]
pub struct Dependency {
name: String,
evr: Option<String>,
flags: DepFlags,
}
impl Dependency {
pub fn name(&self) -> &str {
&self.name
}
pub fn evr(&self) -> Option<&str> {
self.evr.as_deref()
}
pub fn flags(&self) -> DepFlags {
self.flags
}
}
impl fmt::Display for Dependency {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.name)?;
if let Some(evr) = &self.evr {
let op = self.flags.version_cmp_str();
if !op.is_empty() {
write!(f, " {op} {evr}")?;
}
}
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DepFlags(u32);
impl DepFlags {
pub fn bits(self) -> u32 {
self.0
}
pub fn version_cmp_str(self) -> &'static str {
let cmp = self.0
& (librpm_sys::rpmsenseFlags_e_RPMSENSE_LESS
| librpm_sys::rpmsenseFlags_e_RPMSENSE_GREATER
| librpm_sys::rpmsenseFlags_e_RPMSENSE_EQUAL);
match cmp {
0 => "",
x if x == librpm_sys::rpmsenseFlags_e_RPMSENSE_LESS => "<",
x if x == librpm_sys::rpmsenseFlags_e_RPMSENSE_GREATER => ">",
x if x == librpm_sys::rpmsenseFlags_e_RPMSENSE_EQUAL => "=",
x if x
== (librpm_sys::rpmsenseFlags_e_RPMSENSE_LESS
| librpm_sys::rpmsenseFlags_e_RPMSENSE_EQUAL) =>
{
"<="
}
x if x
== (librpm_sys::rpmsenseFlags_e_RPMSENSE_GREATER
| librpm_sys::rpmsenseFlags_e_RPMSENSE_EQUAL) =>
{
">="
}
_ => "?",
}
}
pub fn is_less(self) -> bool {
self.0 & librpm_sys::rpmsenseFlags_e_RPMSENSE_LESS != 0
}
pub fn is_greater(self) -> bool {
self.0 & librpm_sys::rpmsenseFlags_e_RPMSENSE_GREATER != 0
}
pub fn is_equal(self) -> bool {
self.0 & librpm_sys::rpmsenseFlags_e_RPMSENSE_EQUAL != 0
}
pub fn is_prereq(self) -> bool {
self.0 & librpm_sys::rpmsenseFlags_e_RPMSENSE_PREREQ != 0
}
pub fn is_rpmlib(self) -> bool {
self.0 & librpm_sys::rpmsenseFlags_e_RPMSENSE_RPMLIB != 0
}
pub fn is_script_pre(self) -> bool {
self.0 & librpm_sys::rpmsenseFlags_e_RPMSENSE_SCRIPT_PRE != 0
}
pub fn is_script_post(self) -> bool {
self.0 & librpm_sys::rpmsenseFlags_e_RPMSENSE_SCRIPT_POST != 0
}
pub fn is_script_preun(self) -> bool {
self.0 & librpm_sys::rpmsenseFlags_e_RPMSENSE_SCRIPT_PREUN != 0
}
pub fn is_script_postun(self) -> bool {
self.0 & librpm_sys::rpmsenseFlags_e_RPMSENSE_SCRIPT_POSTUN != 0
}
pub fn is_pretrans(self) -> bool {
self.0 & librpm_sys::rpmsenseFlags_e_RPMSENSE_PRETRANS != 0
}
pub fn is_posttrans(self) -> bool {
self.0 & librpm_sys::rpmsenseFlags_e_RPMSENSE_POSTTRANS != 0
}
pub fn is_config(self) -> bool {
self.0 & librpm_sys::rpmsenseFlags_e_RPMSENSE_CONFIG != 0
}
pub fn is_meta(self) -> bool {
self.0 & librpm_sys::rpmsenseFlags_e_RPMSENSE_META != 0
}
}