alpm/
db.rs

1use crate::utils::*;
2use crate::{
3    Alpm, AlpmList, AlpmListMut, AsAlpmList, Error, Group, Package, Result, SigLevel, Usage,
4};
5
6use std::cell::UnsafeCell;
7use std::ffi::CString;
8use std::fmt;
9use std::ops::Deref;
10use std::os::raw::c_int;
11
12use alpm_sys::*;
13
14#[doc(alias("repo", "repository"))]
15#[repr(transparent)]
16pub struct Db {
17    db: UnsafeCell<alpm_db_t>,
18}
19
20impl fmt::Debug for Db {
21    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22        f.debug_struct("Db").field("name", &self.name()).finish()
23    }
24}
25
26pub struct DbMut<'h> {
27    pub(crate) inner: &'h Db,
28}
29
30impl fmt::Debug for DbMut<'_> {
31    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32        fmt::Debug::fmt(&self.inner, f)
33    }
34}
35
36impl Deref for DbMut<'_> {
37    type Target = Db;
38
39    fn deref(&self) -> &Db {
40        self.inner
41    }
42}
43
44impl Alpm {
45    pub fn register_syncdb<S: Into<Vec<u8>>>(&self, name: S, sig_level: SigLevel) -> Result<&Db> {
46        let name = CString::new(name).unwrap();
47
48        let db =
49            unsafe { alpm_register_syncdb(self.as_ptr(), name.as_ptr(), sig_level.bits() as i32) };
50
51        self.check_null(db)?;
52        unsafe { Ok(Db::from_ptr(db)) }
53    }
54
55    pub fn register_syncdb_mut<S: Into<Vec<u8>>>(
56        &mut self,
57        name: S,
58        sig_level: SigLevel,
59    ) -> Result<DbMut> {
60        let db = self.register_syncdb(name, sig_level)?;
61        Ok(DbMut { inner: db })
62    }
63
64    pub fn unregister_all_syncdbs(&mut self) -> Result<()> {
65        self.check_ret(unsafe { alpm_unregister_all_syncdbs(self.as_ptr()) })
66    }
67}
68
69impl DbMut<'_> {
70    pub(crate) unsafe fn from_ptr<'a>(db: *mut alpm_db_t) -> DbMut<'a> {
71        DbMut {
72            inner: unsafe { Db::from_ptr(db) },
73        }
74    }
75
76    pub fn unregister(self) {
77        unsafe { alpm_db_unregister(self.as_ptr()) };
78    }
79
80    pub fn add_server<S: Into<Vec<u8>>>(&self, server: S) -> Result<()> {
81        let server = CString::new(server).unwrap();
82        let ret = unsafe { alpm_db_add_server(self.as_ptr(), server.as_ptr()) };
83        self.check_ret(ret)
84    }
85
86    pub fn set_servers<'a, L: AsAlpmList<&'a str>>(&self, list: L) -> Result<()> {
87        list.with(|list| {
88            let ret = unsafe { alpm_db_set_servers(self.as_ptr(), list.as_ptr()) };
89            self.check_ret(ret)
90        })
91    }
92
93    pub fn remove_server<S: Into<Vec<u8>>>(&self, server: S) -> Result<()> {
94        let server = CString::new(server).unwrap();
95        let ret = unsafe { alpm_db_remove_server(self.as_ptr(), server.as_ptr()) };
96        self.check_ret(ret)
97    }
98}
99
100impl Db {
101    pub(crate) unsafe fn from_ptr<'a>(db: *mut alpm_db_t) -> &'a Db {
102        unsafe { &*(db as *mut Db) }
103    }
104
105    pub(crate) fn handle_ptr(&self) -> *mut alpm_handle_t {
106        unsafe { alpm_db_get_handle(self.as_ptr()) }
107    }
108
109    pub(crate) fn last_error(&self) -> Error {
110        unsafe { Error::new(alpm_errno(alpm_db_get_handle(self.as_ptr()))) }
111    }
112
113    pub(crate) fn check_ret(&self, int: c_int) -> Result<()> {
114        if int != 0 {
115            Err(self.last_error())
116        } else {
117            Ok(())
118        }
119    }
120
121    pub(crate) fn check_null<T>(&self, ptr: *const T) -> Result<()> {
122        if ptr.is_null() {
123            Err(self.last_error())
124        } else {
125            Ok(())
126        }
127    }
128
129    pub fn as_ptr(&self) -> *mut alpm_db_t {
130        self.db.get()
131    }
132
133    pub fn name(&self) -> &str {
134        let name = unsafe { alpm_db_get_name(self.as_ptr()) };
135        unsafe { from_cstr(name) }
136    }
137
138    pub fn servers(&self) -> AlpmList<&str> {
139        let list = unsafe { alpm_db_get_servers(self.as_ptr()) };
140        unsafe { AlpmList::from_ptr(list) }
141    }
142
143    pub fn pkg<S: Into<Vec<u8>>>(&self, name: S) -> Result<&Package> {
144        let name = CString::new(name).unwrap();
145        let pkg = unsafe { alpm_db_get_pkg(self.as_ptr(), name.as_ptr()) };
146        self.check_null(pkg)?;
147        unsafe { Ok(Package::from_ptr(pkg)) }
148    }
149
150    #[doc(alias = "pkgcache")]
151    pub fn pkgs(&self) -> AlpmList<&Package> {
152        let pkgs = unsafe { alpm_db_get_pkgcache(self.as_ptr()) };
153        unsafe { AlpmList::from_ptr(pkgs) }
154    }
155
156    pub fn group<S: Into<Vec<u8>>>(&self, name: S) -> Result<&Group> {
157        let name = CString::new(name).unwrap();
158        let group = unsafe { alpm_db_get_group(self.as_ptr(), name.as_ptr()) };
159        self.check_null(group)?;
160        unsafe { Ok(Group::from_ptr(group)) }
161    }
162
163    pub fn set_usage(&self, usage: Usage) -> Result<()> {
164        let ret = unsafe { alpm_db_set_usage(self.as_ptr(), usage.bits() as i32) };
165        self.check_ret(ret)
166    }
167
168    pub fn search<'a, L>(&'a self, list: L) -> Result<AlpmListMut<&'a Package>>
169    where
170        L: AsAlpmList<&'a str>,
171    {
172        list.with(|list| {
173            let mut ret = std::ptr::null_mut();
174            let ok = unsafe { alpm_db_search(self.as_ptr(), list.as_ptr(), &mut ret) };
175            self.check_ret(ok)?;
176            unsafe { Ok(AlpmListMut::from_ptr(ret)) }
177        })
178    }
179
180    #[doc(alias = "groupcache")]
181    pub fn groups(&self) -> Result<AlpmList<&Group>> {
182        let groups = unsafe { alpm_db_get_groupcache(self.as_ptr()) };
183        self.check_null(groups)?;
184        unsafe { Ok(AlpmList::from_ptr(groups)) }
185    }
186
187    pub fn siglevel(&self) -> SigLevel {
188        let siglevel = unsafe { alpm_db_get_siglevel(self.as_ptr()) };
189        SigLevel::from_bits(siglevel as u32).unwrap()
190    }
191
192    pub fn is_valid(&self) -> Result<()> {
193        let ret = unsafe { alpm_db_get_valid(self.as_ptr()) };
194        self.check_ret(ret)
195    }
196
197    pub fn usage(&self) -> Result<Usage> {
198        let mut usage = 0;
199
200        let ret = unsafe { alpm_db_get_usage(self.as_ptr(), &mut usage) };
201        self.check_ret(ret)?;
202
203        let usage = Usage::from_bits(usage as u32).unwrap();
204        Ok(usage)
205    }
206}
207
208#[cfg(test)]
209mod tests {
210    use crate::SigLevel;
211    use crate::{Alpm, AlpmListMut};
212
213    #[test]
214    fn test_register() {
215        let handle = Alpm::new("/", "tests/db").unwrap();
216        let db = handle.register_syncdb("foo", SigLevel::NONE).unwrap();
217
218        assert_eq!(db.name(), "foo");
219    }
220
221    #[test]
222    fn test_servers() {
223        let mut handle = Alpm::new("/", "tests/db").unwrap();
224        let db = handle.register_syncdb_mut("foo", SigLevel::NONE).unwrap();
225        assert_eq!(db.name(), "foo");
226        let servers = vec!["a", "bb", "ccc"];
227
228        for server in &servers {
229            db.add_server(*server).unwrap();
230        }
231
232        let servers2 = db
233            .servers()
234            .iter()
235            .map(|s| s.to_string())
236            .collect::<Vec<_>>();
237        db.set_servers(servers2.iter()).unwrap();
238        let servers2 = db
239            .servers()
240            .iter()
241            .map(|s| s.to_string())
242            .collect::<Vec<_>>();
243        db.set_servers(servers2.into_iter()).unwrap();
244
245        assert_eq!(servers, db.servers().iter().collect::<Vec<_>>());
246    }
247
248    #[test]
249    fn test_set_servers() {
250        let mut handle = Alpm::new("/", "tests/db").unwrap();
251        let db = handle.register_syncdb_mut("foo", SigLevel::NONE).unwrap();
252        assert_eq!(db.name(), "foo");
253        let servers = vec!["a", "bb", "ccc"];
254
255        db.set_servers(servers.iter().cloned()).unwrap();
256
257        assert_eq!(servers, db.servers().iter().collect::<Vec<_>>());
258    }
259
260    #[test]
261    fn test_mut() {
262        let mut handle = Alpm::new("/", "tests/db").unwrap();
263        handle.register_syncdb_mut("foo", SigLevel::NONE).unwrap();
264        handle.register_syncdb_mut("bar", SigLevel::NONE).unwrap();
265
266        for db in handle.syncdbs_mut() {
267            db.add_server("foo").unwrap();
268        }
269
270        for db in handle.syncdbs_mut() {
271            db.add_server("bar").unwrap();
272        }
273
274        for db in handle.syncdbs() {
275            assert_eq!(db.servers().iter().collect::<Vec<_>>(), vec!["foo", "bar"]);
276        }
277
278        for db in handle.syncdbs_mut() {
279            db.unregister();
280        }
281
282        assert!(handle.syncdbs().is_empty());
283    }
284
285    #[test]
286    fn test_pkg() {
287        let handle = Alpm::new("/", "tests/db").unwrap();
288        let db = handle.register_syncdb("core", SigLevel::NONE).unwrap();
289        let pkg = db.pkg("linux").unwrap();
290        assert!(pkg.version().as_str() == "5.1.8.arch1-1");
291    }
292
293    #[test]
294    fn test_search() {
295        let handle = Alpm::new("/", "tests/db").unwrap();
296        let db = handle.register_syncdb("core", SigLevel::NONE).unwrap();
297        let res = db
298            .search(["^mkinitcpio-nfs-utils$"].iter().cloned())
299            .unwrap();
300        let res = res.iter().collect::<Vec<_>>();
301
302        for _ in &res {}
303        for _ in &res {}
304
305        assert_eq!(res.len(), 1);
306        assert_eq!(res[0].name(), "mkinitcpio-nfs-utils");
307
308        let mut list: AlpmListMut<String> = AlpmListMut::new();
309        list.push("pacman".to_string());
310
311        let pkgs = db.search(&list).unwrap();
312        assert!(!pkgs.is_empty());
313
314        db.search(["pacman"].iter().cloned()).unwrap();
315        db.search(vec!["pacman".to_string()].into_iter()).unwrap();
316    }
317
318    #[test]
319    fn test_group() {
320        let handle = Alpm::new("/", "tests/db").unwrap();
321        let db = handle.register_syncdb("core", SigLevel::NONE).unwrap();
322        let base = db.group("base").unwrap();
323        assert_eq!(base.name(), "base");
324        assert!(base.packages().len() > 10);
325        assert!(base.packages().len() < 100);
326    }
327}