git2/
mailmap.rs

1use std::ffi::CString;
2use std::ptr;
3
4use crate::util::Binding;
5use crate::{raw, Error, Signature};
6
7/// A structure to represent a repository's .mailmap file.
8///
9/// The representation cannot be written to disk.
10pub struct Mailmap {
11    raw: *mut raw::git_mailmap,
12}
13
14impl Binding for Mailmap {
15    type Raw = *mut raw::git_mailmap;
16
17    unsafe fn from_raw(ptr: *mut raw::git_mailmap) -> Mailmap {
18        Mailmap { raw: ptr }
19    }
20
21    fn raw(&self) -> *mut raw::git_mailmap {
22        self.raw
23    }
24}
25
26impl Drop for Mailmap {
27    fn drop(&mut self) {
28        unsafe {
29            raw::git_mailmap_free(self.raw);
30        }
31    }
32}
33
34impl Mailmap {
35    /// Creates an empty, in-memory mailmap object.
36    pub fn new() -> Result<Mailmap, Error> {
37        crate::init();
38        let mut ret = ptr::null_mut();
39        unsafe {
40            try_call!(raw::git_mailmap_new(&mut ret));
41            Ok(Binding::from_raw(ret))
42        }
43    }
44
45    /// Creates an in-memory mailmap object representing the given buffer.
46    pub fn from_buffer(buf: &str) -> Result<Mailmap, Error> {
47        crate::init();
48        let mut ret = ptr::null_mut();
49        let len = buf.len();
50        let buf = CString::new(buf)?;
51        unsafe {
52            try_call!(raw::git_mailmap_from_buffer(&mut ret, buf, len));
53            Ok(Binding::from_raw(ret))
54        }
55    }
56
57    /// Adds a new entry to this in-memory mailmap object.
58    pub fn add_entry(
59        &mut self,
60        real_name: Option<&str>,
61        real_email: Option<&str>,
62        replace_name: Option<&str>,
63        replace_email: &str,
64    ) -> Result<(), Error> {
65        let real_name = crate::opt_cstr(real_name)?;
66        let real_email = crate::opt_cstr(real_email)?;
67        let replace_name = crate::opt_cstr(replace_name)?;
68        let replace_email = CString::new(replace_email)?;
69        unsafe {
70            try_call!(raw::git_mailmap_add_entry(
71                self.raw,
72                real_name,
73                real_email,
74                replace_name,
75                replace_email
76            ));
77            Ok(())
78        }
79    }
80
81    /// Resolves a signature to its real name and email address.
82    pub fn resolve_signature(&self, sig: &Signature<'_>) -> Result<Signature<'static>, Error> {
83        let mut ret = ptr::null_mut();
84        unsafe {
85            try_call!(raw::git_mailmap_resolve_signature(
86                &mut ret,
87                &*self.raw,
88                sig.raw()
89            ));
90            Ok(Binding::from_raw(ret))
91        }
92    }
93}
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98
99    #[test]
100    fn smoke() {
101        let sig_name = "name";
102        let sig_email = "email";
103        let sig = t!(Signature::now(sig_name, sig_email));
104
105        let mut mm = t!(Mailmap::new());
106
107        let mailmapped_sig = t!(mm.resolve_signature(&sig));
108        assert_eq!(mailmapped_sig.name(), Some(sig_name));
109        assert_eq!(mailmapped_sig.email(), Some(sig_email));
110
111        t!(mm.add_entry(None, None, None, sig_email));
112        t!(mm.add_entry(
113            Some("real name"),
114            Some("real@email"),
115            Some(sig_name),
116            sig_email,
117        ));
118
119        let mailmapped_sig = t!(mm.resolve_signature(&sig));
120        assert_eq!(mailmapped_sig.name(), Some("real name"));
121        assert_eq!(mailmapped_sig.email(), Some("real@email"));
122    }
123
124    #[test]
125    fn from_buffer() {
126        let buf = "<prøper@emæil> <email>";
127        let mm = t!(Mailmap::from_buffer(&buf));
128
129        let sig = t!(Signature::now("name", "email"));
130        let mailmapped_sig = t!(mm.resolve_signature(&sig));
131        assert_eq!(mailmapped_sig.name(), Some("name"));
132        assert_eq!(mailmapped_sig.email(), Some("prøper@emæil"));
133    }
134}