1 use std::ffi::CString;
2 use std::ptr;
3 
4 use crate::util::Binding;
5 use crate::{raw, Error, Signature};
6 
7 /// A structure to represent a repository's .mailmap file.
8 ///
9 /// The representation cannot be written to disk.
10 pub struct Mailmap {
11     raw: *mut raw::git_mailmap,
12 }
13 
14 impl Binding for Mailmap {
15     type Raw = *mut raw::git_mailmap;
16 
from_raw(ptr: *mut raw::git_mailmap) -> Mailmap17     unsafe fn from_raw(ptr: *mut raw::git_mailmap) -> Mailmap {
18         Mailmap { raw: ptr }
19     }
20 
raw(&self) -> *mut raw::git_mailmap21     fn raw(&self) -> *mut raw::git_mailmap {
22         self.raw
23     }
24 }
25 
26 impl Drop for Mailmap {
drop(&mut self)27     fn drop(&mut self) {
28         unsafe {
29             raw::git_mailmap_free(self.raw);
30         }
31     }
32 }
33 
34 impl Mailmap {
35     /// Creates an empty, in-memory mailmap object.
new() -> Result<Mailmap, Error>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.
from_buffer(buf: &str) -> Result<Mailmap, Error>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.
add_entry( &mut self, real_name: Option<&str>, real_email: Option<&str>, replace_name: Option<&str>, replace_email: &str, ) -> Result<(), Error>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.
resolve_signature(&self, sig: &Signature<'_>) -> Result<Signature<'static>, Error>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)]
96 mod tests {
97     use super::*;
98 
99     #[test]
smoke()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]
from_buffer()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 }
135