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 is_auto_installed(&self) -> bool { self.cache.depcache().is_auto_installed(self) }
245
246 pub fn is_auto_removable(&self) -> bool {
248 (self.is_installed() || self.marked_install()) && self.cache.depcache().is_garbage(self)
249 }
250
251 pub fn marked(&self) -> Marked {
252 if self.marked_held() {
256 return Marked::Held;
257 }
258
259 if self.marked_keep() {
260 return Marked::Keep;
261 }
262
263 if self.marked_reinstall() {
266 return Marked::ReInstall;
267 }
268
269 if self.marked_upgrade() && self.is_installed() {
270 return Marked::Upgrade;
271 }
272
273 if self.marked_new_install() {
274 return Marked::NewInstall;
275 }
276
277 if self.marked_downgrade() {
278 return Marked::Downgrade;
279 }
280
281 if self.marked_install() {
282 return Marked::Install;
283 }
284
285 if self.marked_purge() {
287 return Marked::Purge;
288 }
289
290 if self.marked_delete() {
291 return Marked::Remove;
292 }
293
294 Marked::None
295 }
296
297 pub fn is_now_broken(&self) -> bool { self.cache.depcache().is_now_broken(self) }
299
300 pub fn is_inst_broken(&self) -> bool { self.cache.depcache().is_inst_broken(self) }
302
303 pub fn marked_new_install(&self) -> bool { self.cache.depcache().marked_new_install(self) }
305
306 pub fn marked_install(&self) -> bool { self.cache.depcache().marked_install(self) }
308
309 pub fn marked_upgrade(&self) -> bool { self.cache.depcache().marked_upgrade(self) }
311
312 pub fn marked_purge(&self) -> bool { self.cache.depcache().marked_purge(self) }
314
315 pub fn marked_delete(&self) -> bool { self.cache.depcache().marked_delete(self) }
317
318 pub fn marked_held(&self) -> bool { self.cache.depcache().marked_held(self) }
320
321 pub fn marked_keep(&self) -> bool { self.cache.depcache().marked_keep(self) }
323
324 pub fn marked_downgrade(&self) -> bool { self.cache.depcache().marked_downgrade(self) }
326
327 pub fn marked_reinstall(&self) -> bool { self.cache.depcache().marked_reinstall(self) }
329
330 pub fn mark_auto(&self, mark_auto: bool) -> bool {
336 self.cache.depcache().mark_auto(self, mark_auto);
337 true
339 }
340
341 pub fn mark_keep(&self) -> bool { self.cache.depcache().mark_keep(self) }
355
356 pub fn mark_delete(&self, purge: bool) -> bool {
366 self.cache.depcache().mark_delete(self, purge)
367 }
368
369 pub fn mark_install(&self, auto_inst: bool, from_user: bool) -> bool {
388 self.cache
389 .depcache()
390 .mark_install(self, auto_inst, from_user)
391 }
392
393 pub fn mark_reinstall(&self, reinstall: bool) -> bool {
403 self.cache.depcache().mark_reinstall(self, reinstall);
404 true
406 }
407
408 pub fn protect(&self) { self.cache.resolver().protect(self) }
411
412 pub fn changelog_uri(&self) -> Option<String> {
413 let cand = self.candidate()?;
414
415 let src_pkg = cand.source_name();
416 let mut src_ver = cand.source_version().to_string();
417 let mut section = cand.section().ok()?.to_string();
418
419 if let Ok(src_records) = self.cache.source_records() {
420 while let Some(record) = src_records.lookup(src_pkg.to_string(), false) {
421 let record_version = record.version();
422
423 match util::cmp_versions(&record_version, &src_ver) {
424 Ordering::Equal | Ordering::Greater => {
425 src_ver = record_version;
426 section = record.section();
427 break;
428 },
429 _ => {},
430 }
431 }
432 }
433
434 let base_url = match cand.package_files().next()?.origin()? {
435 "Ubuntu" => "http://changelogs.ubuntu.com/changelogs/pool",
436 "Debian" => "http://packages.debian.org/changelogs/pool",
437 _ => return None,
438 };
439
440 let prefix = if src_pkg.starts_with("lib") {
441 format!("lib{}", src_pkg.chars().nth(3)?)
442 } else {
443 src_pkg.chars().next()?.to_string()
444 };
445
446 Some(format!(
447 "{base_url}/{}/{prefix}/{src_pkg}/{src_pkg}_{}/changelog",
448 if section.contains('/') { section.split('/').nth(0)? } else { "main" },
449 if let Some(split) = src_ver.split_once(':') { split.1 } else { &src_ver }
451 ))
452 }
453}
454
455impl Clone for Package<'_> {
456 fn clone(&self) -> Self {
457 Self {
458 ptr: unsafe { self.ptr.unique() },
459 cache: self.cache,
460 rdepends_map: self.rdepends_map.clone(),
461 }
462 }
463}
464
465impl fmt::Display for Package<'_> {
466 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
467 write!(f, "{}", self.name())?;
468 Ok(())
469 }
470}
471
472impl fmt::Debug for Package<'_> {
473 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
474 let versions: Vec<Version> = self.versions().collect();
475 f.debug_struct("Package")
476 .field("name", &self.name())
477 .field("arch", &self.arch())
478 .field("virtual", &versions.is_empty())
479 .field("versions", &versions)
480 .finish_non_exhaustive()
481 }
482}
483
484#[cxx::bridge]
485pub(crate) mod raw {
486 unsafe extern "C++" {
487 include!("rust-apt/apt-pkg-c/package.h");
488
489 type PkgIterator;
490 type VerIterator = crate::iterators::VerIterator;
491 type PrvIterator = crate::iterators::PrvIterator;
492 type DepIterator = crate::iterators::DepIterator;
493
494 pub fn name(self: &PkgIterator) -> &str;
496
497 pub fn arch(self: &PkgIterator) -> &str;
499
500 pub fn fullname(self: &PkgIterator, pretty: bool) -> String;
504
505 pub fn current_state(self: &PkgIterator) -> u8;
507
508 pub fn inst_state(self: &PkgIterator) -> u8;
510
511 pub fn selected_state(self: &PkgIterator) -> u8;
513
514 pub fn is_essential(self: &PkgIterator) -> bool;
516
517 unsafe fn current_version(self: &PkgIterator) -> UniquePtr<VerIterator>;
528
529 unsafe fn versions(self: &PkgIterator) -> UniquePtr<VerIterator>;
540
541 unsafe fn provides(self: &PkgIterator) -> UniquePtr<PrvIterator>;
552
553 unsafe fn rdepends(self: &PkgIterator) -> UniquePtr<DepIterator>;
564
565 #[cxx_name = "Index"]
566 pub fn index(self: &PkgIterator) -> u64;
567 unsafe fn unique(self: &PkgIterator) -> UniquePtr<PkgIterator>;
578 pub fn raw_next(self: Pin<&mut PkgIterator>);
579 pub fn end(self: &PkgIterator) -> bool;
580 }
581}