1use crate::{utils::*, LIBRARY, Library};
2use crate::{
3 Alpm, AlpmList, AlpmListMut, Backup, ChangeLog, Db, Dep, FileList, PackageFrom, PackageReason,
4 PackageValidation, Result, Signature, Ver,
5};
6
7#[cfg(feature = "mtree")]
8use crate::MTree;
9
10use std::mem::transmute;
11use std::ops::Deref;
12use std::ptr::NonNull;
13use std::{fmt, ptr};
14
15use alpm_sys_ll::*;
16
17pub trait AsPkg {
18 fn as_pkg(&self) -> Pkg;
19}
20
21impl<'h> AsPkg for Package<'h> {
22 fn as_pkg(&self) -> Pkg {
23 self.pkg
24 }
25}
26
27impl<'h> AsPkg for Pkg<'h> {
28 fn as_pkg(&self) -> Pkg {
29 *self
30 }
31}
32
33#[derive(Copy, Clone)]
34pub struct Package<'h> {
35 pub(crate) pkg: Pkg<'h>,
36}
37
38#[derive(Copy, Clone)]
39pub struct Pkg<'h> {
40 pub(crate) handle: &'h Alpm,
41 pkg: NonNull<alpm_pkg_t>,
42}
43
44impl<'h> fmt::Debug for Pkg<'h> {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 f.debug_struct("Pkg")
47 .field("name", &self.name())
48 .field("version", &self.version())
49 .finish()
50 }
51}
52
53impl<'h> fmt::Debug for Package<'h> {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 f.debug_struct("Package")
56 .field("name", &self.name())
57 .field("version", &self.version())
58 .finish()
59 }
60}
61
62impl<'h> Deref for Package<'h> {
63 type Target = Pkg<'h>;
64 fn deref(&self) -> &Self::Target {
65 &self.pkg
66 }
67}
68
69impl<'h> Package<'h> {
70 pub(crate) unsafe fn new(handle: &Alpm, pkg: *mut alpm_pkg_t) -> Package {
71 Package {
72 pkg: Pkg::new(handle, pkg),
73 }
74 }
75}
76
77impl<'h> Pkg<'h> {
78 pub(crate) unsafe fn new(handle: &Alpm, pkg: *mut alpm_pkg_t) -> Pkg {
79 Pkg {
80 handle,
81 pkg: NonNull::new_unchecked(pkg),
82 }
83 }
84
85 pub(crate) fn as_ptr(self) -> *mut alpm_pkg_t {
86 self.pkg.as_ptr()
87 }
88
89 pub fn name(&self) -> &'h str {
90 let name = unsafe { LIBRARY.force_load().alpm_pkg_get_name(self.as_ptr()) };
91 unsafe { from_cstr(name) }
92 }
93
94 pub fn check_md5sum(&self) -> Result<()> {
95 self.handle
96 .check_ret(unsafe { LIBRARY.force_load().alpm_pkg_checkmd5sum(self.as_ptr()) })
97 }
98
99 pub fn should_ignore(&self) -> bool {
100 let ret = unsafe { LIBRARY.force_load().alpm_pkg_should_ignore(self.handle.as_ptr(), self.as_ptr()) };
101 ret != 0
102 }
103
104 pub fn filename(&self) -> &'h str {
105 let name = unsafe { LIBRARY.force_load().alpm_pkg_get_filename(self.as_ptr()) };
106 unsafe { from_cstr_optional2(name) }
107 }
108
109 pub fn base(&self) -> Option<&'h str> {
110 let base = unsafe { LIBRARY.force_load().alpm_pkg_get_base(self.as_ptr()) };
111 unsafe { from_cstr_optional(base) }
112 }
113
114 pub fn version(&self) -> &'h Ver {
115 let version = unsafe { LIBRARY.force_load().alpm_pkg_get_version(self.as_ptr()) };
116 unsafe { Ver::from_ptr(version) }
117 }
118
119 pub fn origin(&self) -> PackageFrom {
120 let origin = unsafe { LIBRARY.force_load().alpm_pkg_get_origin(self.as_ptr()) };
121 unsafe { transmute::<_alpm_pkgfrom_t, PackageFrom>(origin) }
122 }
123
124 pub fn desc(&self) -> Option<&'h str> {
125 let desc = unsafe { LIBRARY.force_load().alpm_pkg_get_desc(self.as_ptr()) };
126 unsafe { from_cstr_optional(desc) }
127 }
128
129 pub fn url(&self) -> Option<&'h str> {
130 let url = unsafe { LIBRARY.force_load().alpm_pkg_get_url(self.as_ptr()) };
131 unsafe { from_cstr_optional(url) }
132 }
133
134 pub fn build_date(&self) -> i64 {
135 let date = unsafe { LIBRARY.force_load().alpm_pkg_get_builddate(self.as_ptr()) };
136 date as i64
137 }
138
139 pub fn install_date(&self) -> Option<i64> {
140 let date = unsafe { LIBRARY.force_load().alpm_pkg_get_installdate(self.as_ptr()) };
141 if date == 0 {
142 None
143 } else {
144 Some(date as i64)
145 }
146 }
147
148 pub fn packager(&self) -> Option<&'h str> {
149 let packager = unsafe { LIBRARY.force_load().alpm_pkg_get_packager(self.as_ptr()) };
150 unsafe { from_cstr_optional(packager) }
151 }
152
153 pub fn md5sum(&self) -> Option<&'h str> {
154 let md5sum = unsafe { LIBRARY.force_load().alpm_pkg_get_md5sum(self.as_ptr()) };
155 unsafe { from_cstr_optional(md5sum) }
156 }
157
158 pub fn sha256sum(&self) -> Option<&'h str> {
159 let sha256sum = unsafe { LIBRARY.force_load().alpm_pkg_get_sha256sum(self.as_ptr()) };
160 unsafe { from_cstr_optional(sha256sum) }
161 }
162
163 pub fn arch(&self) -> Option<&'h str> {
164 let arch = unsafe { LIBRARY.force_load().alpm_pkg_get_arch(self.as_ptr()) };
165 unsafe { from_cstr_optional(arch) }
166 }
167
168 pub fn size(&self) -> i64 {
169 let size = unsafe { LIBRARY.force_load().alpm_pkg_get_size(self.as_ptr()) };
170 size as i64
171 }
172
173 pub fn isize(&self) -> i64 {
174 let size = unsafe { LIBRARY.force_load().alpm_pkg_get_isize(self.as_ptr()) };
175 size as i64
176 }
177
178 pub fn reason(&self) -> PackageReason {
179 let reason = unsafe { LIBRARY.force_load().alpm_pkg_get_reason(self.as_ptr()) };
180 unsafe { transmute::<_alpm_pkgreason_t, PackageReason>(reason) }
181 }
182
183 pub fn validation(&self) -> PackageValidation {
184 let validation = unsafe { LIBRARY.force_load().alpm_pkg_get_validation(self.as_ptr()) };
185 PackageValidation::from_bits(validation as u32).unwrap()
186 }
187
188 pub fn licenses(&self) -> AlpmList<'h, &'h str> {
189 let list = unsafe { LIBRARY.force_load().alpm_pkg_get_licenses(self.as_ptr()) };
190 unsafe { AlpmList::from_parts(self.handle, list) }
191 }
192
193 pub fn groups(&self) -> AlpmList<'h, &'h str> {
194 let list = unsafe { LIBRARY.force_load().alpm_pkg_get_groups(self.as_ptr()) };
195 unsafe { AlpmList::from_parts(self.handle, list) }
196 }
197
198 pub fn depends(&self) -> AlpmList<'h, Dep<'h>> {
199 let list = unsafe { LIBRARY.force_load().alpm_pkg_get_depends(self.as_ptr()) };
200 unsafe { AlpmList::from_parts(self.handle, list) }
201 }
202
203 pub fn optdepends(&self) -> AlpmList<'h, Dep<'h>> {
204 let list = unsafe { LIBRARY.force_load().alpm_pkg_get_optdepends(self.as_ptr()) };
205 unsafe { AlpmList::from_parts(self.handle, list) }
206 }
207
208 pub fn checkdepends(&self) -> AlpmList<'h, Dep<'h>> {
209 let list = unsafe { LIBRARY.force_load().alpm_pkg_get_checkdepends(self.as_ptr()) };
210 unsafe { AlpmList::from_parts(self.handle, list) }
211 }
212
213 pub fn makedepends(&self) -> AlpmList<'h, Dep<'h>> {
214 let list = unsafe { LIBRARY.force_load().alpm_pkg_get_makedepends(self.as_ptr()) };
215 unsafe { AlpmList::from_parts(self.handle, list) }
216 }
217
218 pub fn conflicts(&self) -> AlpmList<'h, Dep<'h>> {
219 let list = unsafe { LIBRARY.force_load().alpm_pkg_get_conflicts(self.as_ptr()) };
220 unsafe { AlpmList::from_parts(self.handle, list) }
221 }
222
223 pub fn provides(&self) -> AlpmList<'h, Dep<'h>> {
224 let list = unsafe { LIBRARY.force_load().alpm_pkg_get_provides(self.as_ptr()) };
225 unsafe { AlpmList::from_parts(self.handle, list) }
226 }
227
228 pub fn replaces(&self) -> AlpmList<'h, Dep<'h>> {
229 let list = unsafe { LIBRARY.force_load().alpm_pkg_get_replaces(self.as_ptr()) };
230 unsafe { AlpmList::from_parts(self.handle, list) }
231 }
232
233 pub fn files(&self) -> FileList {
234 let files = unsafe { *(LIBRARY.force_load().alpm_pkg_get_files(self.as_ptr())) };
235 unsafe { FileList::new(files) }
236 }
237
238 pub fn backup(&self) -> AlpmList<'h, Backup> {
239 let list = unsafe { LIBRARY.force_load().alpm_pkg_get_backup(self.as_ptr()) };
240 unsafe { AlpmList::from_parts(self.handle, list) }
241 }
242
243 pub fn db(&self) -> Option<Db<'h>> {
244 let db = unsafe { LIBRARY.force_load().alpm_pkg_get_db(self.as_ptr()) };
245 self.handle.check_null(db).ok()?;
246 unsafe { Some(Db::new(self.handle, db)) }
247 }
248
249 pub fn changelog(&self) -> Result<ChangeLog> {
250 let changelog = unsafe { LIBRARY.force_load().alpm_pkg_changelog_open(self.as_ptr()) };
251 self.handle.check_null(changelog)?;
252 let changelog = unsafe { ChangeLog::new(*self, changelog) };
253 Ok(changelog)
254 }
255
256 #[cfg(feature = "mtree")]
257 pub fn mtree(&self) -> Result<MTree> {
258 let archive = unsafe { alpm_pkg_mtree_open(self.as_ptr()) };
259 self.handle.check_null(archive)?;
260
261 let archive = unsafe { MTree::new(*self, archive) };
262
263 Ok(archive)
264 }
265
266 pub fn required_by(&self) -> AlpmListMut<'h, String> {
267 let list = unsafe { LIBRARY.force_load().alpm_pkg_compute_requiredby(self.as_ptr()) };
268 unsafe { AlpmListMut::from_parts(self.handle, list) }
269 }
270
271 pub fn optional_for(&self) -> AlpmListMut<'h, String> {
272 let list = unsafe { LIBRARY.force_load().alpm_pkg_compute_optionalfor(self.as_ptr()) };
273 unsafe { AlpmListMut::from_parts(self.handle, list) }
274 }
275
276 pub fn base64_sig(&self) -> Option<&'h str> {
277 let base64_sig = unsafe { LIBRARY.force_load().alpm_pkg_get_base64_sig(self.as_ptr()) };
278 unsafe { from_cstr_optional(base64_sig) }
279 }
280
281 pub fn has_scriptlet(&self) -> bool {
282 unsafe { LIBRARY.force_load().alpm_pkg_has_scriptlet(self.as_ptr()) != 0 }
283 }
284
285 pub fn sig(&self) -> Result<Signature> {
286 let mut sig = ptr::null_mut();
287 let mut len = 0;
288 let ret = unsafe { LIBRARY.force_load().alpm_pkg_get_sig(self.as_ptr(), &mut sig, &mut len) };
289 self.handle.check_ret(ret)?;
290 let sig = unsafe { Signature::new(sig, len) };
291 Ok(sig)
292 }
293}
294
295#[cfg(test)]
296mod tests {
297 use super::*;
298 use crate::SigLevel;
299 use std::io::Read;
300 use std::mem::size_of;
301
302 #[test]
303 fn test_depends() {
304 let handle = Alpm::new("/", "tests/db").unwrap();
305 let db = handle.register_syncdb("core", SigLevel::NONE).unwrap();
306 let pkg = db.pkg("linux").unwrap();
307 let depends = pkg
308 .depends()
309 .iter()
310 .map(|d| d.to_string())
311 .collect::<Vec<_>>();
312 assert_eq!(
313 &depends,
314 &["coreutils", "linux-firmware", "kmod", "mkinitcpio"]
315 )
316 }
317
318 #[test]
319 fn test_files() {
320 let handle = Alpm::new("/", "tests/db").unwrap();
321 let db = handle.localdb();
322 let pkg = db.pkg("filesystem").unwrap();
323 let files = pkg.files();
324
325 for file in files.files() {
326 println!("{}", file.name());
327 }
328
329 assert!(files.contains("etc/").unwrap().is_some());
330 assert_eq!(pkg.filename(), "");
331 }
332
333 #[test]
334 fn test_files_null() {
335 let handle = Alpm::new("/", "tests/db").unwrap();
336 let db = handle.register_syncdb("core", SigLevel::NONE).unwrap();
337 let pkg = db.pkg("filesystem").unwrap();
338 let files = pkg.files();
339
340 assert_eq!(files.files().len(), 0);
341 }
342
343 #[test]
344 fn test_groups() {
345 let handle = Alpm::new("/", "tests/db").unwrap();
346 let db = handle.register_syncdb("core", SigLevel::NONE).unwrap();
347 let pkg = db.pkg("linux").unwrap();
348 let groups = pkg.groups();
349
350 assert_eq!(&groups.iter().collect::<Vec<_>>(), &["base"],)
351 }
352
353 #[test]
354 fn test_backup() {
355 let handle = Alpm::new("/", "tests/db").unwrap();
356 let db = handle.localdb();
357 let pkg = db.pkg("pacman").unwrap();
358 let backup = pkg.backup();
359 assert_eq!(backup.first().unwrap().name(), "etc/pacman.conf");
360 }
361
362 #[test]
363 fn test_rquired_by() {
364 let handle = Alpm::new("/", "tests/db").unwrap();
365 let db = handle.register_syncdb("extra", SigLevel::NONE).unwrap();
366 let pkg = db.pkg("ostree").unwrap();
367 let optional = pkg
368 .required_by()
369 .iter()
370 .map(|d| d.to_string())
371 .collect::<Vec<_>>();
372 assert_eq!(&optional, &["flatpak"]);
373 }
374
375 #[test]
376 fn test_changelog() {
377 let handle = Alpm::new("/", "tests/db").unwrap();
378 let db = handle.localdb();
379 let pkg = db.pkg("vifm").unwrap();
380 let mut s = String::new();
381 let mut changelog = pkg.changelog().unwrap();
382 changelog.read_to_string(&mut s).unwrap();
383 assert!(s.contains("2010-02-15 Jaroslav Lichtblau <svetlemodry@archlinux.org>"));
384 }
385
386 #[test]
387 fn test_pkg_optimization() {
388 assert!(size_of::<Pkg>() == size_of::<Option<Pkg>>());
389 }
390}