use std::fmt;
use enum_as_inner::EnumAsInner;
use scallop::ExecStatus;
use crate::dep::{Cpv, Version};
use crate::eapi::{self, Restrict as EapiRestrict};
use crate::repo::{Repo, Repository};
use crate::restrict::dep::Restrict as DepRestrict;
use crate::restrict::str::Restrict as StrRestrict;
use crate::restrict::{Restrict as BaseRestrict, Restriction};
pub mod ebuild;
pub mod fake;
#[allow(clippy::large_enum_variant)]
#[derive(EnumAsInner, Debug)]
pub enum Pkg<'a> {
Configured(ebuild::configured::Pkg<'a>, &'a Repo),
Ebuild(ebuild::Pkg<'a>, &'a Repo),
Fake(fake::Pkg<'a>, &'a Repo),
}
make_pkg_traits!(Pkg<'_>);
pub trait Package: fmt::Debug + fmt::Display + PartialEq + Eq + PartialOrd + Ord {
type Repo: Repository;
fn eapi(&self) -> &'static eapi::Eapi;
fn repo(&self) -> Self::Repo;
fn cpv(&self) -> &Cpv;
fn version(&self) -> &Version {
self.cpv().version()
}
fn p(&self) -> String {
self.cpv().p()
}
fn pf(&self) -> String {
self.cpv().pf()
}
fn pr(&self) -> String {
self.cpv().pr()
}
fn pv(&self) -> String {
self.cpv().pv()
}
fn pvr(&self) -> String {
self.cpv().pvr()
}
fn cpn(&self) -> String {
self.cpv().cpn()
}
}
pub trait BuildPackage: Package {
fn build(&self) -> scallop::Result<()>;
fn pretend(&self) -> scallop::Result<()>;
}
pub trait SourcePackage: Package {
fn source(&self) -> scallop::Result<ExecStatus>;
}
pub(crate) trait PackageMetadata: Package {
fn metadata(&self) -> scallop::Result<()>;
}
macro_rules! make_pkg_traits {
($($x:ty),+) => {$(
impl crate::error::PackageError for $x {}
impl PartialEq for $x {
fn eq(&self, other: &Self) -> bool {
self.repo() == other.repo() && self.cpv() == other.cpv()
}
}
impl Eq for $x {}
impl std::hash::Hash for $x {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.repo().hash(state);
self.cpv().hash(state);
}
}
impl PartialOrd for $x {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for $x {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
crate::macros::cmp_not_equal!(self.cpv(), other.cpv());
self.repo().cmp(&other.repo())
}
}
impl std::fmt::Display for $x {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
use crate::repo::Repository;
write!(f, "{}::{}", self.cpv(), self.repo().id())
}
}
impl From<&$x> for crate::restrict::Restrict {
fn from(pkg: &$x) -> Self {
let r1 = pkg.cpv().into();
let r2 = crate::restrict::Restrict::Dep(pkg.repo().into());
crate::restrict::Restrict::and([r1, r2])
}
}
)+};
}
use make_pkg_traits;
impl<'a> Package for Pkg<'a> {
type Repo = &'a Repo;
fn cpv(&self) -> &Cpv {
match self {
Self::Configured(pkg, _) => pkg.cpv(),
Self::Ebuild(pkg, _) => pkg.cpv(),
Self::Fake(pkg, _) => pkg.cpv(),
}
}
fn eapi(&self) -> &'static eapi::Eapi {
match self {
Self::Configured(pkg, _) => pkg.eapi(),
Self::Ebuild(pkg, _) => pkg.eapi(),
Self::Fake(pkg, _) => pkg.eapi(),
}
}
fn repo(&self) -> Self::Repo {
match self {
Self::Configured(_, repo) => repo,
Self::Ebuild(_, repo) => repo,
Self::Fake(_, repo) => repo,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Restrict {
Eapi(EapiRestrict),
Ebuild(ebuild::Restrict),
Repo(StrRestrict),
}
impl Restrict {
pub fn eapi(s: &str) -> Self {
Self::Eapi(EapiRestrict::Id(StrRestrict::equal(s)))
}
pub fn repo(s: &str) -> Self {
Self::Repo(StrRestrict::equal(s))
}
}
impl From<Restrict> for BaseRestrict {
fn from(r: Restrict) -> Self {
Self::Pkg(r)
}
}
impl<'a> Restriction<&'a Pkg<'a>> for Restrict {
fn matches(&self, pkg: &'a Pkg<'a>) -> bool {
use Restrict::*;
match self {
Eapi(r) => r.matches(pkg.eapi()),
Repo(r) => r.matches(pkg.repo().id()),
Ebuild(r) => match pkg {
Pkg::Ebuild(p, _) => r.matches(p),
_ => false,
},
}
}
}
impl<'a> Restriction<&'a Pkg<'a>> for BaseRestrict {
fn matches(&self, pkg: &'a Pkg<'a>) -> bool {
use BaseRestrict::*;
crate::restrict::restrict_match! {self, pkg,
Dep(r) => r.matches(pkg),
Pkg(r) => r.matches(pkg),
}
}
}
impl<'a> Restriction<&'a Pkg<'a>> for DepRestrict {
fn matches(&self, pkg: &'a Pkg<'a>) -> bool {
use DepRestrict::*;
match self {
Repo(Some(r)) => r.matches(pkg.repo().id()),
r => r.matches(pkg.cpv()),
}
}
}
#[cfg(test)]
mod tests {
use crate::config::Config;
use crate::repo::{fake, PkgRepository};
use super::*;
#[test]
fn test_ordering() {
let mut config = Config::default();
let r1: Repo = fake::Repo::new("b", 0).pkgs(["cat/pkg-1"]).into();
let t = config.temp_repo("a", 0, None).unwrap();
t.create_raw_pkg("cat/pkg-0", &[]).unwrap();
let mut pkgs: Vec<_> = r1.iter().chain(t.repo.iter()).collect();
pkgs.sort();
let pkg_strs: Vec<_> = pkgs.iter().map(|p| p.to_string()).collect();
assert_eq!(pkg_strs, ["cat/pkg-0::a", "cat/pkg-1::b"]);
let r1: Repo = fake::Repo::new("a", -1).pkgs(["cat/pkg-0"]).into();
let t = config.temp_repo("b", 0, None).unwrap();
t.create_raw_pkg("cat/pkg-0", &[]).unwrap();
let mut pkgs: Vec<_> = r1.iter().chain(t.repo.iter()).collect();
pkgs.sort();
let pkg_strs: Vec<_> = pkgs.iter().map(|p| p.to_string()).collect();
assert_eq!(pkg_strs, ["cat/pkg-0::b", "cat/pkg-0::a"]);
let r1: Repo = fake::Repo::new("2", 0).pkgs(["cat/pkg-0"]).into();
let t = config.temp_repo("1", 0, None).unwrap();
t.create_raw_pkg("cat/pkg-0", &[]).unwrap();
let mut pkgs: Vec<_> = r1.iter().chain(t.repo.iter()).collect();
pkgs.sort();
let pkg_strs: Vec<_> = pkgs.iter().map(|p| p.to_string()).collect();
assert_eq!(pkg_strs, ["cat/pkg-0::1", "cat/pkg-0::2"]);
}
#[test]
fn package_trait_attributes() {
let cpv = Cpv::new("cat/pkg-1-r2").unwrap();
let r: Repo = fake::Repo::new("b", 0).pkgs([&cpv]).into();
let pkg = r.iter_restrict(&cpv).next().unwrap();
assert_eq!(pkg.p(), "pkg-1");
assert_eq!(pkg.pf(), "pkg-1-r2");
assert_eq!(pkg.pr(), "r2");
assert_eq!(pkg.pv(), "1");
assert_eq!(pkg.pvr(), "1-r2");
assert_eq!(pkg.cpn(), "cat/pkg");
}
}