1 use std::ffi::CString; 2 use std::marker; 3 use std::str; 4 5 use crate::util::Binding; 6 use crate::{raw, Buf, Direction, Error}; 7 8 /// A structure to represent a git [refspec][1]. 9 /// 10 /// Refspecs are currently mainly accessed/created through a `Remote`. 11 /// 12 /// [1]: http://git-scm.com/book/en/Git-Internals-The-Refspec 13 pub struct Refspec<'remote> { 14 raw: *const raw::git_refspec, 15 _marker: marker::PhantomData<&'remote raw::git_remote>, 16 } 17 18 impl<'remote> Refspec<'remote> { 19 /// Get the refspec's direction. direction(&self) -> Direction20 pub fn direction(&self) -> Direction { 21 match unsafe { raw::git_refspec_direction(self.raw) } { 22 raw::GIT_DIRECTION_FETCH => Direction::Fetch, 23 raw::GIT_DIRECTION_PUSH => Direction::Push, 24 n => panic!("unknown refspec direction: {}", n), 25 } 26 } 27 28 /// Get the destination specifier. 29 /// 30 /// If the destination is not utf-8, None is returned. dst(&self) -> Option<&str>31 pub fn dst(&self) -> Option<&str> { 32 str::from_utf8(self.dst_bytes()).ok() 33 } 34 35 /// Get the destination specifier, in bytes. dst_bytes(&self) -> &[u8]36 pub fn dst_bytes(&self) -> &[u8] { 37 unsafe { crate::opt_bytes(self, raw::git_refspec_dst(self.raw)).unwrap() } 38 } 39 40 /// Check if a refspec's destination descriptor matches a reference dst_matches(&self, refname: &str) -> bool41 pub fn dst_matches(&self, refname: &str) -> bool { 42 let refname = CString::new(refname).unwrap(); 43 unsafe { raw::git_refspec_dst_matches(self.raw, refname.as_ptr()) == 1 } 44 } 45 46 /// Get the source specifier. 47 /// 48 /// If the source is not utf-8, None is returned. src(&self) -> Option<&str>49 pub fn src(&self) -> Option<&str> { 50 str::from_utf8(self.src_bytes()).ok() 51 } 52 53 /// Get the source specifier, in bytes. src_bytes(&self) -> &[u8]54 pub fn src_bytes(&self) -> &[u8] { 55 unsafe { crate::opt_bytes(self, raw::git_refspec_src(self.raw)).unwrap() } 56 } 57 58 /// Check if a refspec's source descriptor matches a reference src_matches(&self, refname: &str) -> bool59 pub fn src_matches(&self, refname: &str) -> bool { 60 let refname = CString::new(refname).unwrap(); 61 unsafe { raw::git_refspec_src_matches(self.raw, refname.as_ptr()) == 1 } 62 } 63 64 /// Get the force update setting. is_force(&self) -> bool65 pub fn is_force(&self) -> bool { 66 unsafe { raw::git_refspec_force(self.raw) == 1 } 67 } 68 69 /// Get the refspec's string. 70 /// 71 /// Returns None if the string is not valid utf8. str(&self) -> Option<&str>72 pub fn str(&self) -> Option<&str> { 73 str::from_utf8(self.bytes()).ok() 74 } 75 76 /// Get the refspec's string as a byte array bytes(&self) -> &[u8]77 pub fn bytes(&self) -> &[u8] { 78 unsafe { crate::opt_bytes(self, raw::git_refspec_string(self.raw)).unwrap() } 79 } 80 81 /// Transform a reference to its target following the refspec's rules transform(&self, name: &str) -> Result<Buf, Error>82 pub fn transform(&self, name: &str) -> Result<Buf, Error> { 83 let name = CString::new(name).unwrap(); 84 unsafe { 85 let buf = Buf::new(); 86 try_call!(raw::git_refspec_transform( 87 buf.raw(), 88 self.raw, 89 name.as_ptr() 90 )); 91 Ok(buf) 92 } 93 } 94 95 /// Transform a target reference to its source reference following the refspec's rules rtransform(&self, name: &str) -> Result<Buf, Error>96 pub fn rtransform(&self, name: &str) -> Result<Buf, Error> { 97 let name = CString::new(name).unwrap(); 98 unsafe { 99 let buf = Buf::new(); 100 try_call!(raw::git_refspec_rtransform( 101 buf.raw(), 102 self.raw, 103 name.as_ptr() 104 )); 105 Ok(buf) 106 } 107 } 108 } 109 110 impl<'remote> Binding for Refspec<'remote> { 111 type Raw = *const raw::git_refspec; 112 from_raw(raw: *const raw::git_refspec) -> Refspec<'remote>113 unsafe fn from_raw(raw: *const raw::git_refspec) -> Refspec<'remote> { 114 Refspec { 115 raw: raw, 116 _marker: marker::PhantomData, 117 } 118 } raw(&self) -> *const raw::git_refspec119 fn raw(&self) -> *const raw::git_refspec { 120 self.raw 121 } 122 } 123