alpm_ll/
trans.rs

1use crate::{Alpm, AlpmList, AlpmListMut, CommitResult, Error, Package, PrepareResult, Result};
2
3use alpm_sys_ll::_alpm_transflag_t::*;
4use alpm_sys_ll::*;
5
6use std::ptr;
7
8use bitflags::bitflags;
9
10bitflags! {
11    pub struct TransFlag: u32 {
12        const NONE = 0;
13        const NO_DEPS = ALPM_TRANS_FLAG_NODEPS;
14        const NO_SAVE = ALPM_TRANS_FLAG_NOSAVE;
15        const NO_DEP_VERSION = ALPM_TRANS_FLAG_NODEPVERSION;
16        const CASCADE = ALPM_TRANS_FLAG_CASCADE;
17        const RECURSE = ALPM_TRANS_FLAG_RECURSE;
18        const DB_ONLY = ALPM_TRANS_FLAG_DBONLY;
19        #[cfg(feature = "git")]
20        const NO_HOOKS = ALPM_TRANS_FLAG_NOHOOKS;
21        const ALL_DEPS = ALPM_TRANS_FLAG_ALLDEPS;
22        const DOWNLOAD_ONLY = ALPM_TRANS_FLAG_DOWNLOADONLY;
23        const NO_SCRIPTLET = ALPM_TRANS_FLAG_NOSCRIPTLET;
24        const NO_CONFLICTS = ALPM_TRANS_FLAG_NOCONFLICTS;
25        const NEEDED = ALPM_TRANS_FLAG_NEEDED;
26        const ALL_EXPLICIT = ALPM_TRANS_FLAG_ALLEXPLICIT;
27        const UNNEEDED = ALPM_TRANS_FLAG_UNNEEDED;
28        const RECURSE_ALL = ALPM_TRANS_FLAG_RECURSEALL;
29        const NO_LOCK = ALPM_TRANS_FLAG_NOLOCK;
30    }
31}
32
33impl Alpm {
34    pub fn trans_flags(self) -> TransFlag {
35        let flags = unsafe { self.lib.alpm_trans_get_flags(self.as_ptr()) };
36        TransFlag::from_bits(flags as u32).unwrap()
37    }
38
39    pub fn trans_prepare(&mut self) -> std::result::Result<(), (PrepareResult, Error)> {
40        let mut list = ptr::null_mut();
41        let ret = unsafe { self.lib.alpm_trans_prepare(self.as_ptr(), &mut list) };
42        let err = self.check_ret(ret);
43
44        if let Err(err) = err {
45            let ret = match err {
46                Error::PkgInvalidArch => unsafe {
47                    PrepareResult::PkgInvalidArch(AlpmListMut::from_parts(self, list))
48                },
49                Error::UnsatisfiedDeps => unsafe {
50                    PrepareResult::UnsatisfiedDeps(AlpmListMut::from_parts(self, list))
51                },
52                Error::ConflictingDeps => unsafe {
53                    PrepareResult::ConflictingDeps(AlpmListMut::from_parts(self, list))
54                },
55                _ => PrepareResult::Ok,
56            };
57
58            Err((ret, err))
59        } else {
60            Ok(())
61        }
62    }
63
64    pub fn trans_commit(&mut self) -> std::result::Result<(), (CommitResult, Error)> {
65        let mut list = ptr::null_mut();
66        let ret = unsafe { self.lib.alpm_trans_commit(self.as_ptr(), &mut list) };
67        let err = self.check_ret(ret);
68
69        if let Err(err) = err {
70            let ret = match err {
71                Error::FileConflicts => unsafe {
72                    CommitResult::FileConflict(AlpmListMut::from_parts(self, list))
73                },
74                Error::PkgInvalid | Error::PkgInvalidSig | Error::PkgInvalidChecksum => unsafe {
75                    CommitResult::PkgInvalid(AlpmListMut::from_parts(self, list))
76                },
77                _ => CommitResult::Ok,
78            };
79
80            Err((ret, err))
81        } else {
82            Ok(())
83        }
84    }
85
86    pub fn trans_interrupt(&mut self) -> Result<()> {
87        let ret = unsafe { self.lib.alpm_trans_interrupt(self.as_ptr()) };
88        self.check_ret(ret)
89    }
90
91    pub fn trans_add(&self) -> AlpmList<Package> {
92        let list = unsafe { self.lib.alpm_trans_get_add(self.as_ptr()) };
93        unsafe { AlpmList::from_parts(self, list) }
94    }
95
96    pub fn trans_remove(&self) -> AlpmList<Package> {
97        let list = unsafe { self.lib.alpm_trans_get_remove(self.as_ptr()) };
98        unsafe { AlpmList::from_parts(self, list) }
99    }
100
101    pub fn trans_release(&mut self) -> Result<()> {
102        let ret = unsafe { self.lib.alpm_trans_release(self.as_ptr()) };
103        self.check_ret(ret)
104    }
105}
106
107impl Alpm {
108    pub fn trans_init(&self, flags: TransFlag) -> Result<()> {
109        let ret = unsafe { self.lib.alpm_trans_init(self.as_ptr(), flags.bits() as i32) };
110        self.check_ret(ret)
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117    use crate::{AnyEvent, Error, Event, LogLevel, SigLevel};
118
119    fn logcb(_level: LogLevel, msg: &str, _: &mut ()) {
120        print!("{}", msg);
121    }
122
123    fn eventcb(event: AnyEvent, _: &mut ()) {
124        match event.event() {
125            Event::DatabaseMissing(x) => println!("missing database: {}", x.dbname()),
126            _ => println!("event: {:?}", event),
127        }
128    }
129
130    #[test]
131    #[ignore]
132    fn test_trans() {
133        let mut handle = Alpm::new("/", "tests/db").unwrap();
134        let flags = TransFlag::DB_ONLY;
135
136        handle.set_log_cb((), logcb);
137        handle.set_event_cb((), eventcb);
138
139        let db = handle.register_syncdb_mut("core", SigLevel::NONE).unwrap();
140        db.add_server("https://ftp.rnl.tecnico.ulisboa.pt/pub/archlinux/core/os/x86_64")
141            .unwrap();
142        let db = handle
143            .syncdbs()
144            .iter()
145            .find(|db| db.name() == "core")
146            .unwrap();
147        let pkg = db.pkg("filesystem").unwrap();
148
149        handle.trans_init(flags).unwrap();
150        handle.trans_add_pkg(pkg).unwrap();
151        handle.trans_prepare().unwrap();
152        // Due to age the mirror now returns 404 for the package.
153        // But we're only testing that the function is called correctly anyway.
154        assert!(handle.trans_commit().unwrap_err().1 == Error::Retrieve);
155    }
156}