alpm_ll/
package.rs

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}