//! Contains Cache related structs.
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt;
use std::rc::Rc;
use cxx::UniquePtr;
use crate::config::init_config_system;
use crate::depcache::DepCache;
use crate::package::Package;
use crate::pkgmanager::PackageManager;
use crate::progress::{AcquireProgress, InstallProgress, OperationProgress};
use crate::records::Records;
use crate::resolver::ProblemResolver;
use crate::util::{apt_lock, apt_unlock, apt_unlock_inner, DiskSpace, Exception};
use crate::{depcache, package};
/// Struct for sorting packages.
pub type PackageSort = raw::PackageSort;
/// Enum for the Package Sorter.
pub type Sort = raw::Sort;
/// Enum to determine the upgrade type.
pub type Upgrade = depcache::raw::Upgrade;
impl Default for PackageSort {
fn default() -> PackageSort {
PackageSort {
names: false,
upgradable: Sort::Disable,
virtual_pkgs: Sort::Disable,
installed: Sort::Disable,
auto_installed: Sort::Disable,
auto_removable: Sort::Disable,
}
}
}
impl PackageSort {
/// Packages will be sorted by their names a -> z.
pub fn names(mut self) -> Self {
self.names = true;
self
}
/// Only packages that are upgradable will be included.
pub fn upgradable(mut self) -> Self {
self.upgradable = Sort::Enable;
self
}
/// Only packages that are NOT upgradable will be included.
pub fn not_upgradable(mut self) -> Self {
self.upgradable = Sort::Reverse;
self
}
/// Virtual packages will be included.
pub fn include_virtual(mut self) -> Self {
self.virtual_pkgs = Sort::Enable;
self
}
/// Only Virtual packages will be included.
pub fn only_virtual(mut self) -> Self {
self.virtual_pkgs = Sort::Reverse;
self
}
/// Only packages that are installed will be included.
pub fn installed(mut self) -> Self {
self.installed = Sort::Enable;
self
}
/// Only packages that are NOT installed will be included.
pub fn not_installed(mut self) -> Self {
self.installed = Sort::Reverse;
self
}
/// Only packages that are auto installed will be included.
pub fn auto_installed(mut self) -> Self {
self.auto_installed = Sort::Enable;
self
}
/// Only packages that are manually installed will be included.
pub fn manually_installed(mut self) -> Self {
self.auto_installed = Sort::Reverse;
self
}
/// Only packages that are auto removable will be included.
pub fn auto_removable(mut self) -> Self {
self.auto_removable = Sort::Enable;
self
}
/// Only packages that are NOT auto removable will be included.
pub fn not_auto_removable(mut self) -> Self {
self.auto_removable = Sort::Reverse;
self
}
}
/// Internal struct to pass into [`self::Cache::resolve`]. The C++ library for
/// this wants a progress parameter for this, but it doesn't appear to be doing
/// anything. Furthermore, [the Python-APT implementation doesn't accept a
/// parameter for their dependency resolution funcionality](https://apt-team.pages.debian.net/python-apt/library/apt_pkg.html#apt_pkg.ProblemResolver.resolve),
/// so we should be safe to remove it here.
struct NoOpProgress {}
impl NoOpProgress {
/// Return the AptAcquireProgress in a box
/// To easily pass through for progress
pub fn new_box() -> Box<dyn OperationProgress> { Box::new(NoOpProgress {}) }
}
impl OperationProgress for NoOpProgress {
fn update(&mut self, _: String, _: f32) {}
fn done(&mut self) {}
}
/// Internal struct for managing references to pointers
#[derive(Debug)]
pub(crate) struct PointerMap {
package_map: HashMap<String, Rc<RefCell<raw::PackagePtr>>>,
version_map: HashMap<u32, Rc<RefCell<raw::VersionPtr>>>,
}
impl PointerMap {
pub fn new() -> PointerMap {
PointerMap {
package_map: HashMap::new(),
version_map: HashMap::new(),
}
}
/// Remap all pointers after clearing the entire cache
pub fn remap(&mut self, cache: &UniquePtr<raw::PkgCacheFile>) {
// Remap packages to coincide with the new cache
for (name, pkg_ptr) in self.package_map.iter_mut() {
pkg_ptr.replace(
raw::pkg_cache_find_name(cache, name.to_owned())
// I think it's okay to panic here in the event of a null ptr
.expect("Null package pointer found in pointer map"),
);
// Remap versions
for ver_ptr in raw::pkg_version_list(&pkg_ptr.borrow()) {
let ver_id = crate::package::raw::ver_id(&ver_ptr);
// If the ID is in the map, replace it. Otherwise it doesn't need updating
if let Some(ver) = self.version_map.get_mut(&ver_id) {
ver.replace(ver_ptr);
}
}
}
// Throw away any of the pointers that are null
// Really this says to keep it if it's not null
self.package_map
.retain(|_, pkg| !pkg.borrow().ptr.is_null())
}
/// Get a reference to a package pointer.
/// Create it first if it doesn't exist.
pub fn get_package(&mut self, pkg_ptr: raw::PackagePtr) -> Rc<RefCell<raw::PackagePtr>> {
let pkg_name = crate::package::raw::get_fullname(&pkg_ptr, false);
match self.package_map.get(&pkg_name) {
// Package already exists, hand out a reference
Some(pkg) => Rc::clone(pkg),
// Package doesn't exist,
// insert it into the map and then return a reference
None => {
let pkg = Rc::new(RefCell::new(pkg_ptr));
let clone = Rc::clone(&pkg);
// Insert the package into our map
self.package_map.insert(pkg_name.to_owned(), pkg);
// Return the reference cell
clone
},
}
}
/// Get a reference to a version pointer.
/// Create it first if it doesn't exist.
pub fn get_version(&mut self, ver_ptr: raw::VersionPtr) -> Rc<RefCell<raw::VersionPtr>> {
let ver_id = crate::package::raw::ver_id(&ver_ptr);
match self.version_map.get(&ver_id) {
// Version already exists, hand out a reference
Some(ver) => Rc::clone(ver),
// Version doesn't exist,
// insert it into the map and then return a reference
None => {
let ver = Rc::new(RefCell::new(ver_ptr));
let clone = Rc::clone(&ver);
// Insert the version into our map
self.version_map.insert(ver_id, ver);
// Return the reference cell
clone
},
}
}
}
/// The main struct for accessing any and all `apt` data.
#[derive(Debug)]
pub struct Cache {
pub ptr: Rc<RefCell<UniquePtr<raw::PkgCacheFile>>>,
pub records: Rc<RefCell<Records>>,
depcache: Rc<RefCell<DepCache>>,
resolver: Rc<RefCell<ProblemResolver>>,
pkgmanager: Rc<RefCell<PackageManager>>,
pointer_map: Rc<RefCell<PointerMap>>,
}
impl Default for Cache {
fn default() -> Self { Self::new() }
}
impl Cache {
/// Initialize the configuration system, open and return the cache.
///
/// This is the entry point for all operations of this crate.
pub fn new() -> Self {
init_config_system();
let cache_ptr = Rc::new(RefCell::new(raw::pkg_cache_create()));
Self {
records: Rc::new(RefCell::new(Records::new(Rc::clone(&cache_ptr)))),
depcache: Rc::new(RefCell::new(DepCache::new(Rc::clone(&cache_ptr)))),
resolver: Rc::new(RefCell::new(ProblemResolver::new(Rc::clone(&cache_ptr)))),
pkgmanager: Rc::new(RefCell::new(PackageManager::new(Rc::clone(&cache_ptr)))),
ptr: cache_ptr,
pointer_map: Rc::new(RefCell::new(PointerMap::new())),
}
}
/// Clear the entire cache and start new.
///
/// This function would be used after `cache.update`
/// Or after do_install if you plan on making more changes
pub fn clear(&self) {
// Replace all of the Cache references
self.ptr.replace(raw::pkg_cache_create());
self.records.replace(Records::new(Rc::clone(&self.ptr)));
self.depcache.replace(DepCache::new(Rc::clone(&self.ptr)));
self.resolver
.replace(ProblemResolver::new(Rc::clone(&self.ptr)));
self.pkgmanager
.replace(PackageManager::new(Rc::clone(&self.ptr)));
// Remap packages to coincide with the new cache
self.pointer_map.borrow_mut().remap(&self.ptr.borrow());
}
/// Updates the package cache and returns a Result
///
/// Here is an example of how you may parse the Error messages.
///
/// ```
/// use rust_apt::cache::Cache;
/// use rust_apt::progress::{AcquireProgress, AptAcquireProgress};
///
/// let cache = Cache::new();
/// let mut progress: Box<dyn AcquireProgress> = Box::new(AptAcquireProgress::new());
/// if let Err(error) = cache.update(&mut progress) {
/// for msg in error.what().split(';') {
/// if msg.starts_with("E:") {
/// println!("Error: {}", &msg[2..]);
/// }
/// if msg.starts_with("W:") {
/// println!("Warning: {}", &msg[2..]);
/// }
/// }
/// }
/// ```
///
/// # Known Errors:
/// * E:Could not open lock file /var/lib/apt/lists/lock - open (13: Permission denied)
/// * E:Unable to lock directory /var/lib/apt/lists/
pub fn update(&self, progress: &mut Box<dyn AcquireProgress>) -> Result<(), Exception> {
raw::cache_update(&self.ptr.borrow(), progress)
}
/// Mark all packages for upgrade
///
/// # Example:
///
/// ```
/// use rust_apt::cache::{Cache, Upgrade};
///
/// let cache = Cache::new();
///
/// cache.upgrade(&Upgrade::FullUpgrade).unwrap();
/// ```
pub fn upgrade(&self, upgrade_type: &Upgrade) -> Result<(), Exception> {
self.depcache
.borrow()
.upgrade(&mut NoOpProgress::new_box(), upgrade_type)
}
/// An iterator over the packages
/// that will be altered when `cache.commit()` is called.
///
/// # sort_name:
/// * [`true`] = Packages will be in alphabetical order
/// * [`false`] = Packages will not be sorted by name
pub fn get_changes<'a>(&'a self, sort_name: bool) -> impl Iterator<Item = Package> + '_ {
let mut changed = Vec::new();
let depcache = self.depcache.borrow();
for pkg in raw::pkg_list(&self.ptr.borrow(), &PackageSort::default()) {
if depcache.marked_install(&pkg)
|| depcache.marked_delete(&pkg)
|| depcache.marked_upgrade(&pkg)
|| depcache.marked_downgrade(&pkg)
|| depcache.marked_reinstall(&pkg)
{
changed.push(pkg);
}
}
if sort_name {
changed.sort_by_cached_key(|pkg| package::raw::get_fullname(pkg, true));
}
changed
.into_iter()
.map(|pkg_ptr| self.make_package(pkg_ptr))
}
/// Resolve dependencies with the changes marked on all packages. This marks
/// additional packages for installation/removal to satisfy the dependency
/// chain.
///
/// Note that just running a `mark_*` function on a package doesn't
/// guarantee that the selected state will be kept during dependency
/// resolution. If you need such, make sure to run
/// [`crate::package::Package::protect`] after marking your requested
/// modifications.
///
/// If `fix_broken` is set to [`true`], the library will try to repair
/// broken dependencies of installed packages.
///
/// Returns [`Err`] if there was an error reaching dependency resolution.
#[allow(clippy::result_unit_err)]
pub fn resolve(&self, fix_broken: bool) -> Result<(), Exception> {
// Use our dummy OperationProgress struct. See
// [`crate::cache::OperationProgress`] for why we need this.
self.resolver
.borrow()
.resolve(fix_broken, &mut NoOpProgress::new_box())
}
/// Fetch any archives needed to complete the transaction.
///
/// # Returns:
/// * A [`Result`] enum: the [`Ok`] variant if fetching succeeded, and
/// [`Err`] if there was an issue.
///
/// # Example:
/// ```
/// use rust_apt::cache::Cache;
/// use rust_apt::package::Mark;
/// use rust_apt::progress::{AptAcquireProgress};
///
/// let cache = Cache::new();
/// let pkg = cache.get("neovim").unwrap();
/// let mut progress = AptAcquireProgress::new_box();
///
/// pkg.set(&Mark::Install).then_some(()).unwrap();
/// pkg.protect();
/// cache.resolve(true).unwrap();
///
/// cache.get_archives(&mut progress).unwrap();
/// ```
/// # Known Errors:
/// * W:Problem unlinking the file
/// /var/cache/apt/archives/partial/neofetch_7.1.0-4_all.deb -
/// PrepareFiles (13: Permission denied)
/// * W:Problem unlinking the file
/// /var/cache/apt/archives/partial/neofetch_7.1.0-4_all.deb -
/// PrepareFiles (13: Permission denied)
/// * W:Problem unlinking the file
/// /var/cache/apt/archives/partial/neofetch_7.1.0-4_all.deb -
/// PrepareFiles (13: Permission denied)
/// * W:Problem unlinking the file
/// /var/cache/apt/archives/partial/neofetch_7.1.0-4_all.deb -
/// PrepareFiles (13: Permission denied)
/// * W:Problem unlinking the file
/// /var/cache/apt/archives/partial/neofetch_7.1.0-4_all.deb -
/// PrepareFiles (13: Permission denied)
/// * W:Problem unlinking the file /var/log/apt/eipp.log.xz - FileFd::Open
/// (13: Permission denied)
/// * W:Could not open file /var/log/apt/eipp.log.xz - open (17: File
/// exists)
/// * W:Could not open file '/var/log/apt/eipp.log.xz' - EIPP::OrderInstall
/// (17: File exists)
/// * E:Internal Error, ordering was unable to handle the media swap"
pub fn get_archives(&self, progress: &mut Box<dyn AcquireProgress>) -> Result<(), Exception> {
self.pkgmanager
.borrow()
.get_archives(&mut self.records.borrow_mut(), progress)
}
/// Install, remove, and do any other actions requested by the cache.
///
/// # Returns:
/// * A [`Result`] enum: the [`Ok`] variant if transaction was successful,
/// and [`Err`] if there was an issue.
///
/// # Example:
/// ```
/// use rust_apt::cache::Cache;
/// use rust_apt::package::Mark;
/// use rust_apt::progress::{AptAcquireProgress, AptInstallProgress};
///
/// let cache = Cache::new();
/// let pkg = cache.get("neovim").unwrap();
/// let mut acquire_progress = AptAcquireProgress::new_box();
/// let mut install_progress = AptInstallProgress::new_box();
///
/// pkg.set(&Mark::Install).then_some(()).unwrap();
/// pkg.protect();
/// cache.resolve(true).unwrap();
///
/// // These need root
/// // cache.get_archives(&mut acquire_progress).unwrap();
/// // cache.do_install(&mut install_progress).unwrap();
/// ```
///
/// # Known Errors:
/// * W:Problem unlinking the file /var/log/apt/eipp.log.xz - FileFd::Open
/// (13: Permission denied)
/// * W:Could not open file /var/log/apt/eipp.log.xz - open (17: File
/// exists)
/// * W:Could not open file '/var/log/apt/eipp.log.xz' - EIPP::OrderInstall
/// (17: File exists)
/// * E:Could not create temporary file for /var/lib/apt/extended_states -
/// mkstemp (13: Permission denied)
/// * E:Failed to write temporary StateFile /var/lib/apt/extended_states
/// * W:Could not open file '/var/log/apt/term.log' - OpenLog (13:
/// Permission denied)
/// * E:Sub-process /usr/bin/dpkg returned an error code (2)
/// * W:Problem unlinking the file /var/cache/apt/pkgcache.bin -
/// pkgDPkgPM::Go (13: Permission denied)
pub fn do_install(&self, progress: &mut Box<dyn InstallProgress>) -> Result<(), Exception> {
self.pkgmanager.borrow().do_install(progress)
}
/// Handle get_archives and do_install in an easy wrapper.
///
/// # Returns:
/// * A [`Result`]: the [`Ok`] variant if transaction was successful, and
/// [`Err`] if there was an issue.
/// # Example:
/// ```
/// use rust_apt::cache::Cache;
/// use rust_apt::package::Mark;
/// use rust_apt::progress::{AptAcquireProgress, AptInstallProgress};
///
/// let cache = Cache::new();
/// let pkg = cache.get("neovim").unwrap();
/// let mut acquire_progress = AptAcquireProgress::new_box();
/// let mut install_progress = AptInstallProgress::new_box();
///
/// pkg.set(&Mark::Install).then_some(()).unwrap();
/// pkg.protect();
/// cache.resolve(true).unwrap();
///
/// // This needs root
/// // cache.commit(&mut acquire_progress, &mut install_progress).unwrap();
/// ```
pub fn commit(
&self,
progress: &mut Box<dyn AcquireProgress>,
install_progress: &mut Box<dyn InstallProgress>,
) -> Result<(), Exception> {
// Lock the whole thing so as to prevent tamper
apt_lock()?;
// The archives can be grabbed during the apt lock.
self.get_archives(progress)?;
// If the system is locked we will want to unlock the dpkg files.
// This way when dpkg is running it can access its files.
apt_unlock_inner();
// Perform the operation.
self.do_install(install_progress)?;
// Finally Unlock the whole thing.
apt_unlock();
Ok(())
}
/// Clear any marked changes in the DepCache.
pub fn clear_marked(&self) -> Result<(), Exception> {
// Use our dummy OperationProgress struct.
self.depcache.borrow().init(&mut NoOpProgress::new_box())
}
/// Returns an iterator of SourceURIs.
///
/// These are the files that `apt update` will fetch.
pub fn sources(&self) -> impl Iterator<Item = raw::SourceFile> + '_ {
raw::source_uris(&self.ptr.borrow()).into_iter()
}
/// Returns an iterator of Packages that provide the virtual package.
///
/// NOTE: This function is **ONLY** designed to get the list of packages of
/// a virtual package. It also expects that you'll be installing the
/// candidate version, and this likewise doesn't return a specific version
/// to install. You probably want to use [`Package::rev_provides_list`]
/// instead.
pub fn provides(
&self,
virt_pkg: &Package,
cand_only: bool,
) -> impl Iterator<Item = Package> + '_ {
raw::pkg_provides_list(&self.ptr.borrow(), &virt_pkg.ptr.borrow(), cand_only)
.into_iter()
.map(|pkg_ptr| self.make_package(pkg_ptr))
}
// Disabled as it doesn't really work yet. Would likely need to
// Be on the objects them self and not the cache
// pub fn validate(&self, ver: *mut raw::VerIterator) -> bool {
// raw::validate(ver, self._cache)
// }
/// Get a single package.
///
/// `cache.get("apt")` Returns a Package object for the native arch.
///
/// `cache.get("apt:i386")` Returns a Package object for the i386 arch
pub fn get<'a>(&'a self, name: &str) -> Option<Package<'a>> {
let mut fields = name.split(':');
let name = fields.next()?;
let arch = fields.next().unwrap_or_default();
// Match if the arch exists or not.
match arch.is_empty() {
true => {
Some(self.make_package(
raw::pkg_cache_find_name(&self.ptr.borrow(), name.to_owned()).ok()?,
))
},
false => Some(
self.make_package(
raw::pkg_cache_find_name_arch(
&self.ptr.borrow(),
name.to_owned(),
arch.to_owned(),
)
.ok()?,
),
),
}
}
/// # Internal method to create a package from a pointer and deduplicate code.
///
/// If you don't use this on the cache struct you can pass the Cache as self
///
/// # Example:
///
/// We can't have a real example here as this deals with private fields
///
/// Say `pkg_ptr` is your package pointer from the cxx binding.
///
/// let pkg = Cache::make_package(&cache, pkg_ptr);
///
/// println!("{new_pkg}");
pub(crate) fn make_package(&self, pkg_ptr: raw::PackagePtr) -> Package {
Package::new(
Rc::clone(&self.records),
Rc::clone(&self.ptr),
Rc::clone(&self.depcache),
Rc::clone(&self.resolver),
Rc::clone(&self.pointer_map),
Rc::clone(&self.pointer_map.borrow_mut().get_package(pkg_ptr)),
)
}
/// An iterator of packages in the cache.
pub fn packages<'a>(&'a self, sort: &'a PackageSort) -> impl Iterator<Item = Package> + '_ {
let mut pkg_list = raw::pkg_list(&self.ptr.borrow(), sort);
if sort.names {
pkg_list.sort_by_cached_key(|pkg| package::raw::get_fullname(pkg, true));
}
pkg_list
.into_iter()
.map(|pkg_ptr| self.make_package(pkg_ptr))
}
/// The number of packages marked for installation.
pub fn install_count(&self) -> u32 { self.depcache.borrow().install_count() }
/// The number of packages marked for removal.
pub fn delete_count(&self) -> u32 { self.depcache.borrow().delete_count() }
/// The number of packages marked for keep.
pub fn keep_count(&self) -> u32 { self.depcache.borrow().keep_count() }
/// The number of packages with broken dependencies in the cache.
pub fn broken_count(&self) -> u32 { self.depcache.borrow().broken_count() }
/// The size of all packages to be downloaded.
pub fn download_size(&self) -> u64 { self.depcache.borrow().download_size() }
/// The amount of space required for installing/removing the packages,"
///
/// i.e. the Installed-Size of all packages marked for installation"
/// minus the Installed-Size of all packages for removal."
pub fn disk_size(&self) -> DiskSpace { self.depcache.borrow().disk_size() }
}
pub struct PackageFile {
pkg_file: RefCell<raw::PackageFile>,
pub cache: Rc<RefCell<UniquePtr<raw::PkgCacheFile>>>,
}
impl PackageFile {
pub fn new(
pkg_file: raw::PackageFile,
cache: Rc<RefCell<UniquePtr<raw::PkgCacheFile>>>,
) -> PackageFile {
PackageFile {
pkg_file: RefCell::new(pkg_file),
cache,
}
}
/// The path to the PackageFile
pub fn filename(&self) -> Option<String> { raw::filename(&self.pkg_file.borrow()).ok() }
/// The Archive of the PackageFile. ex: unstable
pub fn archive(&self) -> Option<String> { raw::archive(&self.pkg_file.borrow()).ok() }
/// The Origin of the PackageFile. ex: Debian
pub fn origin(&self) -> Option<String> { raw::origin(&self.pkg_file.borrow()).ok() }
/// The Codename of the PackageFile. ex: main, non-free
pub fn codename(&self) -> Option<String> { raw::codename(&self.pkg_file.borrow()).ok() }
/// The Label of the PackageFile. ex: Debian
pub fn label(&self) -> Option<String> { raw::label(&self.pkg_file.borrow()).ok() }
/// The Hostname of the PackageFile. ex: deb.debian.org
pub fn site(&self) -> Option<String> { raw::site(&self.pkg_file.borrow()).ok() }
/// The Component of the PackageFile. ex: sid
pub fn component(&self) -> Option<String> { raw::component(&self.pkg_file.borrow()).ok() }
/// The Architecture of the PackageFile. ex: amd64
pub fn arch(&self) -> Option<String> { raw::arch(&self.pkg_file.borrow()).ok() }
/// The Index Type of the PackageFile. Known values are:
///
/// Debian Package Index,
/// Debian Translation Index,
/// Debian dpkg status file,
pub fn index_type(&self) -> Option<String> { raw::index_type(&self.pkg_file.borrow()).ok() }
/// The Index of the PackageFile
pub fn index(&self) -> u64 { raw::index(&self.pkg_file.borrow()) }
/// Return true if the PackageFile is trusted.
pub fn is_trusted(&self) -> bool {
raw::pkg_file_is_trusted(&self.cache.borrow(), &mut self.pkg_file.borrow_mut())
}
}
impl fmt::Debug for PackageFile {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"PackageFile <\n Filename: {},\n Archive: {},\n Origin: {},\n Codename: \
{},\n Label: {},\n Site: {},\n Component: {},\n Arch: {},\n Index: \
{},\n Index Type: {},\n Trusted: {},\n>",
self.filename().unwrap_or_else(|| String::from("Unknown")),
self.archive().unwrap_or_else(|| String::from("Unknown")),
self.origin().unwrap_or_else(|| String::from("Unknown")),
self.codename().unwrap_or_else(|| String::from("Unknown")),
self.label().unwrap_or_else(|| String::from("Unknown")),
self.site().unwrap_or_else(|| String::from("Unknown")),
self.component().unwrap_or_else(|| String::from("Unknown")),
self.arch().unwrap_or_else(|| String::from("Unknown")),
self.index(),
self.index_type().unwrap_or_else(|| String::from("Unknown")),
self.is_trusted(),
)?;
Ok(())
}
}
impl fmt::Display for PackageFile {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{self:?}")?;
Ok(())
}
}
/// This module contains the bindings and structs shared with c++
#[cxx::bridge]
pub mod raw {
/// Struct representing a Source File.
#[derive(Debug)]
struct SourceFile {
/// `http://deb.volian.org/volian/dists/scar/InRelease`
uri: String,
/// `deb.volian.org_volian_dists_scar_InRelease`
filename: String,
}
/// A wrapper around the Apt pkgIterator.
struct PackagePtr {
ptr: UniquePtr<PkgIterator>,
}
/// A wrapper around the Apt verIterator.
struct VersionPtr {
ptr: UniquePtr<VerIterator>,
desc: UniquePtr<DescIterator>,
}
/// A wrapper around PkgFileIterator.
struct PackageFile {
/// PackageFile UniquePtr.
ptr: UniquePtr<PkgFile>,
}
/// A wrapper around VerFileIterator.
struct VersionFile {
/// VersionFile UniquePtr.
ptr: UniquePtr<VerFileIterator>,
}
/// Enum to determine what will be sorted.
#[derive(Debug)]
pub enum Sort {
/// Disable the sort method.
Disable,
/// Enable the sort method.
Enable,
/// Reverse the sort method.
Reverse,
}
/// Struct for sorting packages.
#[derive(Debug)]
pub struct PackageSort {
pub names: bool,
pub upgradable: Sort,
pub virtual_pkgs: Sort,
pub installed: Sort,
pub auto_installed: Sort,
pub auto_removable: Sort,
}
unsafe extern "C++" {
/// Apt C++ Type
type PkgCacheFile;
/// Apt C++ Type
type PkgCache;
/// Apt C++ Type
type PkgSourceList;
/// Apt C++ Type
type PkgDepCache;
/// Apt C++ Type
type PkgIterator;
/// Apt C++ Type
type PkgFile;
/// Apt C++ Type
type VerIterator;
/// Apt C++ Type
type VerFileIterator;
/// Apt C++ Type
type DescIterator;
type DynAcquireProgress = crate::progress::raw::DynAcquireProgress;
include!("rust-apt/apt-pkg-c/cache.h");
include!("rust-apt/apt-pkg-c/progress.h");
include!("rust-apt/apt-pkg-c/records.h");
// Main Initializers for apt:
/// Create the CacheFile.
///
/// It is advised to init the config and system before creating the
/// cache. These bindings can be found in config::raw.
// TODO: Maybe this should return result. I believe this can fail with an apt error
pub fn pkg_cache_create() -> UniquePtr<PkgCacheFile>;
/// Update the package lists, handle errors and return a Result.
// TODO: What kind of errors can be returned here?
// TODO: Implement custom errors to match with apt errors
pub fn cache_update(
cache: &UniquePtr<PkgCacheFile>,
progress: &mut DynAcquireProgress,
) -> Result<()>;
/// Get the package list uris. This is the files that are updated with
/// `apt update`.
pub fn source_uris(cache: &UniquePtr<PkgCacheFile>) -> Vec<SourceFile>;
// Package Functions:
/// Returns a Vector of all the packages in the cache.
pub fn pkg_list(cache: &UniquePtr<PkgCacheFile>, sort: &PackageSort) -> Vec<PackagePtr>;
// pkg_file_list and pkg_version_list should be in package::raw
// I was unable to make this work so they remain here.
/// Return a Vector of all the VersionFiles for a version.
pub fn ver_file_list(ver: &VersionPtr) -> Vec<VersionFile>;
/// Return a Vector of all the PackageFiles for a version.
pub fn ver_pkg_file_list(ver: &VersionPtr) -> Vec<PackageFile>;
/// Return a Vector of all the versions of a package.
pub fn pkg_version_list(pkg: &PackagePtr) -> Vec<VersionPtr>;
/// Return a Vector of all the packages that provide another. steam:i386
/// provides steam.
pub fn pkg_provides_list(
cache: &UniquePtr<PkgCacheFile>,
iterator: &PackagePtr,
cand_only: bool,
) -> Vec<PackagePtr>;
/// Return a package by name.
/// Ptr will be NULL if the package doesn't exist.
// TODO: This should probably return result with an error
// TODO: "Package does not exist"
pub fn pkg_cache_find_name(
cache: &UniquePtr<PkgCacheFile>,
name: String,
) -> Result<PackagePtr>;
/// Return a package by name and architecture.
/// Ptr will be NULL if the package doesn't exist.
// TODO: This should probably return result with an error
// TODO: "Package does not exist"
pub fn pkg_cache_find_name_arch(
cache: &UniquePtr<PkgCacheFile>,
name: String,
arch: String,
) -> Result<PackagePtr>;
// PackageFile Functions:
/// The path to the PackageFile
///
/// Error "Unknown" if the information doesn't exist.
pub fn filename(pkg_file: &PackageFile) -> Result<String>;
/// The Archive of the PackageFile. ex: unstable
///
/// Error "Unknown" if the information doesn't exist.
pub fn archive(pkg_file: &PackageFile) -> Result<String>;
/// The Origin of the PackageFile. ex: Debian
///
/// Error "Unknown" if the information doesn't exist.
pub fn origin(pkg_file: &PackageFile) -> Result<String>;
/// The Codename of the PackageFile. ex: main, non-free
///
/// Error "Unknown" if the information doesn't exist.
pub fn codename(pkg_file: &PackageFile) -> Result<String>;
/// The Label of the PackageFile. ex: Debian
///
/// Error "Unknown" if the information doesn't exist.
pub fn label(pkg_file: &PackageFile) -> Result<String>;
/// The Hostname of the PackageFile. ex: deb.debian.org
///
/// Error "Unknown" if the information doesn't exist.
pub fn site(pkg_file: &PackageFile) -> Result<String>;
/// The Component of the PackageFile. ex: sid
///
/// Error "Unknown" if the information doesn't exist.
pub fn component(pkg_file: &PackageFile) -> Result<String>;
/// The Architecture of the PackageFile. ex: amd64
///
/// Error "Unknown" if the information doesn't exist.
pub fn arch(pkg_file: &PackageFile) -> Result<String>;
/// The Index Type of the PackageFile. Known values are:
///
/// Debian Package Index,
/// Debian Translation Index,
/// Debian dpkg status file,
///
/// Error "Unknown" if the information doesn't exist.
pub fn index_type(pkg_file: &PackageFile) -> Result<String>;
/// The Index of the PackageFile
pub fn index(pkg_file: &PackageFile) -> u64;
/// Return true if the PackageFile is trusted.
pub fn pkg_file_is_trusted(
cache: &UniquePtr<PkgCacheFile>,
pkg_file: &mut PackageFile,
) -> bool;
}
}
impl fmt::Debug for raw::VersionPtr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"VersionPtr: {}:{}",
package::raw::get_fullname(&package::raw::ver_parent(self), false),
package::raw::ver_str(self)
)?;
Ok(())
}
}
impl fmt::Debug for raw::PkgCacheFile {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "PkgCacheFile: {{ To Be Implemented }}")?;
Ok(())
}
}
impl fmt::Debug for raw::PkgDepCache {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "PkgDepCache: {{ To Be Implemented }}")?;
Ok(())
}
}
impl fmt::Debug for raw::PackagePtr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "PackagePtr: {}", package::raw::get_fullname(self, false))?;
Ok(())
}
}
impl fmt::Display for raw::SourceFile {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Source< Uri: {}, Filename: {}>", self.uri, self.filename)?;
Ok(())
}
}
impl fmt::Debug for raw::PackageFile {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "PackageFile: {{ To Be Implemented }}")?;
Ok(())
}
}
impl fmt::Debug for raw::VersionFile {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "VersionFile: {{ To Be Implemented }}")?;
Ok(())
}
}