diff --git a/alpm-utils/src/alpm.rs b/alpm-utils/src/alpm.rs index ae3e10a..762bb8d 100644 --- a/alpm-utils/src/alpm.rs +++ b/alpm-utils/src/alpm.rs @@ -1,22 +1,74 @@ -use crate::depends::satisfies_ver; +//! Extension methods for the [`Alpm`] type. -use alpm::{Alpm, Result, Package, Depend}; +use crate::DbListExt; +use alpm::{Alpm, AlpmList, Db, IntoIter, Package}; +/// Extension methods for [`Alpm`] which aren't critical enough to live in the +/// main crate, directly within `Alpm`. pub trait AlpmExt { - fn find_local_satisfier>(&self, pkg: S) -> Result>; + /// An iterator of [`Package`]s that are found in "sync databases", + /// typically registered in one's `pacman.conf`. + fn native_packages(&self) -> NativePkgs<'_>; + + /// The opposite of [`AlpmExt::native_packages`]; installed packages that + /// aren't found in any registered "sync database". + fn foreign_packages(&self) -> ForeignPkgs<'_>; } impl AlpmExt for Alpm { - fn find_local_satisfier>(&self, pkg: S) -> Result> { - let localdb = self.localdb(); - let pkg = pkg.into(); + fn native_packages(&self) -> NativePkgs<'_> { + NativePkgs::new(self) + } + + fn foreign_packages(&self) -> ForeignPkgs<'_> { + ForeignPkgs::new(self) + } +} + +/// [`Package`]s that are found in registered "sync databases". +pub struct NativePkgs<'a> { + local: IntoIter<'a, Package<'a>>, + sync: AlpmList<'a, Db<'a>>, +} + +impl<'a> NativePkgs<'a> { + fn new(alpm: &'a Alpm) -> NativePkgs<'a> { + let local = alpm.localdb().pkgs().into_iter(); + let sync = alpm.syncdbs(); + + NativePkgs { local, sync } + } +} + +impl<'a> Iterator for NativePkgs<'a> { + type Item = Package<'a>; + + fn next(&mut self) -> Option { + let s = self.sync; + self.local.find(|p| s.pkg(p.name()).is_ok()) + } +} + +/// Installed [`Package`]s that are _not_ found in registered "sync databases". +pub struct ForeignPkgs<'a> { + local: IntoIter<'a, Package<'a>>, + sync: AlpmList<'a, Db<'a>>, +} + +impl<'a> ForeignPkgs<'a> { + fn new(alpm: &'a Alpm) -> ForeignPkgs<'a> { + let local = alpm.localdb().pkgs().into_iter(); + let sync = alpm.syncdbs(); + + ForeignPkgs { local, sync } + } +} - if let Ok(alpm_pkg) = localdb.pkg(&pkg) { - if satisfies_ver(&Depend::new(&pkg), alpm_pkg.version()) { - return Ok(Some(alpm_pkg)); - } - } +impl<'a> Iterator for ForeignPkgs<'a> { + type Item = Package<'a>; - return Ok(localdb.pkgs()?.find_satisfier(pkg)); + fn next(&mut self) -> Option { + let s = self.sync; + self.local.find(|p| s.pkg(p.name()).is_err()) } } diff --git a/alpm-utils/src/db.rs b/alpm-utils/src/db.rs index f0b0a3f..8e8bb77 100644 --- a/alpm-utils/src/db.rs +++ b/alpm-utils/src/db.rs @@ -2,7 +2,7 @@ use alpm::{AlpmList, Db, Package, Result}; use crate::AsTarg; -/// Extention for AlpmList +/// Extentions for `AlpmList`. pub trait DbListExt<'a> { /// Similar to find_satisfier() but expects a Target instead of a &str. fn find_target_satisfier(&self, target: T) -> Option>; diff --git a/alpm-utils/src/depends.rs b/alpm-utils/src/depends.rs index 70c734c..49ebb13 100644 --- a/alpm-utils/src/depends.rs +++ b/alpm-utils/src/depends.rs @@ -1,11 +1,7 @@ use alpm::{AsDep, DepModVer, Ver}; /// Checks if a dependency is satisfied by a package (name + version). -pub fn satisfies_dep, V: AsRef>( - dep: impl AsDep, - name: S, - version: V, -) -> bool { +pub fn satisfies_dep, V: AsRef>(dep: impl AsDep, name: S, version: V) -> bool { let name = name.as_ref(); let dep = dep.as_dep(); diff --git a/alpm-utils/src/lib.rs b/alpm-utils/src/lib.rs index 8576dde..efb9742 100644 --- a/alpm-utils/src/lib.rs +++ b/alpm-utils/src/lib.rs @@ -6,8 +6,11 @@ #[cfg(feature = "conf")] mod conf; + #[cfg(feature = "alpm")] +mod alpm; mod db; + /// Utils for dependency checking. #[cfg(feature = "alpm")] pub mod depends; @@ -15,6 +18,8 @@ mod target; #[cfg(feature = "conf")] pub use crate::conf::*; + #[cfg(feature = "alpm")] +pub use crate::alpm::*; pub use crate::db::*; pub use crate::target::*;