aur_depends/
upgrade.rs

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/// An AUR package that should be updated.
12#[derive(Debug)]
13pub struct AurUpdate<'a> {
14    /// The local package.
15    pub local: &'a alpm::Package,
16    /// The AUR package.
17    pub remote: ArcPackage,
18}
19
20/// A pkgbuild should be updated.
21#[derive(Debug)]
22pub struct PkgbuildUpdate<'a> {
23    /// The local package.
24    pub local: &'a alpm::Package,
25    /// The pkgbuild repo the package belongs to.
26    pub repo: String,
27    /// The pkgbuild package base srcinfo.
28    pub remote_srcinfo: &'a Srcinfo,
29    /// The pkgbuild package base package,
30    pub remote_pkg: &'a srcinfo::Package,
31}
32
33/// Collection of AUR updates and missing packages.
34#[derive(Debug, Default)]
35pub struct Updates<'a> {
36    /// The aur updates.
37    pub aur_updates: Vec<AurUpdate<'a>>,
38    /// The pkgbuild updates.
39    pub pkgbuild_updates: Vec<PkgbuildUpdate<'a>>,
40    /// Packages that matched ignore pkg/group.
41    pub aur_ignored: Vec<AurUpdate<'a>>,
42    /// Packages that matched ignore pkg/group.
43    pub pkgbuild_ignored: Vec<PkgbuildUpdate<'a>>,
44    /// Packages that were not found in the AUR or elsewhere.
45    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    /// Get aur packages need to be updated.
69    ///
70    /// # Example
71    ///
72    /// ```no_run
73    /// # use aur_depends::{Error, Updates};
74    /// # #[tokio::test]
75    /// # async fn run() -> Result<(), Error> {
76    /// use std::collections::HashSet;
77    /// use alpm::Alpm;
78    /// use raur::Handle;
79    ///
80    /// use aur_depends::{Flags, Resolver};
81    ///
82    /// let alpm = Alpm::new("/", "/var/lib/pacman")?;
83    /// let raur = Handle::default();
84    /// let mut cache = HashSet::new();
85    /// let mut resolver = Resolver::new(&alpm, Vec::new(), &mut cache, &raur, Flags::aur_only());
86    ///
87    /// let updates = resolver.updates().await?;
88    ///
89    /// for update in updates.aur_updates {
90    ///     println!("update: {}: {} -> {}", update.local.name(), update.local.version(),
91    ///     update.remote.version);
92    /// }
93    /// # Ok (())
94    /// # }
95    /// ```
96    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}