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}