]> git.proxmox.com Git - cargo.git/blob - vendor/git2-0.6.8/src/stash.rs
New upstream version 0.23.0
[cargo.git] / vendor / git2-0.6.8 / src / stash.rs
1 use {raw, panic, Oid, StashApplyProgress};
2 use std::ffi::{CStr};
3 use util::{Binding};
4 use libc::{c_int, c_char, size_t, c_void};
5 use build::{CheckoutBuilder};
6 use std::mem;
7
8 /// Stash application progress notification function.
9 ///
10 /// Return `true` to continue processing, or `false` to
11 /// abort the stash application.
12 pub type StashApplyProgressCb<'a> = FnMut(StashApplyProgress) -> bool + 'a;
13
14 /// This is a callback function you can provide to iterate over all the
15 /// stashed states that will be invoked per entry.
16 pub type StashCb<'a> = FnMut(usize, &str, &Oid) -> bool + 'a;
17
18 #[allow(unused)]
19 /// Stash application options structure
20 pub struct StashApplyOptions<'cb> {
21 progress: Option<Box<StashApplyProgressCb<'cb>>>,
22 checkout_options: Option<CheckoutBuilder<'cb>>,
23 raw_opts: raw::git_stash_apply_options
24 }
25
26 impl<'cb> Default for StashApplyOptions<'cb> {
27 fn default() -> Self {
28 Self::new()
29 }
30 }
31
32 impl<'cb> StashApplyOptions<'cb> {
33 /// Creates a default set of merge options.
34 pub fn new() -> StashApplyOptions<'cb> {
35 let mut opts = StashApplyOptions {
36 progress: None,
37 checkout_options: None,
38 raw_opts: unsafe { mem::zeroed() },
39 };
40 assert_eq!(unsafe {
41 raw::git_stash_apply_init_options(&mut opts.raw_opts, 1)
42 }, 0);
43 opts
44 }
45
46 /// Set stash application flag to GIT_STASH_APPLY_REINSTATE_INDEX
47 pub fn reinstantiate_index(&mut self) -> &mut StashApplyOptions<'cb> {
48 self.raw_opts.flags = raw::GIT_STASH_APPLY_REINSTATE_INDEX;
49 self
50 }
51
52 /// Options to use when writing files to the working directory
53 pub fn checkout_options(&mut self, opts: CheckoutBuilder<'cb>) -> &mut StashApplyOptions<'cb> {
54 self.checkout_options = Some(opts);
55 self
56 }
57
58 /// Optional callback to notify the consumer of application progress.
59 ///
60 /// Return `true` to continue processing, or `false` to
61 /// abort the stash application.
62 pub fn progress_cb<C>(&mut self, callback: C) -> &mut StashApplyOptions<'cb>
63 where C: FnMut(StashApplyProgress) -> bool + 'cb
64 {
65 self.progress = Some(Box::new(callback) as Box<StashApplyProgressCb<'cb>>);
66 self.raw_opts.progress_cb = stash_apply_progress_cb;
67 self.raw_opts.progress_payload = self as *mut _ as *mut _;
68 self
69 }
70
71 /// Pointer to a raw git_stash_apply_options
72 pub fn raw(&mut self) -> &raw::git_stash_apply_options {
73 unsafe {
74 if let Some(opts) = self.checkout_options.as_mut() {
75 opts.configure(&mut self.raw_opts.checkout_options);
76 }
77 }
78 &self.raw_opts
79 }
80 }
81
82 #[allow(unused)]
83 pub struct StashCbData<'a> {
84 pub callback: &'a mut StashCb<'a>
85 }
86
87 #[allow(unused)]
88 pub extern fn stash_cb(index: size_t,
89 message: *const c_char,
90 stash_id: *const raw::git_oid,
91 payload: *mut c_void)
92 -> c_int
93 {
94 panic::wrap(|| unsafe {
95 let mut data = &mut *(payload as *mut StashCbData);
96 let res = {
97 let mut callback = &mut data.callback;
98 callback(index,
99 CStr::from_ptr(message).to_str().unwrap(),
100 &Binding::from_raw(stash_id))
101 };
102
103 if res { 0 } else { 1 }
104 }).unwrap_or(1)
105 }
106
107 fn convert_progress(progress: raw::git_stash_apply_progress_t) -> StashApplyProgress {
108 match progress {
109 raw::GIT_STASH_APPLY_PROGRESS_NONE => StashApplyProgress::None,
110 raw::GIT_STASH_APPLY_PROGRESS_LOADING_STASH => StashApplyProgress::LoadingStash,
111 raw::GIT_STASH_APPLY_PROGRESS_ANALYZE_INDEX => StashApplyProgress::AnalyzeIndex,
112 raw::GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED => StashApplyProgress::AnalyzeModified,
113 raw::GIT_STASH_APPLY_PROGRESS_ANALYZE_UNTRACKED => StashApplyProgress::AnalyzeUntracked,
114 raw::GIT_STASH_APPLY_PROGRESS_CHECKOUT_UNTRACKED => StashApplyProgress::CheckoutUntracked,
115 raw::GIT_STASH_APPLY_PROGRESS_CHECKOUT_MODIFIED => StashApplyProgress::CheckoutModified,
116 raw::GIT_STASH_APPLY_PROGRESS_DONE => StashApplyProgress::Done,
117
118 _ => StashApplyProgress::None
119 }
120 }
121
122 #[allow(unused)]
123 extern fn stash_apply_progress_cb(progress: raw::git_stash_apply_progress_t,
124 payload: *mut c_void)
125 -> c_int
126 {
127 panic::wrap(|| unsafe {
128 let mut options = &mut *(payload as *mut StashApplyOptions);
129 let res = {
130 let mut callback = options.progress.as_mut().unwrap();
131 callback(convert_progress(progress))
132 };
133
134 if res { 0 } else { -1 }
135 }).unwrap_or(-1)
136 }
137
138 #[cfg(test)]
139 mod tests {
140 use stash::{StashApplyOptions};
141 use std::io::{Write};
142 use std::fs;
143 use std::path::Path;
144 use test::{repo_init};
145 use {Repository, STATUS_WT_NEW, STASH_INCLUDE_UNTRACKED};
146
147 fn make_stash<C>(next: C) where C: FnOnce(&mut Repository) {
148 let (_td, mut repo) = repo_init();
149 let signature = repo.signature().unwrap();
150
151 let p = Path::new(repo.workdir().unwrap()).join("file_b.txt");
152 println!("using path {:?}", p);
153 fs::File::create(&p).unwrap()
154 .write("data".as_bytes()).unwrap();
155
156 let rel_p = Path::new("file_b.txt");
157 assert!(repo.status_file(&rel_p).unwrap() == STATUS_WT_NEW);
158
159 repo.stash_save(&signature, "msg1", Some(STASH_INCLUDE_UNTRACKED)).unwrap();
160
161 assert!(repo.status_file(&rel_p).is_err());
162
163 let mut count = 0;
164 repo.stash_foreach(|index, name, _oid| {
165 count += 1;
166 assert!(index == 0);
167 assert!(name == "On master: msg1");
168 true
169 }).unwrap();
170
171 assert!(count == 1);
172 next(&mut repo);
173 }
174
175 fn count_stash(repo: &mut Repository) -> usize {
176 let mut count = 0;
177 repo.stash_foreach(|_, _, _| { count += 1; true }).unwrap();
178 count
179 }
180
181 #[test]
182 fn smoke_stash_save_drop() {
183 make_stash(|repo| {
184 repo.stash_drop(0).unwrap();
185 assert!(count_stash(repo) == 0)
186 })
187 }
188
189 #[test]
190 fn smoke_stash_save_pop() {
191 make_stash(|repo| {
192 repo.stash_pop(0, None).unwrap();
193 assert!(count_stash(repo) == 0)
194 })
195 }
196
197 #[test]
198 fn smoke_stash_save_apply() {
199 make_stash(|repo| {
200 let mut options = StashApplyOptions::new();
201 options.progress_cb(|progress| {
202 println!("{:?}", progress);
203 true
204 });
205
206 repo.stash_apply(0, Some(&mut options)).unwrap();
207 assert!(count_stash(repo) == 1)
208 })
209 }
210 }