use crate::{
dep::{Dep, OptDep},
parser::parse_pkg,
};
use anyhow::anyhow;
use chrono::{DateTime, Utc};
use hex;
use std::{
cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd},
collections::BTreeMap,
fmt::{Display, Formatter, Result},
io::BufRead,
str::FromStr,
};
use url::Url;
pub struct Pkgs(BTreeMap<String, Pkg>);
impl Default for Pkgs {
fn default() -> Self {
Self::new()
}
}
impl Pkgs {
pub fn new() -> Pkgs {
Pkgs(BTreeMap::<String, Pkg>::new())
}
pub fn add(&mut self, name: String, pkg: Pkg) {
_ = self.0.insert(name.to_string(), pkg);
}
pub fn contains(&self, name: &str) -> bool {
self.0.contains_key(name)
}
pub fn get(&self, name: &str) -> Option<&Pkg> {
self.0.get(name)
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn names(&self) -> std::collections::btree_map::Keys<'_, String, Pkg> {
self.0.keys()
}
pub fn packages(&self) -> std::collections::btree_map::Values<'_, String, Pkg> {
self.0.values()
}
}
#[derive(Default)]
pub struct Pkg {
pub name: String,
pub file_name: String,
pub base: String,
pub version: String,
pub desc: String,
pub groups: Vec<String>,
pub c_size: usize,
pub i_size: usize,
pub md5_sum: Vec<u8>,
pub sha256_sum: Vec<u8>,
pub pgp_sig: Option<String>,
pub url: Option<Url>,
pub license: Vec<String>,
pub arch: String,
pub build_date: DateTime<Utc>,
pub packager: String,
pub replaces: Vec<String>,
pub conflicts: Vec<String>,
pub provides: Vec<String>,
pub deps: Vec<Dep>,
pub opt_deps: Vec<OptDep>,
pub check_deps: Vec<Dep>,
pub make_deps: Vec<Dep>,
}
impl Ord for Pkg {
fn cmp(&self, other: &Self) -> Ordering {
self.name.cmp(&other.name)
}
}
impl PartialOrd for Pkg {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for Pkg {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}
impl Eq for Pkg {}
macro_rules! writeln_array {
($f:expr , $array:expr) => {
if $array.is_empty() {
writeln!($f, "()")
} else {
writeln!($f, "(")?;
for item in &$array {
writeln!($f, "\t{}", item)?;
}
writeln!($f, ")")
}
};
}
macro_rules! writeln_option {
($f:expr , $option:expr) => {
if let Some(value) = &$option {
writeln!($f, "{}", value)
} else {
writeln!($f, "n/a")
}
};
}
impl Display for Pkg {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
writeln!(f, "[{}]", self.name)?;
writeln!(f, "file_name = {}", self.file_name)?;
writeln!(f, "base = {}", self.base)?;
writeln!(f, "version = {}", self.version)?;
writeln!(f, "desc = {}", self.desc)?;
write!(f, "groups = ")?;
writeln_array!(f, self.groups)?;
writeln!(f, "c_size = {}", self.c_size)?;
writeln!(f, "i_size = {}", self.i_size)?;
writeln!(f, "md5_sum = {}", hex::encode(&self.md5_sum))?;
writeln!(f, "sha256_sum = {}", hex::encode(&self.sha256_sum))?;
write!(f, "pgp_sig = ")?;
writeln_option!(f, self.pgp_sig)?;
write!(f, "url = ")?;
writeln_option!(f, self.url)?;
write!(f, "license = ")?;
writeln_array!(f, self.license)?;
writeln!(f, "arch = {}", self.arch)?;
writeln!(f, "build_date = {}", self.build_date)?;
writeln!(f, "packager = {}", self.packager)?;
write!(f, "replaces = ")?;
writeln_array!(f, self.replaces)?;
write!(f, "conflicts = ")?;
writeln_array!(f, self.conflicts)?;
write!(f, "provides = ")?;
writeln_array!(f, self.provides)?;
write!(f, "depends = ")?;
writeln_array!(f, self.deps)?;
write!(f, "opt_depends = ")?;
writeln_array!(f, self.opt_deps)?;
write!(f, "check_depends = ")?;
writeln_array!(f, self.check_deps)?;
write!(f, "make_depends = ")?;
writeln_array!(f, self.make_deps)
}
}
impl Pkg {
pub fn parse<R: BufRead>(reader: R) -> anyhow::Result<Pkg> {
parse_pkg(reader)
}
}
const EQ: &str = "=";
const GE: &str = ">=";
const GT: &str = ">";
const LE: &str = "<=";
const LT: &str = "<";
pub enum Op {
Eq,
Ge,
Gt,
Le,
Lt,
}
impl Display for Op {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(
f,
"{}",
match self {
Op::Eq => EQ,
Op::Ge => GE,
Op::Gt => GT,
Op::Le => LE,
Op::Lt => LT,
}
)
}
}
impl FromStr for Op {
type Err = anyhow::Error;
fn from_str(s: &str) -> anyhow::Result<Self> {
match s {
EQ => Ok(Op::Eq),
GE => Ok(Op::Ge),
GT => Ok(Op::Gt),
LE => Ok(Op::Le),
LT => Ok(Op::Lt),
_ => Err(anyhow!(format!(
"cannot convert '{s}' to dependency operand"
))),
}
}
}
pub struct Rstr {
pub op: Op,
pub version: String,
}
impl Display for Rstr {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(f, "{} {}", self.op, self.version)
}
}