1 use crate::build
::CheckoutBuilder
;
2 use crate::util
::Binding
;
3 use crate::{panic, raw, Oid, StashApplyProgress}
;
4 use libc
::{c_char, c_int, c_void, size_t}
;
8 /// Stash application progress notification function.
10 /// Return `true` to continue processing, or `false` to
11 /// abort the stash application.
12 pub type StashApplyProgressCb
<'a
> = dyn FnMut(StashApplyProgress
) -> bool
+ 'a
;
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
> = dyn FnMut(usize, &str, &Oid
) -> bool
+ 'a
;
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
,
26 impl<'cb
> Default
for StashApplyOptions
<'cb
> {
27 fn default() -> Self {
32 impl<'cb
> StashApplyOptions
<'cb
> {
33 /// Creates a default set of merge options.
34 pub fn new() -> StashApplyOptions
<'cb
> {
35 let mut opts
= StashApplyOptions
{
37 checkout_options
: None
,
38 raw_opts
: unsafe { mem::zeroed() }
,
41 unsafe { raw::git_stash_apply_init_options(&mut opts.raw_opts, 1) }
,
47 /// Set stash application flag to GIT_STASH_APPLY_REINSTATE_INDEX
48 pub fn reinstantiate_index(&mut self) -> &mut StashApplyOptions
<'cb
> {
49 self.raw_opts
.flags
= raw
::GIT_STASH_APPLY_REINSTATE_INDEX
as u32;
53 /// Options to use when writing files to the working directory
54 pub fn checkout_options(&mut self, opts
: CheckoutBuilder
<'cb
>) -> &mut StashApplyOptions
<'cb
> {
55 self.checkout_options
= Some(opts
);
59 /// Optional callback to notify the consumer of application progress.
61 /// Return `true` to continue processing, or `false` to
62 /// abort the stash application.
63 pub fn progress_cb
<C
>(&mut self, callback
: C
) -> &mut StashApplyOptions
<'cb
>
65 C
: FnMut(StashApplyProgress
) -> bool
+ 'cb
,
67 self.progress
= Some(Box
::new(callback
) as Box
<StashApplyProgressCb
<'cb
>>);
68 self.raw_opts
.progress_cb
= Some(stash_apply_progress_cb
);
69 self.raw_opts
.progress_payload
= self as *mut _
as *mut _
;
73 /// Pointer to a raw git_stash_apply_options
74 pub fn raw(&mut self) -> &raw
::git_stash_apply_options
{
76 if let Some(opts
) = self.checkout_options
.as_mut() {
77 opts
.configure(&mut self.raw_opts
.checkout_options
);
85 pub struct StashCbData
<'a
> {
86 pub callback
: &'a
mut StashCb
<'a
>,
90 pub extern "C" fn stash_cb(
92 message
: *const c_char
,
93 stash_id
: *const raw
::git_oid
,
96 panic
::wrap(|| unsafe {
97 let mut data
= &mut *(payload
as *mut StashCbData
<'_
>);
99 let mut callback
= &mut data
.callback
;
102 CStr
::from_ptr(message
).to_str().unwrap(),
103 &Binding
::from_raw(stash_id
),
116 fn convert_progress(progress
: raw
::git_stash_apply_progress_t
) -> StashApplyProgress
{
118 raw
::GIT_STASH_APPLY_PROGRESS_NONE
=> StashApplyProgress
::None
,
119 raw
::GIT_STASH_APPLY_PROGRESS_LOADING_STASH
=> StashApplyProgress
::LoadingStash
,
120 raw
::GIT_STASH_APPLY_PROGRESS_ANALYZE_INDEX
=> StashApplyProgress
::AnalyzeIndex
,
121 raw
::GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED
=> StashApplyProgress
::AnalyzeModified
,
122 raw
::GIT_STASH_APPLY_PROGRESS_ANALYZE_UNTRACKED
=> StashApplyProgress
::AnalyzeUntracked
,
123 raw
::GIT_STASH_APPLY_PROGRESS_CHECKOUT_UNTRACKED
=> StashApplyProgress
::CheckoutUntracked
,
124 raw
::GIT_STASH_APPLY_PROGRESS_CHECKOUT_MODIFIED
=> StashApplyProgress
::CheckoutModified
,
125 raw
::GIT_STASH_APPLY_PROGRESS_DONE
=> StashApplyProgress
::Done
,
127 _
=> StashApplyProgress
::None
,
132 extern "C" fn stash_apply_progress_cb(
133 progress
: raw
::git_stash_apply_progress_t
,
134 payload
: *mut c_void
,
136 panic
::wrap(|| unsafe {
137 let mut options
= &mut *(payload
as *mut StashApplyOptions
<'_
>);
139 let mut callback
= options
.progress
.as_mut().unwrap();
140 callback(convert_progress(progress
))
154 use crate::stash
::StashApplyOptions
;
155 use crate::test
::repo_init
;
156 use crate::{Repository, StashFlags, Status}
;
161 fn make_stash
<C
>(next
: C
)
163 C
: FnOnce(&mut Repository
),
165 let (_td
, mut repo
) = repo_init();
166 let signature
= repo
.signature().unwrap();
168 let p
= Path
::new(repo
.workdir().unwrap()).join("file_b.txt");
169 println
!("using path {:?}", p
);
172 .write("data".as_bytes())
175 let rel_p
= Path
::new("file_b.txt");
176 assert
!(repo
.status_file(&rel_p
).unwrap() == Status
::WT_NEW
);
178 repo
.stash_save(&signature
, "msg1", Some(StashFlags
::INCLUDE_UNTRACKED
))
181 assert
!(repo
.status_file(&rel_p
).is_err());
184 repo
.stash_foreach(|index
, name
, _oid
| {
187 assert
!(name
== "On master: msg1");
196 fn count_stash(repo
: &mut Repository
) -> usize {
198 repo
.stash_foreach(|_
, _
, _
| {
207 fn smoke_stash_save_drop() {
209 repo
.stash_drop(0).unwrap();
210 assert
!(count_stash(repo
) == 0)
215 fn smoke_stash_save_pop() {
217 repo
.stash_pop(0, None
).unwrap();
218 assert
!(count_stash(repo
) == 0)
223 fn smoke_stash_save_apply() {
225 let mut options
= StashApplyOptions
::new();
226 options
.progress_cb(|progress
| {
227 println
!("{:?}", progress
);
231 repo
.stash_apply(0, Some(&mut options
)).unwrap();
232 assert
!(count_stash(repo
) == 1)
237 fn test_stash_save2_msg_none() {
238 let (_td
, mut repo
) = repo_init();
239 let signature
= repo
.signature().unwrap();
241 let p
= Path
::new(repo
.workdir().unwrap()).join("file_b.txt");
245 .write("data".as_bytes())
248 repo
.stash_save2(&signature
, None
, Some(StashFlags
::INCLUDE_UNTRACKED
))
251 let mut stash_name
= String
::new();
252 repo
.stash_foreach(|index
, name
, _oid
| {
253 assert_eq
!(index
, 0);
254 stash_name
= name
.to_string();
259 assert
!(stash_name
.starts_with("WIP on master:"));