rust_apt/iterators/package.rs
1use std::cell::OnceCell;
2use std::collections::HashMap;
3use std::fmt;
4
5use cxx::UniquePtr;
6
7use crate::raw::{IntoRawIter, PkgIterator};
8use crate::{create_depends_map, Cache, DepType, Dependency, Provider, Version};
9/// The state that the user wishes the package to be in.
10#[derive(Debug, Eq, PartialEq, Hash)]
11pub enum PkgSelectedState {
12 Unknown = 0,
13 Install = 1,
14 Hold = 2,
15 DeInstall = 3,
16 Purge = 4,
17}
18
19impl From<u8> for PkgSelectedState {
20 fn from(value: u8) -> Self {
21 match value {
22 0 => PkgSelectedState::Unknown,
23 1 => PkgSelectedState::Install,
24 2 => PkgSelectedState::Hold,
25 3 => PkgSelectedState::DeInstall,
26 4 => PkgSelectedState::Purge,
27 _ => panic!("PkgSelectedState is malformed?"),
28 }
29 }
30}
31
32/// Installation state of the package
33#[derive(Debug, Eq, PartialEq, Hash)]
34pub enum PkgInstState {
35 Ok = 0,
36 ReInstReq = 1,
37 HoldInst = 2,
38 HoldReInstReq = 3,
39}
40
41impl From<u8> for PkgInstState {
42 fn from(value: u8) -> Self {
43 match value {
44 0 => PkgInstState::Ok,
45 1 => PkgInstState::ReInstReq,
46 2 => PkgInstState::HoldInst,
47 3 => PkgInstState::HoldReInstReq,
48 _ => panic!("PkgInstState is malformed?"),
49 }
50 }
51}
52
53/// The current state of a Package.
54#[derive(Debug, Eq, PartialEq, Hash)]
55pub enum PkgCurrentState {
56 NotInstalled = 0,
57 UnPacked = 1,
58 HalfConfigured = 2,
59 HalfInstalled = 4,
60 ConfigFiles = 5,
61 Installed = 6,
62 TriggersAwaited = 7,
63 TriggersPending = 8,
64}
65
66impl From<u8> for PkgCurrentState {
67 fn from(value: u8) -> Self {
68 match value {
69 0 => PkgCurrentState::NotInstalled,
70 1 => PkgCurrentState::UnPacked,
71 2 => PkgCurrentState::HalfConfigured,
72 4 => PkgCurrentState::HalfInstalled,
73 5 => PkgCurrentState::ConfigFiles,
74 6 => PkgCurrentState::Installed,
75 7 => PkgCurrentState::TriggersAwaited,
76 8 => PkgCurrentState::TriggersPending,
77 _ => panic!("PkgCurrentState is malformed?"),
78 }
79 }
80}
81
82/// A single unique libapt package.
83pub struct Package<'a> {
84 pub(crate) ptr: UniquePtr<PkgIterator>,
85 pub(crate) cache: &'a Cache,
86 rdepends_map: OnceCell<HashMap<DepType, Vec<Dependency<'a>>>>,
87}
88
89impl<'a> Package<'a> {
90 pub fn new(cache: &'a Cache, ptr: UniquePtr<PkgIterator>) -> Package<'a> {
91 Package {
92 ptr,
93 cache,
94 rdepends_map: OnceCell::new(),
95 }
96 }
97
98 /// Returns a Reverse Dependency Map of the package
99 ///
100 /// Dependencies are in a `Vec<Dependency>`
101 ///
102 /// The Dependency struct represents an Or Group of dependencies.
103 ///
104 /// For example where we use the [`crate::DepType::Depends`] key:
105 ///
106 /// ```
107 /// use rust_apt::{new_cache, DepType};
108 /// let cache = new_cache!().unwrap();
109 /// let pkg = cache.get("apt").unwrap();
110 /// for dep in pkg.rdepends().get(&DepType::Depends).unwrap() {
111 /// if dep.is_or() {
112 /// for base_dep in dep.iter() {
113 /// println!("{}", base_dep.name())
114 /// }
115 /// } else {
116 /// // is_or is false so there is only one BaseDep
117 /// println!("{}", dep.first().name())
118 /// }
119 /// }
120 /// ```
121 pub fn rdepends(&self) -> &HashMap<DepType, Vec<Dependency<'a>>> {
122 self.rdepends_map.get_or_init(|| {
123 create_depends_map(self.cache, unsafe { self.ptr.rdepends().make_safe() })
124 })
125 }
126
127 /// Return either a Version or None
128 ///
129 /// # Example:
130 /// ```
131 /// use rust_apt::new_cache;
132 ///
133 /// let cache = new_cache!().unwrap();
134 /// let pkg = cache.get("apt").unwrap();
135 ///
136 /// pkg.get_version("2.4.7");
137 /// ```
138 pub fn get_version(&'a self, version_str: &str) -> Option<Version<'a>> {
139 for ver in unsafe { self.ptr.versions().raw_iter() } {
140 if version_str == ver.version() {
141 return Some(Version::new(ver, self.cache));
142 }
143 }
144 None
145 }
146
147 /// True if the Package is installed.
148 pub fn is_installed(&self) -> bool { unsafe { !self.current_version().end() } }
149
150 /// True if the package has versions.
151 ///
152 /// If a package has no versions it is considered virtual.
153 pub fn has_versions(&self) -> bool { unsafe { !self.ptr.versions().end() } }
154
155 /// True if the package provides any other packages.
156 pub fn has_provides(&self) -> bool { unsafe { !self.ptr.provides().end() } }
157
158 /// The installed state of this package.
159 pub fn inst_state(&self) -> PkgInstState { PkgInstState::from(self.ptr.inst_state()) }
160
161 /// The selected state of this package.
162 pub fn selected_state(&self) -> PkgSelectedState {
163 PkgSelectedState::from(self.ptr.selected_state())
164 }
165
166 /// The current state of this package.
167 pub fn current_state(&self) -> PkgCurrentState {
168 PkgCurrentState::from(self.ptr.current_state())
169 }
170
171 /// Returns the version object of the installed version.
172 ///
173 /// If there isn't an installed version, returns None
174 pub fn installed(&self) -> Option<Version<'a>> {
175 Some(Version::new(
176 unsafe { self.current_version().make_safe() }?,
177 self.cache,
178 ))
179 }
180
181 /// Returns the version object of the candidate.
182 ///
183 /// If there isn't a candidate, returns None
184 pub fn candidate(&self) -> Option<Version<'a>> {
185 Some(Version::new(
186 unsafe { self.cache.depcache().candidate_version(self).make_safe()? },
187 self.cache,
188 ))
189 }
190
191 /// Returns the install version if it exists.
192 ///
193 /// # This differs from [`crate::Package::installed`] in the
194 /// # following ways:
195 ///
196 /// * If a version is marked for install this will return the version to be
197 /// installed.
198 /// * If an installed package is marked for removal, this will return
199 /// [`None`].
200 pub fn install_version(&self) -> Option<Version<'a>> {
201 // Cxx error here just indicates that the Version doesn't exist
202 Some(Version::new(
203 unsafe { self.cache.depcache().install_version(self).make_safe()? },
204 self.cache,
205 ))
206 }
207
208 /// Returns a version list
209 /// starting with the newest and ending with the oldest.
210 pub fn versions(&self) -> impl Iterator<Item = Version<'a>> {
211 unsafe { self.ptr.versions() }
212 .raw_iter()
213 .map(|ver| Version::new(ver, self.cache))
214 }
215
216 /// Returns a list of providers
217 pub fn provides(&self) -> impl Iterator<Item = Provider<'a>> {
218 unsafe { self.ptr.provides() }
219 .raw_iter()
220 .map(|p| Provider::new(p, self.cache))
221 }
222
223 /// Check if the package is upgradable.
224 ///
225 /// ## skip_depcache:
226 ///
227 /// Skipping the DepCache is unnecessary if it's already been initialized.
228 /// If you're unsure use `false`
229 ///
230 /// * [true] = Increases performance by skipping the pkgDepCache.
231 /// * [false] = Use DepCache to check if the package is upgradable
232 pub fn is_upgradable(&self) -> bool {
233 self.is_installed() && self.cache.depcache().is_upgradable(self)
234 }
235
236 /// Check if the package is auto installed. (Not installed by the user)
237 pub fn is_auto_installed(&self) -> bool { self.cache.depcache().is_auto_installed(self) }
238
239 /// Check if the package is auto removable
240 pub fn is_auto_removable(&self) -> bool {
241 (self.is_installed() || self.marked_install()) && self.cache.depcache().is_garbage(self)
242 }
243
244 /// Check if the package is now broken
245 pub fn is_now_broken(&self) -> bool { self.cache.depcache().is_now_broken(self) }
246
247 /// Check if the package package installed is broken
248 pub fn is_inst_broken(&self) -> bool { self.cache.depcache().is_inst_broken(self) }
249
250 /// Check if the package is marked install
251 pub fn marked_install(&self) -> bool { self.cache.depcache().marked_install(self) }
252
253 /// Check if the package is marked upgrade
254 pub fn marked_upgrade(&self) -> bool { self.cache.depcache().marked_upgrade(self) }
255
256 /// Check if the package is marked purge
257 pub fn marked_purge(&self) -> bool { self.cache.depcache().marked_purge(self) }
258
259 /// Check if the package is marked delete
260 pub fn marked_delete(&self) -> bool { self.cache.depcache().marked_delete(self) }
261
262 /// Check if the package is marked keep
263 pub fn marked_keep(&self) -> bool { self.cache.depcache().marked_keep(self) }
264
265 /// Check if the package is marked downgrade
266 pub fn marked_downgrade(&self) -> bool { self.cache.depcache().marked_downgrade(self) }
267
268 /// Check if the package is marked reinstall
269 pub fn marked_reinstall(&self) -> bool { self.cache.depcache().marked_reinstall(self) }
270
271 /// # Mark a package as automatically installed.
272 ///
273 /// ## mark_auto:
274 /// * [true] = Mark the package as automatically installed.
275 /// * [false] = Mark the package as manually installed.
276 pub fn mark_auto(&self, mark_auto: bool) -> bool {
277 self.cache.depcache().mark_auto(self, mark_auto);
278 // Convert to a bool to remain consistent with other mark functions.
279 true
280 }
281
282 /// # Mark a package for keep.
283 ///
284 /// ## Returns:
285 /// * [true] if the mark was successful
286 /// * [false] if the mark was unsuccessful
287 ///
288 /// This means that the package will not be changed from its current
289 /// version. This will not stop a reinstall, but will stop removal, upgrades
290 /// and downgrades
291 ///
292 /// We don't believe that there is any reason to unmark packages for keep.
293 /// If someone has a reason, and would like it implemented, please put in a
294 /// feature request.
295 pub fn mark_keep(&self) -> bool { self.cache.depcache().mark_keep(self) }
296
297 /// # Mark a package for removal.
298 ///
299 /// ## Returns:
300 /// * [true] if the mark was successful
301 /// * [false] if the mark was unsuccessful
302 ///
303 /// ## purge:
304 /// * [true] = Configuration files will be removed along with the package.
305 /// * [false] = Only the package will be removed.
306 pub fn mark_delete(&self, purge: bool) -> bool {
307 self.cache.depcache().mark_delete(self, purge)
308 }
309
310 /// # Mark a package for installation.
311 ///
312 /// ## auto_inst:
313 /// * [true] = Additionally mark the dependencies for this package.
314 /// * [false] = Mark only this package.
315 ///
316 /// ## from_user:
317 /// * [true] = The package will be marked manually installed.
318 /// * [false] = The package will be unmarked automatically installed.
319 ///
320 /// ## Returns:
321 /// * [true] if the mark was successful
322 /// * [false] if the mark was unsuccessful
323 ///
324 /// If a package is already installed, at the latest version,
325 /// and you mark that package for install you will get true,
326 /// but the package will not be altered.
327 /// `pkg.marked_install()` will be false
328 pub fn mark_install(&self, auto_inst: bool, from_user: bool) -> bool {
329 self.cache
330 .depcache()
331 .mark_install(self, auto_inst, from_user)
332 }
333
334 /// # Mark a package for reinstallation.
335 ///
336 /// ## Returns:
337 /// * [true] if the mark was successful
338 /// * [false] if the mark was unsuccessful
339 ///
340 /// ## reinstall:
341 /// * [true] = The package will be marked for reinstall.
342 /// * [false] = The package will be unmarked for reinstall.
343 pub fn mark_reinstall(&self, reinstall: bool) -> bool {
344 self.cache.depcache().mark_reinstall(self, reinstall);
345 // Convert to a bool to remain consistent with other mark functions/
346 true
347 }
348
349 /// Protect a package's state
350 /// for when [`crate::cache::Cache::resolve`] is called.
351 pub fn protect(&self) { self.cache.resolver().protect(self) }
352}
353
354impl<'a> fmt::Display for Package<'a> {
355 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
356 write!(f, "{}", self.name())?;
357 Ok(())
358 }
359}
360
361impl<'a> fmt::Debug for Package<'a> {
362 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
363 let versions: Vec<Version> = self.versions().collect();
364 f.debug_struct("Package")
365 .field("name", &self.name())
366 .field("arch", &self.arch())
367 .field("virtual", &versions.is_empty())
368 .field("versions", &versions)
369 .finish_non_exhaustive()
370 }
371}
372
373#[cxx::bridge]
374pub(crate) mod raw {
375 unsafe extern "C++" {
376 include!("rust-apt/apt-pkg-c/package.h");
377
378 type PkgIterator;
379 type VerIterator = crate::iterators::VerIterator;
380 type PrvIterator = crate::iterators::PrvIterator;
381 type DepIterator = crate::iterators::DepIterator;
382
383 /// Get the name of the package without the architecture.
384 pub fn name(self: &PkgIterator) -> &str;
385
386 /// Get the architecture of a package.
387 pub fn arch(self: &PkgIterator) -> &str;
388
389 /// Get the fullname of the package.
390 ///
391 /// Pretty is a bool that will omit the native arch.
392 pub fn fullname(self: &PkgIterator, pretty: bool) -> String;
393
394 /// Get the current state of a package.
395 pub fn current_state(self: &PkgIterator) -> u8;
396
397 /// Get the installed state of a package.
398 pub fn inst_state(self: &PkgIterator) -> u8;
399
400 /// Get the selected state of a package.
401 pub fn selected_state(self: &PkgIterator) -> u8;
402
403 /// True if the package is essential.
404 pub fn is_essential(self: &PkgIterator) -> bool;
405
406 /// Get a pointer the the currently installed version.
407 ///
408 /// # Safety
409 ///
410 /// If the inner pointer is null segfaults can occur.
411 ///
412 /// Using [`crate::raw::IntoRawIter::make_safe`] to convert to an Option
413 /// is recommended.
414 ///
415 /// The returned UniquePtr cannot outlive the cache.
416 unsafe fn current_version(self: &PkgIterator) -> UniquePtr<VerIterator>;
417
418 /// Get a pointer to the beginning of the VerIterator.
419 ///
420 /// # Safety
421 ///
422 /// If the inner pointer is null segfaults can occur.
423 ///
424 /// Using [`crate::raw::IntoRawIter::make_safe`] to convert to an Option
425 /// is recommended.
426 ///
427 /// The returned UniquePtr cannot outlive the cache.
428 unsafe fn versions(self: &PkgIterator) -> UniquePtr<VerIterator>;
429
430 /// Get the providers of this package.
431 ///
432 /// # Safety
433 ///
434 /// If the inner pointer is null segfaults can occur.
435 ///
436 /// Using [`crate::raw::IntoRawIter::make_safe`] to convert to an Option
437 /// is recommended.
438 ///
439 /// The returned UniquePtr cannot outlive the cache.
440 unsafe fn provides(self: &PkgIterator) -> UniquePtr<PrvIterator>;
441
442 /// Get the reverse dependencies of this package
443 ///
444 /// # Safety
445 ///
446 /// If the inner pointer is null segfaults can occur.
447 ///
448 /// Using [`crate::raw::IntoRawIter::make_safe`] to convert to an Option
449 /// is recommended.
450 ///
451 /// The returned UniquePtr cannot outlive the cache.
452 unsafe fn rdepends(self: &PkgIterator) -> UniquePtr<DepIterator>;
453
454 #[cxx_name = "Index"]
455 pub fn index(self: &PkgIterator) -> u64;
456 /// Clone the pointer.
457 ///
458 /// # Safety
459 ///
460 /// If the inner pointer is null segfaults can occur.
461 ///
462 /// Using [`crate::raw::IntoRawIter::make_safe`] to convert to an Option
463 /// is recommended.
464 ///
465 /// The returned UniquePtr cannot outlive the cache.
466 unsafe fn unique(self: &PkgIterator) -> UniquePtr<PkgIterator>;
467 pub fn raw_next(self: Pin<&mut PkgIterator>);
468 pub fn end(self: &PkgIterator) -> bool;
469 }
470}