oma_apt/
cache.rs

1//! Contains Cache related structs.
2
3use std::cell::OnceCell;
4use std::fs;
5use std::path::Path;
6
7use cxx::{Exception, UniquePtr};
8
9use crate::config::{Config, init_config_system};
10use crate::depcache::DepCache;
11use crate::error::{AptErrors, pending_error};
12use crate::pkgmanager::raw::OrderResult;
13use crate::progress::{AcquireProgress, InstallProgress, OperationProgress};
14use crate::raw::{
15    IntoRawIter, IterPkgIterator, PackageManager, PkgCacheFile, PkgIterator, ProblemResolver,
16    create_cache, create_pkgmanager, create_problem_resolver,
17};
18use crate::records::{PackageRecords, SourceRecords};
19use crate::util::{apt_lock, apt_unlock, apt_unlock_inner};
20use crate::{Package, PkgSelectedState};
21
22/// Selection of Upgrade type
23#[repr(i32)]
24#[derive(Clone, Debug)]
25pub enum Upgrade {
26    /// Upgrade will Install new and Remove packages in addition to
27    /// upgrading them.
28    ///
29    /// Equivalent to `apt full-upgrade` and `apt-get dist-upgrade`.
30    FullUpgrade = 0,
31    /// Upgrade will Install new but not Remove packages.
32    ///
33    /// Equivalent to `apt upgrade`.
34    Upgrade = 1,
35    /// Upgrade will Not Install new or Remove packages.
36    ///
37    /// Equivalent to `apt-get upgrade`.
38    SafeUpgrade = 3,
39}
40
41impl Upgrade {
42    pub fn to_edsp(&self) -> i32 {
43        match self {
44            Upgrade::FullUpgrade => Edsp::UpgradeAll as i32,
45            Upgrade::Upgrade => Edsp::UpgradeAll as i32 | Edsp::ForbidRemove as i32,
46            Upgrade::SafeUpgrade => {
47                Edsp::UpgradeAll as i32 | Edsp::ForbidNewInstall as i32 | Edsp::ForbidRemove as i32
48            }
49        }
50    }
51}
52
53#[allow(dead_code)]
54enum Edsp {
55    Autoremove = 1 << 0,
56    UpgradeAll = 1 << 1,
57    ForbidNewInstall = 1 << 2,
58    ForbidRemove = 1 << 3,
59}
60
61/// Selection of how to sort
62enum Sort {
63    /// Disable the sort method.
64    Disable,
65    /// Enable the sort method.
66    Enable,
67    /// Reverse the sort method.
68    Reverse,
69}
70
71/// Determines how to sort packages from the Cache.
72pub struct PackageSort {
73    names: bool,
74    upgradable: Sort,
75    virtual_pkgs: Sort,
76    installed: Sort,
77    auto_installed: Sort,
78    auto_removable: Sort,
79    hold: Sort,
80}
81
82impl Default for PackageSort {
83    fn default() -> PackageSort {
84        PackageSort {
85            names: false,
86            upgradable: Sort::Disable,
87            virtual_pkgs: Sort::Disable,
88            installed: Sort::Disable,
89            auto_installed: Sort::Disable,
90            auto_removable: Sort::Disable,
91            hold: Sort::Disable,
92        }
93    }
94}
95
96impl PackageSort {
97    /// Packages will be sorted by their names a -> z.
98    pub fn names(mut self) -> Self {
99        self.names = true;
100        self
101    }
102
103    /// Only packages that are upgradable will be included.
104    pub fn upgradable(mut self) -> Self {
105        self.upgradable = Sort::Enable;
106        self
107    }
108
109    /// Only packages that are NOT upgradable will be included.
110    pub fn not_upgradable(mut self) -> Self {
111        self.upgradable = Sort::Reverse;
112        self
113    }
114
115    /// Virtual packages will be included.
116    pub fn include_virtual(mut self) -> Self {
117        self.virtual_pkgs = Sort::Enable;
118        self
119    }
120
121    /// Only Virtual packages will be included.
122    pub fn only_virtual(mut self) -> Self {
123        self.virtual_pkgs = Sort::Reverse;
124        self
125    }
126
127    /// Only packages that are installed will be included.
128    pub fn installed(mut self) -> Self {
129        self.installed = Sort::Enable;
130        self
131    }
132
133    /// Only packages that are NOT installed will be included.
134    pub fn not_installed(mut self) -> Self {
135        self.installed = Sort::Reverse;
136        self
137    }
138
139    /// Only packages that are auto installed will be included.
140    pub fn auto_installed(mut self) -> Self {
141        self.auto_installed = Sort::Enable;
142        self
143    }
144
145    /// Only packages that are manually installed will be included.
146    pub fn manually_installed(mut self) -> Self {
147        self.auto_installed = Sort::Reverse;
148        self.installed = Sort::Enable;
149        self
150    }
151
152    /// Only packages that are auto removable will be included.
153    pub fn auto_removable(mut self) -> Self {
154        self.auto_removable = Sort::Enable;
155        self
156    }
157
158    /// Only packages that are NOT auto removable will be included.
159    pub fn not_auto_removable(mut self) -> Self {
160        self.auto_removable = Sort::Reverse;
161        self
162    }
163
164    /// Only packages that are hold installed will be included.
165    pub fn hold_installed(mut self) -> Self {
166        self.hold = Sort::Enable;
167        self
168    }
169
170    /// Only packages that are NOT hold installed will be included.
171    pub fn not_hold_installed(mut self) -> Self {
172        self.hold = Sort::Disable;
173        self.installed = Sort::Enable;
174        self
175    }
176}
177
178/// The main struct for accessing any and all `apt` data.
179pub struct Cache {
180    pub(crate) ptr: UniquePtr<PkgCacheFile>,
181    depcache: OnceCell<DepCache>,
182    records: OnceCell<PackageRecords>,
183    source_records: OnceCell<SourceRecords>,
184    pkgmanager: OnceCell<UniquePtr<PackageManager>>,
185    problem_resolver: OnceCell<UniquePtr<ProblemResolver>>,
186    local_debs: Vec<String>,
187}
188
189impl Cache {
190    /// Initialize the configuration system, open and return the cache.
191    /// This is the entry point for all operations of this crate.
192    ///
193    /// `local_files` allows you to temporarily add local files to the cache, as
194    /// long as they are one of the following:
195    ///
196    /// - `*.deb` or `*.ddeb` files
197    /// - `Packages` and `Sources` files from apt repositories. These files can
198    ///   be compressed.
199    /// - `*.dsc` or `*.changes` files
200    /// - A valid directory containing the file `./debian/control`
201    ///
202    /// This function returns an [`AptErrors`] if any of the files cannot
203    /// be found or are invalid.
204    ///
205    /// Note that if you run [`Cache::commit`] or [`Cache::update`],
206    /// You will be required to make a new cache to perform any further changes
207    pub fn new<T: AsRef<str>>(local_files: &[T]) -> Result<Cache, AptErrors> {
208        let volatile_files: Vec<_> = local_files.iter().map(|d| d.as_ref()).collect();
209
210        init_config_system();
211        Ok(Cache {
212            ptr: create_cache(&volatile_files)?,
213            depcache: OnceCell::new(),
214            records: OnceCell::new(),
215            source_records: OnceCell::new(),
216            pkgmanager: OnceCell::new(),
217            problem_resolver: OnceCell::new(),
218            local_debs: volatile_files
219                .into_iter()
220                .filter(|f| f.ends_with(".deb"))
221                .map(|f| f.to_string())
222                .collect(),
223        })
224    }
225
226    /// Internal Method for generating the package list.
227    pub fn raw_pkgs(&self) -> impl Iterator<Item = UniquePtr<PkgIterator>> {
228        unsafe { self.begin().raw_iter() }
229    }
230
231    /// Get the DepCache
232    pub fn depcache(&self) -> &DepCache {
233        self.depcache
234            .get_or_init(|| DepCache::new(unsafe { self.create_depcache() }))
235    }
236
237    /// Get the PkgRecords
238    pub fn records(&self) -> &PackageRecords {
239        self.records
240            .get_or_init(|| PackageRecords::new(unsafe { self.create_records() }))
241    }
242
243    /// Get the PkgRecords
244    pub fn source_records(&self) -> Result<&SourceRecords, AptErrors> {
245        if let Some(records) = self.source_records.get() {
246            return Ok(records);
247        }
248
249        match unsafe { self.ptr.source_records() } {
250            Ok(raw_records) => {
251                self.source_records
252                    .set(SourceRecords::new(raw_records))
253                    // Unwrap: This is verified empty at the beginning.
254                    .unwrap_or_default();
255                // Unwrap: Records was just added above.
256                Ok(self.source_records.get().unwrap())
257            }
258            Err(_) => Err(AptErrors::new()),
259        }
260    }
261
262    /// Get the PkgManager
263    pub fn pkg_manager(&self) -> &PackageManager {
264        self.pkgmanager
265            .get_or_init(|| unsafe { create_pkgmanager(self.depcache()) })
266    }
267
268    /// Get the ProblemResolver
269    pub fn resolver(&self) -> &ProblemResolver {
270        self.problem_resolver
271            .get_or_init(|| unsafe { create_problem_resolver(self.depcache()) })
272    }
273
274    /// Iterate through the packages in a random order
275    pub fn iter(&self) -> CacheIter<'_> {
276        CacheIter {
277            pkgs: unsafe { self.begin().raw_iter() },
278            cache: self,
279        }
280    }
281
282    /// An iterator of packages in the cache.
283    pub fn packages(&self, sort: &PackageSort) -> impl Iterator<Item = Package<'_>> {
284        let mut pkg_list = vec![];
285        for pkg in self.raw_pkgs() {
286            match sort.virtual_pkgs {
287                // Virtual packages are enabled, include them.
288                // This works differently than the rest. I should probably change defaults.
289                Sort::Enable => {}
290                // If disabled and pkg has no versions, exclude
291                Sort::Disable => {
292                    if unsafe { pkg.versions().end() } {
293                        continue;
294                    }
295                }
296                // If reverse and the package has versions, exclude
297                // This section is for if you only want virtual packages
298                Sort::Reverse => {
299                    if unsafe { !pkg.versions().end() } {
300                        continue;
301                    }
302                }
303            }
304
305            match sort.upgradable {
306                // Virtual packages are enabled, include them.
307                Sort::Disable => {}
308                // If disabled and pkg has no versions, exclude
309                Sort::Enable => {
310                    // If the package isn't installed, then it can not be upgradable
311                    if unsafe { pkg.current_version().end() }
312                        || !self.depcache().is_upgradable(&pkg)
313                    {
314                        continue;
315                    }
316                }
317                // If reverse and the package is installed and upgradable, exclude
318                // This section is for if you only want packages that are not upgradable
319                Sort::Reverse => {
320                    if unsafe { !pkg.current_version().end() }
321                        && self.depcache().is_upgradable(&pkg)
322                    {
323                        continue;
324                    }
325                }
326            }
327
328            match sort.installed {
329                // Installed Package is Disabled, so we keep them
330                Sort::Disable => {}
331                Sort::Enable => {
332                    if unsafe { pkg.current_version().end() } {
333                        continue;
334                    }
335                }
336                // Only include installed packages.
337                Sort::Reverse => {
338                    if unsafe { !pkg.current_version().end() } {
339                        continue;
340                    }
341                }
342            }
343
344            match sort.auto_installed {
345                // Installed Package is Disabled, so we keep them
346                Sort::Disable => {}
347                Sort::Enable => {
348                    if !self.depcache().is_auto_installed(&pkg) {
349                        continue;
350                    }
351                }
352                // Only include installed packages.
353                Sort::Reverse => {
354                    if self.depcache().is_auto_installed(&pkg) {
355                        continue;
356                    }
357                }
358            }
359
360            match sort.auto_removable {
361                // auto_removable is Disabled, so we keep them
362                Sort::Disable => {}
363                // If the package is not auto removable skip it.
364                Sort::Enable => {
365                    // If the Package isn't auto_removable skip
366                    if !self.depcache().is_garbage(&pkg) {
367                        continue;
368                    }
369                }
370                // If the package is auto removable skip it.
371                Sort::Reverse => {
372                    if self.depcache().is_garbage(&pkg) {
373                        continue;
374                    }
375                }
376            }
377
378            match sort.hold {
379                Sort::Disable => {}
380                Sort::Enable => {
381                    if PkgSelectedState::from(pkg.selected_state()) != PkgSelectedState::Hold {
382                        continue;
383                    }
384                }
385                Sort::Reverse => {
386                    if PkgSelectedState::from(pkg.selected_state()) == PkgSelectedState::Hold {
387                        continue;
388                    }
389                }
390            }
391
392            // If this is reached we're clear to include the package.
393            pkg_list.push(pkg);
394        }
395
396        if sort.names {
397            pkg_list.sort_by_cached_key(|pkg| pkg.name().to_string());
398        }
399
400        pkg_list.into_iter().map(|pkg| Package::new(self, pkg))
401    }
402
403    /// Updates the package cache and returns a Result
404    ///
405    /// Here is an example of how you may parse the Error messages.
406    ///
407    /// ```
408    /// use oma_apt::new_cache;
409    /// use oma_apt::progress::AcquireProgress;
410    ///
411    /// let cache = new_cache!().unwrap();
412    /// let mut progress = AcquireProgress::apt();
413    /// if let Err(e) = cache.update(&mut progress) {
414    ///     for error in e.iter() {
415    ///         if error.is_error {
416    ///             println!("Error: {}", error.msg);
417    ///         } else {
418    ///             println!("Warning: {}", error.msg);
419    ///         }
420    ///     }
421    /// }
422    /// ```
423    /// # Known Errors:
424    /// * E:Could not open lock file /var/lib/apt/lists/lock - open (13:
425    ///   Permission denied)
426    /// * E:Unable to lock directory /var/lib/apt/lists/
427    pub fn update(self, progress: &mut AcquireProgress) -> Result<(), AptErrors> {
428        Ok(self.ptr.update(progress.mut_status())?)
429    }
430
431    /// Mark all packages for upgrade
432    ///
433    /// # Example:
434    ///
435    /// ```
436    /// use oma_apt::new_cache;
437    /// use oma_apt::cache::Upgrade;
438    ///
439    /// let cache = new_cache!().unwrap();
440    ///
441    /// cache.upgrade(Upgrade::FullUpgrade).unwrap();
442    /// ```
443    pub fn upgrade(&self, upgrade_type: Upgrade) -> Result<(), AptErrors> {
444        let mut progress = OperationProgress::quiet();
445
446        let solver = Config::new().find("APT::Solver", "internal");
447
448        if solver == "internal" {
449            Ok(self
450                .depcache()
451                .upgrade(progress.pin().as_mut(), upgrade_type as i32)?)
452        } else {
453            Ok(self
454                .depcache()
455                .resolve_by_edsp(progress.pin().as_mut(), upgrade_type.to_edsp())?)
456        }
457    }
458
459    /// Resolve dependencies with the changes marked on all packages. This marks
460    /// additional packages for installation/removal to satisfy the dependency
461    /// chain.
462    ///
463    /// Note that just running a `mark_*` function on a package doesn't
464    /// guarantee that the selected state will be kept during dependency
465    /// resolution. If you need such, make sure to run
466    /// [`crate::Package::protect`] after marking your requested
467    /// modifications.
468    ///
469    /// If `fix_broken` is set to [`true`], the library will try to repair
470    /// broken dependencies of installed packages.
471    ///
472    /// Returns [`Err`] if there was an error reaching dependency resolution.
473    #[allow(clippy::result_unit_err)]
474    pub fn resolve(&self, fix_broken: bool) -> Result<(), AptErrors> {
475        Ok(self
476            .resolver()
477            .resolve(fix_broken, OperationProgress::quiet().pin().as_mut())?)
478    }
479
480    /// Autoinstall every broken package and run the problem resolver
481    /// Returns false if the problem resolver fails.
482    ///
483    /// # Example:
484    ///
485    /// ```
486    /// use oma_apt::new_cache;
487    ///
488    /// let cache = new_cache!().unwrap();
489    ///
490    /// cache.fix_broken();
491    ///
492    /// for pkg in cache.get_changes(false) {
493    ///     println!("Pkg Name: {}", pkg.name())
494    /// }
495    /// ```
496    pub fn fix_broken(&self) -> bool {
497        self.depcache().fix_broken()
498    }
499
500    /// Fetch any archives needed to complete the transaction.
501    ///
502    /// # Returns:
503    /// * A [`Result`] enum: the [`Ok`] variant if fetching succeeded, and
504    ///   [`Err`] if there was an issue.
505    ///
506    /// # Example:
507    /// ```
508    /// use oma_apt::new_cache;
509    /// use oma_apt::progress::AcquireProgress;
510    ///
511    /// let cache = new_cache!().unwrap();
512    /// let pkg = cache.get("neovim").unwrap();
513    /// let mut progress = AcquireProgress::apt();
514    ///
515    /// pkg.mark_install(true, true);
516    /// pkg.protect();
517    /// cache.resolve(true).unwrap();
518    ///
519    /// cache.get_archives(&mut progress).unwrap();
520    /// ```
521    /// # Known Errors:
522    /// * W:Problem unlinking the file
523    ///   /var/cache/apt/archives/partial/neofetch_7.1.0-4_all.deb -
524    ///   PrepareFiles (13: Permission denied)
525    /// * W:Problem unlinking the file
526    ///   /var/cache/apt/archives/partial/neofetch_7.1.0-4_all.deb -
527    ///   PrepareFiles (13: Permission denied)
528    /// * W:Problem unlinking the file
529    ///   /var/cache/apt/archives/partial/neofetch_7.1.0-4_all.deb -
530    ///   PrepareFiles (13: Permission denied)
531    /// * W:Problem unlinking the file
532    ///   /var/cache/apt/archives/partial/neofetch_7.1.0-4_all.deb -
533    ///   PrepareFiles (13: Permission denied)
534    /// * W:Problem unlinking the file
535    ///   /var/cache/apt/archives/partial/neofetch_7.1.0-4_all.deb -
536    ///   PrepareFiles (13: Permission denied)
537    /// * W:Problem unlinking the file /var/log/apt/eipp.log.xz - FileFd::Open
538    ///   (13: Permission denied)
539    /// * W:Could not open file /var/log/apt/eipp.log.xz - open (17: File
540    ///   exists)
541    /// * W:Could not open file '/var/log/apt/eipp.log.xz' - EIPP::OrderInstall
542    ///   (17: File exists)
543    /// * E:Internal Error, ordering was unable to handle the media swap"
544    pub fn get_archives(&self, progress: &mut AcquireProgress) -> Result<(), Exception> {
545        self.pkg_manager()
546            .get_archives(&self.ptr, self.records(), progress.mut_status())
547    }
548
549    /// Install, remove, and do any other actions requested by the cache.
550    ///
551    /// # Returns:
552    /// * A [`Result`] enum: the [`Ok`] variant if transaction was successful,
553    ///   and [`Err`] if there was an issue.
554    ///
555    /// # Example:
556    /// ```
557    /// use oma_apt::new_cache;
558    /// use oma_apt::progress::{AcquireProgress, InstallProgress};
559    ///
560    /// let cache = new_cache!().unwrap();
561    /// let pkg = cache.get("neovim").unwrap();
562    /// let mut acquire_progress = AcquireProgress::apt();
563    /// let mut install_progress = InstallProgress::apt();
564    ///
565    /// pkg.mark_install(true, true);
566    /// pkg.protect();
567    /// cache.resolve(true).unwrap();
568    ///
569    /// // These need root
570    /// // cache.get_archives(&mut acquire_progress).unwrap();
571    /// // cache.do_install(&mut install_progress).unwrap();
572    /// ```
573    ///
574    /// # Known Errors:
575    /// * W:Problem unlinking the file /var/log/apt/eipp.log.xz - FileFd::Open
576    ///   (13: Permission denied)
577    /// * W:Could not open file /var/log/apt/eipp.log.xz - open (17: File
578    ///   exists)
579    /// * W:Could not open file '/var/log/apt/eipp.log.xz' - EIPP::OrderInstall
580    ///   (17: File exists)
581    /// * E:Could not create temporary file for /var/lib/apt/extended_states -
582    ///   mkstemp (13: Permission denied)
583    /// * E:Failed to write temporary StateFile /var/lib/apt/extended_states
584    /// * W:Could not open file '/var/log/apt/term.log' - OpenLog (13:
585    ///   Permission denied)
586    /// * E:Sub-process /usr/bin/dpkg returned an error code (2)
587    /// * W:Problem unlinking the file /var/cache/apt/pkgcache.bin -
588    ///   pkgDPkgPM::Go (13: Permission denied)
589    pub fn do_install(self, progress: &mut InstallProgress) -> Result<(), AptErrors> {
590        let res = match progress {
591            InstallProgress::Fancy(inner) => self.pkg_manager().do_install(inner.pin().as_mut()),
592            InstallProgress::Fd(fd) => self.pkg_manager().do_install_fd(*fd),
593        };
594
595        if pending_error() {
596            return Err(AptErrors::new());
597        }
598
599        match res {
600            OrderResult::Completed => {}
601            OrderResult::Failed => panic!(
602                "DoInstall failed with no error from libapt. Please report this as an issue."
603            ),
604            OrderResult::Incomplete => {
605                panic!("Result is 'Incomplete', please request media swapping as a feature.")
606            }
607            _ => unreachable!(),
608        }
609
610        Ok(())
611    }
612
613    /// Handle get_archives and do_install in an easy wrapper.
614    ///
615    /// # Returns:
616    /// * A [`Result`]: the [`Ok`] variant if transaction was successful, and
617    ///   [`Err`] if there was an issue.
618    /// # Example:
619    /// ```
620    /// use oma_apt::new_cache;
621    /// use oma_apt::progress::{AcquireProgress, InstallProgress};
622    ///
623    /// let cache = new_cache!().unwrap();
624    /// let pkg = cache.get("neovim").unwrap();
625    /// let mut acquire_progress = AcquireProgress::apt();
626    /// let mut install_progress = InstallProgress::apt();
627    ///
628    /// pkg.mark_install(true, true);
629    /// pkg.protect();
630    /// cache.resolve(true).unwrap();
631    ///
632    /// // This needs root
633    /// // cache.commit(&mut acquire_progress, &mut install_progress).unwrap();
634    /// ```
635    pub fn commit(
636        self,
637        progress: &mut AcquireProgress,
638        install_progress: &mut InstallProgress,
639    ) -> Result<(), AptErrors> {
640        // Lock the whole thing so as to prevent tamper
641        apt_lock()?;
642
643        let config = Config::new();
644        let archive_dir = config.dir("Dir::Cache::Archives", "/var/cache/apt/archives/");
645
646        // Copy local debs into archives dir
647        for deb in &self.local_debs {
648            // If it reaches this point it really will be a valid filename, allegedly
649            if let Some(filename) = Path::new(deb).file_name() {
650                // Append the file name onto the archive dir
651                fs::copy(deb, archive_dir.to_string() + &filename.to_string_lossy())?;
652            }
653        }
654
655        // The archives can be grabbed during the apt lock.
656        self.get_archives(progress)?;
657
658        // If the system is locked we will want to unlock the dpkg files.
659        // This way when dpkg is running it can access its files.
660        apt_unlock_inner();
661
662        // Perform the operation.
663        self.do_install(install_progress)?;
664
665        // Finally Unlock the whole thing.
666        apt_unlock();
667        Ok(())
668    }
669
670    /// Get a single package.
671    ///
672    /// `cache.get("apt")` Returns a Package object for the native arch.
673    ///
674    /// `cache.get("apt:i386")` Returns a Package object for the i386 arch
675    pub fn get(&self, name: &str) -> Option<Package<'_>> {
676        Some(Package::new(self, unsafe {
677            self.find_pkg(name).make_safe()?
678        }))
679    }
680
681    /// An iterator over the packages
682    /// that will be altered when `cache.commit()` is called.
683    ///
684    /// # sort_name:
685    /// * [`true`] = Packages will be in alphabetical order
686    /// * [`false`] = Packages will not be sorted by name
687    pub fn get_changes(&self, sort_name: bool) -> impl Iterator<Item = Package<'_>> {
688        let mut changed = Vec::new();
689        let depcache = self.depcache();
690
691        for pkg in self.raw_pkgs() {
692            if depcache.marked_install(&pkg)
693                || depcache.marked_delete(&pkg)
694                || depcache.marked_upgrade(&pkg)
695                || depcache.marked_downgrade(&pkg)
696                || depcache.marked_reinstall(&pkg)
697            {
698                changed.push(pkg);
699            }
700        }
701
702        if sort_name {
703            // Sort by cached key seems to be the fastest for what we're doing.
704            // Maybe consider impl ord or something for these.
705            changed.sort_by_cached_key(|pkg| pkg.name().to_string());
706        }
707
708        changed
709            .into_iter()
710            .map(|pkg_ptr| Package::new(self, pkg_ptr))
711    }
712}
713
714/// Iterator Implementation for the Cache.
715pub struct CacheIter<'a> {
716    pkgs: IterPkgIterator,
717    cache: &'a Cache,
718}
719
720impl<'a> Iterator for CacheIter<'a> {
721    type Item = Package<'a>;
722
723    fn next(&mut self) -> Option<Self::Item> {
724        Some(Package::new(self.cache, self.pkgs.next()?))
725    }
726}
727
728#[cxx::bridge]
729pub(crate) mod raw {
730    impl UniquePtr<PkgRecords> {}
731
732    unsafe extern "C++" {
733        include!("oma-apt/apt-pkg-c/cache.h");
734        type PkgCacheFile;
735
736        type PkgIterator = crate::raw::PkgIterator;
737        type VerIterator = crate::raw::VerIterator;
738        type PkgFileIterator = crate::raw::PkgFileIterator;
739        type PkgRecords = crate::records::raw::PkgRecords;
740        type SourceRecords = crate::records::raw::SourceRecords;
741        type IndexFile = crate::records::raw::IndexFile;
742        type PkgDepCache = crate::depcache::raw::PkgDepCache;
743        type AcqTextStatus = crate::acquire::raw::AcqTextStatus;
744        type PkgAcquire = crate::acquire::raw::PkgAcquire;
745
746        /// Create the CacheFile.
747        pub fn create_cache(volatile_files: &[&str]) -> Result<UniquePtr<PkgCacheFile>>;
748
749        /// Update the package lists, handle errors and return a Result.
750        pub fn update(self: &PkgCacheFile, progress: Pin<&mut AcqTextStatus>) -> Result<()>;
751
752        /// Loads the index files into PkgAcquire.
753        ///
754        /// Used to get to source list uris.
755        ///
756        /// It's not clear if this returning a bool is useful.
757        pub fn get_indexes(self: &PkgCacheFile, fetcher: &PkgAcquire) -> bool;
758
759        /// Return a pointer to PkgDepcache.
760        ///
761        /// # Safety
762        ///
763        /// The returned UniquePtr cannot outlive the cache.
764        unsafe fn create_depcache(self: &PkgCacheFile) -> UniquePtr<PkgDepCache>;
765
766        /// Return a pointer to PkgRecords.
767        ///
768        /// # Safety
769        ///
770        /// The returned UniquePtr cannot outlive the cache.
771        unsafe fn create_records(self: &PkgCacheFile) -> UniquePtr<PkgRecords>;
772
773        unsafe fn source_records(self: &PkgCacheFile) -> Result<UniquePtr<SourceRecords>>;
774
775        /// The priority of the Version as shown in `apt policy`.
776        pub fn priority(self: &PkgCacheFile, version: &VerIterator) -> i32;
777
778        /// Lookup the IndexFile of the Package file
779        ///
780        /// # Safety
781        ///
782        /// The IndexFile can not outlive PkgCacheFile.
783        ///
784        /// The returned UniquePtr cannot outlive the cache.
785        unsafe fn find_index(self: &PkgCacheFile, file: &PkgFileIterator) -> UniquePtr<IndexFile>;
786
787        /// Return a package by name and optionally architecture.
788        ///
789        /// # Safety
790        ///
791        /// If the Internal Pkg Pointer is NULL, operations can segfault.
792        /// You should call `make_safe()` asap to convert it to an Option.
793        ///
794        /// The returned UniquePtr cannot outlive the cache.
795        unsafe fn find_pkg(self: &PkgCacheFile, name: &str) -> UniquePtr<PkgIterator>;
796
797        /// Return the pointer to the start of the PkgIterator.
798        ///
799        /// # Safety
800        ///
801        /// If the Internal Pkg Pointer is NULL, operations can segfault.
802        /// You should call `raw_iter()` asap.
803        ///
804        /// The returned UniquePtr cannot outlive the cache.
805        unsafe fn begin(self: &PkgCacheFile) -> UniquePtr<PkgIterator>;
806    }
807}