alpm_ll/
db.rs

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