use std::io::Read;
use std::fs::{File, read_dir};
use std::path::{Path, PathBuf};
use flate2::read::GzDecoder;
use itertools::process_results;
use rayon::prelude::*;
use tar::Archive;
use Provide;
use error::Result;
use package::MetaPackage;
#[derive(Debug)]
pub struct Db {
path: PathBuf,
pub packages: Vec<MetaPackage>
}
impl Db {
pub fn sync_dbs(location: impl AsRef<Path>) -> Result<Vec<Db>> {
let mut sync_dbs_path = PathBuf::from(location.as_ref());
sync_dbs_path.push("sync");
let mut dbs = Vec::new();
for db_path in read_dir(&sync_dbs_path)? {
let db_path = db_path?.path();
if let Some(extension) = db_path.extension() {
if extension == "db" {
dbs.push(db_path.to_path_buf());
}
}
}
let dbs: Vec<_> = dbs.par_iter()
.map(|db_path| -> Result<Db> {
let packages = Db::sync_db_pkgs(&db_path)?;
Ok(Db {
path: db_path.to_path_buf(),
packages: packages
})
})
.collect();
process_results(dbs, |iter| iter.collect() )
}
pub fn local_db(location: impl AsRef<Path>) -> Result<Db> {
let mut local_db_path = PathBuf::from(location.as_ref());
local_db_path.push("local");
let packages = Db::local_db_pkgs(&local_db_path)?;
Ok(Db {
path: local_db_path,
packages: packages
})
}
fn local_db_pkgs(path: impl AsRef<Path>) -> Result<Vec<MetaPackage>> {
let mut pkgs = Vec::with_capacity(200);
let mut iter_count = 0;
for spec_dir in read_dir(&path)? {
let spec_dir = spec_dir?;
let mut pkg_path = spec_dir.path();
if pkg_path != Path::join(path.as_ref(), "ALPM_DB_VERSION") {
iter_count += 1;
if iter_count >= 200 {
iter_count = 0;
pkgs.reserve(200);
}
pkg_path.push("desc");
let mut file = File::open(pkg_path)?;
let mut data = String::new();
file.read_to_string(&mut data)?;
pkgs.push(MetaPackage::parse_pkgdesc(data)?);
}
}
Ok(pkgs)
}
fn sync_db_pkgs(path: impl AsRef<Path>) -> Result<Vec<MetaPackage>> {
let db = File::open(&path)?;
let db = GzDecoder::new(db);
let mut db = Archive::new(db);
let mut pkgs = Vec::with_capacity(200);
let mut iter_count = 0;
for desc in db.entries()? {
let mut desc = desc?;
let path = desc.path()?.to_path_buf();
if path.to_string_lossy() != "ALPM_DB_VERSION" {
iter_count += 1;
if iter_count >= 200 {
iter_count = 0;
pkgs.reserve(200);
}
let mut data = String::new();
desc.read_to_string(&mut data)?;
pkgs.push(MetaPackage::parse_pkgdesc(data)?);
}
}
Ok(pkgs)
}
pub fn pkg(&self, pkgname: impl AsRef<str>) -> Option<&MetaPackage> {
self.packages.iter()
.find(|pkg| pkg.name == pkgname.as_ref() )
}
pub fn provides(&self, provide: &Provide) -> bool {
self.packages.iter()
.any(|pkg| pkg.satisfies(provide) )
}
}