1use std::cell::OnceCell;
2use std::cmp::Ordering;
3use std::collections::HashMap;
4use std::fmt;
5
6use cxx::UniquePtr;
7
8use crate::raw::{IntoRawIter, PkgIterator};
9use crate::{Cache, DepType, Dependency, Provider, Version, create_depends_map, util};
10#[derive(Debug, Eq, PartialEq, Hash)]
12pub enum PkgSelectedState {
13 Unknown = 0,
14 Install = 1,
15 Hold = 2,
16 DeInstall = 3,
17 Purge = 4,
18}
19
20impl From<u8> for PkgSelectedState {
21 fn from(value: u8) -> Self {
22 match value {
23 0 => PkgSelectedState::Unknown,
24 1 => PkgSelectedState::Install,
25 2 => PkgSelectedState::Hold,
26 3 => PkgSelectedState::DeInstall,
27 4 => PkgSelectedState::Purge,
28 _ => panic!("PkgSelectedState is malformed?"),
29 }
30 }
31}
32
33#[derive(Debug, Eq, PartialEq, Hash)]
35pub enum PkgInstState {
36 Ok = 0,
37 ReInstReq = 1,
38 HoldInst = 2,
39 HoldReInstReq = 3,
40}
41
42impl From<u8> for PkgInstState {
43 fn from(value: u8) -> Self {
44 match value {
45 0 => PkgInstState::Ok,
46 1 => PkgInstState::ReInstReq,
47 2 => PkgInstState::HoldInst,
48 3 => PkgInstState::HoldReInstReq,
49 _ => panic!("PkgInstState is malformed?"),
50 }
51 }
52}
53
54#[derive(Debug, Eq, PartialEq, Hash)]
56pub enum PkgCurrentState {
57 NotInstalled = 0,
58 UnPacked = 1,
59 HalfConfigured = 2,
60 HalfInstalled = 4,
61 ConfigFiles = 5,
62 Installed = 6,
63 TriggersAwaited = 7,
64 TriggersPending = 8,
65}
66
67impl From<u8> for PkgCurrentState {
68 fn from(value: u8) -> Self {
69 match value {
70 0 => PkgCurrentState::NotInstalled,
71 1 => PkgCurrentState::UnPacked,
72 2 => PkgCurrentState::HalfConfigured,
73 4 => PkgCurrentState::HalfInstalled,
74 5 => PkgCurrentState::ConfigFiles,
75 6 => PkgCurrentState::Installed,
76 7 => PkgCurrentState::TriggersAwaited,
77 8 => PkgCurrentState::TriggersPending,
78 _ => panic!("PkgCurrentState is malformed?"),
79 }
80 }
81}
82
83#[derive(Debug)]
84pub enum Marked {
85 NewInstall,
86 Install,
87 ReInstall,
88 Remove,
89 Purge,
90 Keep,
91 Upgrade,
92 Downgrade,
93 Held,
94 None,
95}
96
97pub struct Package<'a> {
99 pub(crate) ptr: UniquePtr<PkgIterator>,
100 pub(crate) cache: &'a Cache,
101 rdepends_map: OnceCell<HashMap<DepType, Vec<Dependency<'a>>>>,
102}
103
104impl<'a> Package<'a> {
105 pub fn new(cache: &'a Cache, ptr: UniquePtr<PkgIterator>) -> Package<'a> {
106 Package {
107 ptr,
108 cache,
109 rdepends_map: OnceCell::new(),
110 }
111 }
112
113 pub fn rdepends(&self) -> &HashMap<DepType, Vec<Dependency<'a>>> {
137 self.rdepends_map.get_or_init(|| {
138 create_depends_map(self.cache, unsafe { self.ptr.rdepends().make_safe() })
139 })
140 }
141
142 pub fn get_version(&self, version_str: &str) -> Option<Version<'a>> {
154 for ver in unsafe { self.ptr.versions().raw_iter() } {
155 if version_str == ver.version() {
156 return Some(Version::new(ver, self.cache));
157 }
158 }
159 None
160 }
161
162 pub fn is_installed(&self) -> bool { unsafe { !self.current_version().end() } }
164
165 pub fn has_versions(&self) -> bool { unsafe { !self.ptr.versions().end() } }
169
170 pub fn has_provides(&self) -> bool { unsafe { !self.ptr.provides().end() } }
172
173 pub fn inst_state(&self) -> PkgInstState { PkgInstState::from(self.ptr.inst_state()) }
175
176 pub fn selected_state(&self) -> PkgSelectedState {
178 PkgSelectedState::from(self.ptr.selected_state())
179 }
180
181 pub fn current_state(&self) -> PkgCurrentState {
183 PkgCurrentState::from(self.ptr.current_state())
184 }
185
186 pub fn installed(&self) -> Option<Version<'a>> {
190 Some(Version::new(
191 unsafe { self.current_version().make_safe() }?,
192 self.cache,
193 ))
194 }
195
196 pub fn candidate(&self) -> Option<Version<'a>> {
200 Some(Version::new(
201 unsafe { self.cache.depcache().candidate_version(self).make_safe()? },
202 self.cache,
203 ))
204 }
205
206 pub fn install_version(&self) -> Option<Version<'a>> {
216 Some(Version::new(
218 unsafe { self.cache.depcache().install_version(self).make_safe()? },
219 self.cache,
220 ))
221 }
222
223 pub fn versions(&self) -> impl Iterator<Item = Version<'a>> {
226 unsafe { self.ptr.versions() }
227 .raw_iter()
228 .map(|ver| Version::new(ver, self.cache))
229 }
230
231 pub fn provides(&self) -> impl Iterator<Item = Provider<'a>> {
233 unsafe { self.ptr.provides() }
234 .raw_iter()
235 .map(|p| Provider::new(p, self.cache))
236 }
237
238 pub fn is_upgradable(&self) -> bool {
240 self.is_installed() && self.cache.depcache().is_upgradable(self)
241 }
242
243 pub fn phasing_applied(&self) -> bool { self.cache.depcache().phasing_applied(self) }
246
247 pub fn is_auto_installed(&self) -> bool { self.cache.depcache().is_auto_installed(self) }
249
250 pub fn is_auto_removable(&self) -> bool {
252 (self.is_installed() || self.marked_install()) && self.cache.depcache().is_garbage(self)
253 }
254
255 pub fn marked(&self) -> Marked {
256 if self.marked_held() {
260 return Marked::Held;
261 }
262
263 if self.marked_keep() {
264 return Marked::Keep;
265 }
266
267 if self.marked_reinstall() {
270 return Marked::ReInstall;
271 }
272
273 if self.marked_upgrade() && self.is_installed() {
274 return Marked::Upgrade;
275 }
276
277 if self.marked_new_install() {
278 return Marked::NewInstall;
279 }
280
281 if self.marked_downgrade() {
282 return Marked::Downgrade;
283 }
284
285 if self.marked_install() {
286 return Marked::Install;
287 }
288
289 if self.marked_purge() {
291 return Marked::Purge;
292 }
293
294 if self.marked_delete() {
295 return Marked::Remove;
296 }
297
298 Marked::None
299 }
300
301 pub fn is_now_broken(&self) -> bool { self.cache.depcache().is_now_broken(self) }
303
304 pub fn is_inst_broken(&self) -> bool { self.cache.depcache().is_inst_broken(self) }
306
307 pub fn marked_new_install(&self) -> bool { self.cache.depcache().marked_new_install(self) }
309
310 pub fn marked_install(&self) -> bool { self.cache.depcache().marked_install(self) }
312
313 pub fn marked_upgrade(&self) -> bool { self.cache.depcache().marked_upgrade(self) }
315
316 pub fn marked_purge(&self) -> bool { self.cache.depcache().marked_purge(self) }
318
319 pub fn marked_delete(&self) -> bool { self.cache.depcache().marked_delete(self) }
321
322 pub fn marked_held(&self) -> bool { self.cache.depcache().marked_held(self) }
324
325 pub fn marked_keep(&self) -> bool { self.cache.depcache().marked_keep(self) }
327
328 pub fn marked_downgrade(&self) -> bool { self.cache.depcache().marked_downgrade(self) }
330
331 pub fn marked_reinstall(&self) -> bool { self.cache.depcache().marked_reinstall(self) }
333
334 pub fn mark_auto(&self, mark_auto: bool) -> bool {
340 self.cache.depcache().mark_auto(self, mark_auto);
341 true
343 }
344
345 pub fn mark_keep(&self) -> bool { self.cache.depcache().mark_keep(self) }
359
360 pub fn mark_delete(&self, purge: bool) -> bool {
370 self.cache.depcache().mark_delete(self, purge)
371 }
372
373 pub fn mark_install(&self, auto_inst: bool, from_user: bool) -> bool {
392 self.cache
393 .depcache()
394 .mark_install(self, auto_inst, from_user)
395 }
396
397 pub fn mark_reinstall(&self, reinstall: bool) -> bool {
407 self.cache.depcache().mark_reinstall(self, reinstall);
408 true
410 }
411
412 pub fn protect(&self) { self.cache.resolver().protect(self) }
415
416 pub fn changelog_uri(&self) -> Option<String> {
417 let cand = self.candidate()?;
418
419 let src_pkg = cand.source_name();
420 let mut src_ver = cand.source_version().to_string();
421 let mut section = cand.section().ok()?.to_string();
422
423 if let Ok(src_records) = self.cache.source_records() {
424 while let Some(record) = src_records.lookup(src_pkg.to_string(), false) {
425 let record_version = record.version();
426
427 match util::cmp_versions(&record_version, &src_ver) {
428 Ordering::Equal | Ordering::Greater => {
429 src_ver = record_version;
430 section = record.section();
431 break;
432 },
433 _ => {},
434 }
435 }
436 }
437
438 let base_url = match cand.package_files().next()?.origin()? {
439 "Ubuntu" => "http://changelogs.ubuntu.com/changelogs/pool",
440 "Debian" => "http://packages.debian.org/changelogs/pool",
441 _ => return None,
442 };
443
444 let prefix = if src_pkg.starts_with("lib") {
445 format!("lib{}", src_pkg.chars().nth(3)?)
446 } else {
447 src_pkg.chars().next()?.to_string()
448 };
449
450 Some(format!(
451 "{base_url}/{}/{prefix}/{src_pkg}/{src_pkg}_{}/changelog",
452 if section.contains('/') { section.split('/').nth(0)? } else { "main" },
453 if let Some(split) = src_ver.split_once(':') { split.1 } else { &src_ver }
455 ))
456 }
457}
458
459impl Clone for Package<'_> {
460 fn clone(&self) -> Self {
461 Self {
462 ptr: unsafe { self.ptr.unique() },
463 cache: self.cache,
464 rdepends_map: self.rdepends_map.clone(),
465 }
466 }
467}
468
469impl fmt::Display for Package<'_> {
470 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
471 write!(f, "{}", self.name())?;
472 Ok(())
473 }
474}
475
476impl fmt::Debug for Package<'_> {
477 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
478 let versions: Vec<Version> = self.versions().collect();
479 f.debug_struct("Package")
480 .field("name", &self.name())
481 .field("arch", &self.arch())
482 .field("virtual", &versions.is_empty())
483 .field("versions", &versions)
484 .finish_non_exhaustive()
485 }
486}
487
488#[cxx::bridge]
489pub(crate) mod raw {
490 unsafe extern "C++" {
491 include!("rust-apt/apt-pkg-c/package.h");
492
493 type PkgIterator;
494 type VerIterator = crate::iterators::VerIterator;
495 type PrvIterator = crate::iterators::PrvIterator;
496 type DepIterator = crate::iterators::DepIterator;
497
498 pub fn name(self: &PkgIterator) -> &str;
500
501 pub fn arch(self: &PkgIterator) -> &str;
503
504 pub fn fullname(self: &PkgIterator, pretty: bool) -> String;
508
509 pub fn current_state(self: &PkgIterator) -> u8;
511
512 pub fn inst_state(self: &PkgIterator) -> u8;
514
515 pub fn selected_state(self: &PkgIterator) -> u8;
517
518 pub fn is_essential(self: &PkgIterator) -> bool;
520
521 unsafe fn current_version(self: &PkgIterator) -> UniquePtr<VerIterator>;
532
533 unsafe fn versions(self: &PkgIterator) -> UniquePtr<VerIterator>;
544
545 unsafe fn provides(self: &PkgIterator) -> UniquePtr<PrvIterator>;
556
557 unsafe fn rdepends(self: &PkgIterator) -> UniquePtr<DepIterator>;
568
569 #[cxx_name = "Index"]
570 pub fn index(self: &PkgIterator) -> u64;
571 unsafe fn unique(self: &PkgIterator) -> UniquePtr<PkgIterator>;
582 pub fn raw_next(self: Pin<&mut PkgIterator>);
583 pub fn end(self: &PkgIterator) -> bool;
584 }
585}