alpm/
alpm.rs

1use crate::utils::*;
2use crate::{Callbacks, Error, Result};
3
4use std::ffi::{c_void, CString};
5use std::fmt;
6use std::os::raw::c_int;
7use std::ptr::NonNull;
8
9use alpm_sys::*;
10use bitflags::bitflags;
11
12extern "C" {
13    pub(crate) fn free(ptr: *mut c_void);
14}
15
16#[allow(dead_code)]
17pub struct Alpm {
18    handle: NonNull<alpm_handle_t>,
19    pub(crate) cbs: Callbacks,
20}
21
22impl std::fmt::Debug for Alpm {
23    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24        f.debug_struct("Alpm").finish()
25    }
26}
27
28impl Drop for Alpm {
29    fn drop(&mut self) {
30        unsafe { alpm_release(self.as_ptr()) };
31    }
32}
33
34#[derive(Debug, Eq, PartialEq, Copy, Clone, Ord, PartialOrd, Hash)]
35pub struct ReleaseError;
36
37impl fmt::Display for ReleaseError {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        f.write_str("failed to release alpm")
40    }
41}
42
43impl std::error::Error for ReleaseError {}
44
45impl Alpm {
46    #[doc(alias("alpm_initialize", "initialize"))]
47    pub fn new<S: Into<Vec<u8>>>(root: S, db_path: S) -> Result<Alpm> {
48        let mut err = alpm_errno_t::ALPM_ERR_OK;
49        let root = CString::new(root).unwrap();
50        let db_path = CString::new(db_path).unwrap();
51
52        let handle = unsafe { alpm_initialize(root.as_ptr(), db_path.as_ptr(), &mut err) };
53
54        match NonNull::new(handle) {
55            None => unsafe { Err(Error::new(err)) },
56            Some(handle) => Ok(Alpm {
57                handle,
58                cbs: Callbacks::default(),
59            }),
60        }
61    }
62
63    pub fn new2(root: &str, db_path: &str) -> Result<Alpm> {
64        Alpm::new(root, db_path)
65    }
66
67    pub fn release(self) -> std::result::Result<(), ReleaseError> {
68        if unsafe { alpm_release(self.as_ptr()) } == 0 {
69            std::mem::forget(self);
70            Ok(())
71        } else {
72            std::mem::forget(self);
73            Err(ReleaseError)
74        }
75    }
76
77    pub(crate) fn as_ptr(&self) -> *mut alpm_handle_t {
78        self.handle.as_ptr()
79    }
80
81    pub(crate) fn check_ret(&self, int: c_int) -> Result<()> {
82        if int != 0 {
83            Err(self.last_error())
84        } else {
85            Ok(())
86        }
87    }
88
89    pub(crate) fn check_null<T>(&self, ptr: *const T) -> Result<()> {
90        if ptr.is_null() {
91            Err(self.last_error())
92        } else {
93            Ok(())
94        }
95    }
96}
97
98pub fn version() -> &'static str {
99    unsafe { from_cstr(alpm_version()) }
100}
101
102bitflags! {
103    #[derive(Debug, PartialEq, Eq)]
104    pub struct Capabilities: u32 {
105        const NLS = alpm_caps::ALPM_CAPABILITY_NLS;
106        const DOWNLOADER = alpm_caps::ALPM_CAPABILITY_DOWNLOADER;
107        const SIGNATURES = alpm_caps::ALPM_CAPABILITY_SIGNATURES;
108    }
109}
110
111impl Default for Capabilities {
112    fn default() -> Capabilities {
113        Capabilities::new()
114    }
115}
116
117impl Capabilities {
118    pub fn new() -> Capabilities {
119        Capabilities::from_bits(unsafe { alpm_capabilities() as u32 }).unwrap()
120    }
121
122    pub fn nls(self) -> bool {
123        self.intersects(Capabilities::NLS)
124    }
125
126    pub fn downloader(self) -> bool {
127        self.intersects(Capabilities::DOWNLOADER)
128    }
129
130    pub fn signatures(self) -> bool {
131        self.intersects(Capabilities::SIGNATURES)
132    }
133}
134
135#[cfg(test)]
136mod tests {
137    use super::*;
138    use crate::SigLevel;
139
140    #[test]
141    fn test_lifetime() {
142        let handle = Alpm::new("/", "tests/db").unwrap();
143        let db = handle.register_syncdb("core", SigLevel::NONE).unwrap();
144        let pkg = db.pkg("linux").unwrap();
145        let name = pkg.name();
146        assert_eq!(name, "linux");
147    }
148
149    #[test]
150    fn test_list_lifetime() {
151        let handle = Alpm::new("/", "tests/db").unwrap();
152        let db = handle.register_syncdb("core", SigLevel::NONE).unwrap();
153        let pkgs = db.pkgs();
154        assert!(pkgs.len() > 10);
155    }
156}