-
Notifications
You must be signed in to change notification settings - Fork 1
/
reference.rs
144 lines (133 loc) · 4.35 KB
/
reference.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
use std::libc::{c_char, c_int};
use std::{ptr, str, c_str};
use super::{OID, raise};
use super::Repository;
use ext;
/// Delete the branch reference.
pub fn branch_delete(reference: &Reference) {
unsafe {
if ext::git_branch_delete(reference.c_ref) != 0 {
raise();
}
}
}
pub struct Reference<'r> {
priv c_ref: *ext::git_reference,
priv owner: &'r Repository,
}
impl<'r> Reference<'r> {
pub fn new(c_ref: *ext::git_reference, owner: &'r Repository) -> Reference<'r> {
Reference {
c_ref: c_ref,
owner: owner,
}
}
///
/// Return the name of the given local or remote branch.
///
/// The name of the branch matches the definition of the name for branch_lookup.
/// That is, if the returned name is given to branch_lookup() then the reference is
/// returned that was given to this function.
///
/// return Some(~str) on success; otherwise None (if the ref is no local or remote branch).
///
pub fn branch_name(&self) -> Option<~str> {
unsafe {
let mut ptr_to_name: *c_char = ptr::null();
if ext::git_branch_name(&mut ptr_to_name, self.c_ref) == 0 {
Some(str::raw::from_c_str(ptr_to_name))
} else {
None
}
}
}
/// Determine if the current local branch is pointed at by HEAD.
pub fn is_head(&self) -> bool {
unsafe {
match ext::git_branch_is_head(self.c_ref) {
1 => true,
0 => false,
_ => { raise(); false },
}
}
}
/// Move/rename an existing local branch reference.
///
/// The new branch name will be checked for validity.
/// See `git_tag_create()` for rules about valid names.
pub fn branch_move(&self, new_branch_name: &str, force: bool) -> Option<Reference<'r>>
{
let mut ptr: *ext::git_reference = ptr::null();
let flag = force as c_int;
unsafe {
new_branch_name.with_c_str(|c_name| {
let res = ext::git_branch_move(&mut ptr, self.c_ref, c_name, flag);
match res {
0 => Some( Reference::new(ptr, self.owner) ),
ext::GIT_EINVALIDSPEC => None,
_ => { raise(); None },
}
})
}
}
/// Return the reference supporting the remote tracking branch,
/// returns None when the upstream is not found
pub fn upstream(&self) -> Option<Reference<'r>>
{
let mut ptr: *ext::git_reference = ptr::null();
unsafe {
let res = ext::git_branch_upstream(&mut ptr, self.c_ref);
match res {
0 => Some( Reference::new(ptr, self.owner) ),
ext::GIT_ENOTFOUND => None,
_ => { raise(); None },
}
}
}
/// Set the upstream configuration for a given local branch
/// upstream_name: remote-tracking or local branch to set as
/// upstream. Pass None to unset.
pub fn set_upstream(&self, upstream_name: Option<&str>)
{
unsafe {
let c_name =
match upstream_name {
None => c_str::CString::new(ptr::null(), false),
Some(nameref) => nameref.to_c_str(),
};
c_name.with_ref(|name_ptr| {
if ext::git_branch_set_upstream(self.c_ref, name_ptr) == 0 {
()
} else {
raise()
}
})
}
}
pub fn resolve(&self) -> OID {
unsafe {
let mut resolved_ref: *ext::git_reference = ptr::null();
let mut oid = OID { id: [0, .. 20] };
if ext::git_reference_resolve(&mut resolved_ref, self.c_ref) == 0 {
let result_oid = ext::git_reference_target(resolved_ref);
if result_oid == ptr::null() {
raise();
} else {
ptr::copy_memory(&mut oid, result_oid, 1);
ext::git_reference_free(resolved_ref);
}
} else {
raise();
}
return oid;
}
}
}
#[unsafe_destructor]
impl<'r> Drop for Reference<'r> {
fn drop(&mut self) {
unsafe {
ext::git_reference_free(self.c_ref);
}
}
}