1use crate::Error;
2use crate::Flags;
3use crate::Resolver;
4use srcinfo::Srcinfo;
5
6use alpm::{Alpm, AlpmList, Version};
7use alpm_utils::DbListExt;
8use raur::ArcPackage;
9use raur::Raur;
10
11#[derive(Debug)]
13pub struct AurUpdate<'a> {
14 pub local: &'a alpm::Package,
16 pub remote: ArcPackage,
18}
19
20#[derive(Debug)]
22pub struct PkgbuildUpdate<'a> {
23 pub local: &'a alpm::Package,
25 pub repo: String,
27 pub remote_srcinfo: &'a Srcinfo,
29 pub remote_pkg: &'a srcinfo::Package,
31}
32
33#[derive(Debug, Default)]
35pub struct Updates<'a> {
36 pub aur_updates: Vec<AurUpdate<'a>>,
38 pub pkgbuild_updates: Vec<PkgbuildUpdate<'a>>,
40 pub aur_ignored: Vec<AurUpdate<'a>>,
42 pub pkgbuild_ignored: Vec<PkgbuildUpdate<'a>>,
44 pub missing: Vec<&'a alpm::Package>,
46}
47
48impl<'a, 'b, E: std::error::Error + Sync + Send + 'static, H: Raur<Err = E> + Sync>
49 Resolver<'a, 'b, H>
50{
51 fn update_targs<'c>(
52 alpm: &'c Alpm,
53 local: Option<AlpmList<&'c alpm::Db>>,
54 ) -> Vec<&'c alpm::Package> {
55 let dbs = alpm.syncdbs();
56
57 if let Some(local) = local {
58 local.iter().flat_map(|db| db.pkgs()).collect()
59 } else {
60 alpm.localdb()
61 .pkgs()
62 .into_iter()
63 .filter(|p| dbs.pkg(p.name()).is_err())
64 .collect()
65 }
66 }
67
68 pub async fn updates(&mut self, local: Option<&[&str]>) -> Result<Updates<'a>, Error> {
97 let local = match local {
98 Some(local) => {
99 let mut local_dbs = self.alpm.syncdbs().to_list_mut();
100 local_dbs.retain(|db| local.iter().any(|name| *name == db.name()));
101 Some(local_dbs)
102 }
103 None => None,
104 };
105
106 let targets = Self::update_targs(self.alpm, local.as_ref().map(|l| l.list()));
107 let (mut pkgbuilds, mut aur) = targets
108 .into_iter()
109 .partition::<Vec<_>, _>(|p| self.is_pkgbuild(p.name()));
110
111 if !self.flags.contains(Flags::AUR) {
112 aur.clear();
113 }
114 if !self.flags.contains(Flags::PKGBUILDS) {
115 pkgbuilds.clear();
116 }
117
118 let aur_pkg_names = aur.iter().map(|pkg| pkg.name()).collect::<Vec<_>>();
119 self.raur
120 .cache_info(self.cache, &aur_pkg_names)
121 .await
122 .map_err(|e| Error::Raur(Box::new(e)))?;
123
124 let mut updates = Updates::default();
125
126 for local in pkgbuilds {
127 let (repo, srcinfo, remote) = self.find_pkgbuild(local.name()).unwrap();
128
129 let should_upgrade = if self.flags.contains(Flags::ENABLE_DOWNGRADE) {
130 Version::new(srcinfo.version()) != local.version()
131 } else {
132 Version::new(srcinfo.version()) > local.version()
133 };
134 if !should_upgrade {
135 continue;
136 }
137
138 let update = PkgbuildUpdate {
139 local,
140 repo: repo.to_string(),
141 remote_srcinfo: srcinfo,
142 remote_pkg: remote,
143 };
144
145 if local.should_ignore() {
146 updates.pkgbuild_ignored.push(update);
147 } else {
148 updates.pkgbuild_updates.push(update);
149 }
150 }
151
152 for local in aur {
153 if let Some(pkg) = self.cache.get(local.name()) {
154 let should_upgrade = if self.flags.contains(Flags::ENABLE_DOWNGRADE) {
155 Version::new(&*pkg.version) != local.version()
156 } else {
157 Version::new(&*pkg.version) > local.version()
158 };
159 if !should_upgrade {
160 continue;
161 }
162
163 let should_ignore = local.should_ignore();
164
165 let update = AurUpdate {
166 local,
167 remote: pkg.clone(),
168 };
169
170 if should_ignore {
171 updates.aur_ignored.push(update);
172 } else {
173 updates.aur_updates.push(update);
174 }
175 } else {
176 updates.missing.push(local);
177 }
178 }
179
180 Ok(updates)
181 }
182}