1use std::io::Read;
5use std::fs::{File, read_dir};
6use std::path::{Path, PathBuf};
7
8use flate2::read::GzDecoder;
9use itertools::process_results;
10use rayon::prelude::*;
11use tar::Archive;
12
13use Provide;
14use error::Result;
15use package::MetaPackage;
16
17#[derive(Debug)]
18pub struct Db {
19 path: PathBuf,
20 pub packages: Vec<MetaPackage>
21}
22
23impl Db {
24 pub fn sync_dbs(location: impl AsRef<Path>) -> Result<Vec<Db>> {
27 let mut sync_dbs_path = PathBuf::from(location.as_ref());
28 sync_dbs_path.push("sync");
29
30 let mut dbs = Vec::new();
31 for db_path in read_dir(&sync_dbs_path)? {
32 let db_path = db_path?.path();
33 if let Some(extension) = db_path.extension() {
34 if extension == "db" {
35 dbs.push(db_path.to_path_buf());
36 }
37 }
38 }
39
40 let dbs: Vec<_> = dbs.par_iter()
41 .map(|db_path| -> Result<Db> {
42 let packages = Db::sync_db_pkgs(&db_path)?;
43 Ok(Db {
44 path: db_path.to_path_buf(),
45 packages: packages
46 })
47 })
48 .collect();
49
50 process_results(dbs, |iter| iter.collect() )
51 }
52
53 pub fn local_db(location: impl AsRef<Path>) -> Result<Db> {
55 let mut local_db_path = PathBuf::from(location.as_ref());
56 local_db_path.push("local");
57 let packages = Db::local_db_pkgs(&local_db_path)?;
58 Ok(Db {
59 path: local_db_path,
60 packages: packages
61 })
62 }
63
64 fn local_db_pkgs(path: impl AsRef<Path>) -> Result<Vec<MetaPackage>> {
65 let mut pkgs = Vec::with_capacity(200);
66 let mut iter_count = 0;
67
68 for spec_dir in read_dir(&path)? {
69 let spec_dir = spec_dir?;
70 let mut pkg_path = spec_dir.path();
71
72 if pkg_path != Path::join(path.as_ref(), "ALPM_DB_VERSION") {
73 iter_count += 1;
74 if iter_count >= 200 {
75 iter_count = 0;
76 pkgs.reserve(200);
77 }
78 pkg_path.push("desc");
79 let mut file = File::open(pkg_path)?;
80
81 let mut data = String::new();
82 file.read_to_string(&mut data)?;
83 pkgs.push(MetaPackage::parse_pkgdesc(data)?);
84 }
85 }
86 Ok(pkgs)
87 }
88
89 fn sync_db_pkgs(path: impl AsRef<Path>) -> Result<Vec<MetaPackage>> {
90 let db = File::open(&path)?;
91 let db = GzDecoder::new(db);
92 let mut db = Archive::new(db);
93
94 let mut pkgs = Vec::with_capacity(200);
95 let mut iter_count = 0;
96
97 for desc in db.entries()? {
98 let mut desc = desc?;
99 let path = desc.path()?.to_path_buf();
100
101 if path.to_string_lossy() != "ALPM_DB_VERSION" {
102 iter_count += 1;
103 if iter_count >= 200 {
104 iter_count = 0;
105 pkgs.reserve(200);
106 }
107 let mut data = String::new();
108 desc.read_to_string(&mut data)?;
109
110 pkgs.push(MetaPackage::parse_pkgdesc(data)?);
111 }
112 }
113 Ok(pkgs)
114 }
115
116 pub fn pkg(&self, pkgname: impl AsRef<str>) -> Option<&MetaPackage> {
119 self.packages.iter()
120 .find(|pkg| pkg.name == pkgname.as_ref() )
121 }
122
123 pub fn provides(&self, provide: &Provide) -> bool {
133 self.packages.iter()
134 .any(|pkg| pkg.satisfies(provide) )
135 }
136}