use std::kinds::marker;
use std::c_str::CString;
use libc;
use {raw, Remote, Error, Signature};
pub struct Push<'remote> {
raw: *mut raw::git_push,
marker1: marker::ContravariantLifetime<'remote>,
marker2: marker::NoSend,
marker3: marker::NoSync,
}
pub struct PushStatus {
pub reference: String,
pub message: Option<String>,
}
impl<'remote> Push<'remote> {
pub unsafe fn from_raw<'a>(_remote: &'a Remote,
raw: *mut raw::git_push) -> Push<'a> {
Push {
raw: raw,
marker1: marker::ContravariantLifetime,
marker2: marker::NoSend,
marker3: marker::NoSync,
}
}
pub fn raw(&self) -> *mut raw::git_push { self.raw }
pub fn add_refspec(&mut self, refspec: &str) -> Result<(), Error> {
unsafe {
try_call!(raw::git_push_add_refspec(self.raw, refspec.to_c_str()));
Ok(())
}
}
pub fn finish(&mut self) -> Result<(), Error> {
unsafe {
try_call!(raw::git_push_finish(self.raw));
Ok(())
}
}
pub fn unpack_ok(&self) -> bool {
unsafe { raw::git_push_unpack_ok(&*self.raw) != 0 }
}
pub fn update_tips(&mut self, signature: Option<&Signature>,
reflog_message: Option<&str>) -> Result<(), Error> {
unsafe {
try_call!(raw::git_push_update_tips(self.raw,
signature.map(|s| &*s.raw()),
reflog_message.map(|s| s.to_c_str())));
Ok(())
}
}
pub fn statuses(&mut self) -> Result<Vec<PushStatus>, Error> {
let mut ret: Vec<PushStatus> = Vec::new();
unsafe {
try_call!(raw::git_push_status_foreach(self.raw, cb,
&mut ret as *mut _
as *mut libc::c_void));
}
return Ok(ret);
extern fn cb(git_ref: *const libc::c_char,
msg: *const libc::c_char,
data: *mut libc::c_void) -> libc::c_int {
unsafe {
let git_ref = match CString::new(git_ref, false).as_str() {
Some(s) => s.to_string(),
None => return 0,
};
let msg = if !msg.is_null() {
match CString::new(msg, false).as_str() {
Some(s) => Some(s.to_string()),
None => return 0,
}
} else {
None
};
let data = &mut *(data as *mut Vec<PushStatus>);
data.push(PushStatus { reference: git_ref, message: msg });
return 0;
}
}
}
}
#[unsafe_destructor]
impl<'a> Drop for Push<'a> {
fn drop(&mut self) {
unsafe { raw::git_push_free(self.raw) }
}
}
#[cfg(test)]
mod tests {
use std::io::TempDir;
use url::Url;
use Repository;
#[test]
fn smoke() {
let td = TempDir::new("test").unwrap();
let remote = td.path().join("remote");
Repository::init_bare(&remote).unwrap();
let (_td, repo) = ::test::repo_init();
let url = Url::from_file_path(&remote).unwrap();
let url = url.to_string();
let mut remote = repo.remote("origin", url.as_slice()).unwrap();
let mut push = remote.push().unwrap();
push.add_refspec("refs/heads/master").unwrap();
push.finish().unwrap();
assert!(push.unpack_ok());
push.update_tips(None, None).unwrap();
let v = push.statuses().unwrap();
assert!(v.len() > 0);
assert_eq!(v[0].reference.as_slice(), "refs/heads/master");
assert!(v[0].message.is_none());
}
}