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