|
1 | 1 | use crate::build::CheckoutBuilder;
|
2 |
| -use crate::util::Binding; |
3 |
| -use crate::{panic, raw, Oid, StashApplyProgress}; |
| 2 | +use crate::util::{self, Binding}; |
| 3 | +use crate::{panic, raw, IntoCString, Oid, Signature, StashApplyProgress, StashFlags}; |
4 | 4 | use libc::{c_char, c_int, c_void, size_t};
|
5 |
| -use std::ffi::CStr; |
| 5 | +use std::ffi::{c_uint, CStr, CString}; |
6 | 6 | use std::mem;
|
7 | 7 |
|
| 8 | +#[allow(unused)] |
| 9 | +/// Stash application options structure |
| 10 | +pub struct StashSaveOptions<'a> { |
| 11 | + message: Option<CString>, |
| 12 | + flags: Option<StashFlags>, |
| 13 | + stasher: Signature<'a>, |
| 14 | + pathspec: Vec<CString>, |
| 15 | + pathspec_ptrs: Vec<*const c_char>, |
| 16 | + raw_opts: raw::git_stash_save_options, |
| 17 | +} |
| 18 | + |
| 19 | +impl<'a> StashSaveOptions<'a> { |
| 20 | + /// Creates a default |
| 21 | + pub fn new(stasher: Signature<'a>) -> Self { |
| 22 | + let mut opts = Self { |
| 23 | + message: None, |
| 24 | + flags: None, |
| 25 | + stasher, |
| 26 | + pathspec: Vec::new(), |
| 27 | + pathspec_ptrs: Vec::new(), |
| 28 | + raw_opts: unsafe { mem::zeroed() }, |
| 29 | + }; |
| 30 | + assert_eq!( |
| 31 | + unsafe { |
| 32 | + raw::git_stash_save_options_init( |
| 33 | + &mut opts.raw_opts, |
| 34 | + raw::GIT_STASH_SAVE_OPTIONS_VERSION, |
| 35 | + ) |
| 36 | + }, |
| 37 | + 0 |
| 38 | + ); |
| 39 | + opts |
| 40 | + } |
| 41 | + |
| 42 | + /// |
| 43 | + pub fn flags(&mut self, flags: Option<StashFlags>) -> &mut Self { |
| 44 | + self.flags = flags; |
| 45 | + self |
| 46 | + } |
| 47 | + |
| 48 | + /// Add to the array of paths patterns to build the stash. |
| 49 | + pub fn pathspec<T: IntoCString>(&mut self, pathspec: T) -> &mut Self { |
| 50 | + let s = util::cstring_to_repo_path(pathspec).unwrap(); |
| 51 | + self.pathspec_ptrs.push(s.as_ptr()); |
| 52 | + self.pathspec.push(s); |
| 53 | + self |
| 54 | + } |
| 55 | + |
| 56 | + /// Acquire a pointer to the underlying raw options. |
| 57 | + /// |
| 58 | + /// This function is unsafe as the pointer is only valid so long as this |
| 59 | + /// structure is not moved, modified, or used elsewhere. |
| 60 | + pub unsafe fn raw(&mut self) -> *const raw::git_stash_save_options { |
| 61 | + self.raw_opts.flags = self.flags.unwrap_or_else(StashFlags::empty).bits as c_uint; |
| 62 | + self.raw_opts.message = crate::call::convert(&self.message); |
| 63 | + self.raw_opts.paths.count = self.pathspec_ptrs.len() as size_t; |
| 64 | + self.raw_opts.paths.strings = self.pathspec_ptrs.as_ptr() as *mut _; |
| 65 | + self.raw_opts.stasher = self.stasher.raw(); |
| 66 | + |
| 67 | + &self.raw_opts as *const _ |
| 68 | + } |
| 69 | +} |
| 70 | + |
8 | 71 | /// Stash application progress notification function.
|
9 | 72 | ///
|
10 | 73 | /// Return `true` to continue processing, or `false` to
|
@@ -151,12 +214,12 @@ extern "C" fn stash_apply_progress_cb(
|
151 | 214 |
|
152 | 215 | #[cfg(test)]
|
153 | 216 | mod tests {
|
154 |
| - use crate::stash::StashApplyOptions; |
| 217 | + use crate::stash::{StashApplyOptions, StashSaveOptions}; |
155 | 218 | use crate::test::repo_init;
|
156 |
| - use crate::{Repository, StashFlags, Status}; |
| 219 | + use crate::{IndexAddOption, Repository, StashFlags, Status}; |
157 | 220 | use std::fs;
|
158 | 221 | use std::io::Write;
|
159 |
| - use std::path::Path; |
| 222 | + use std::path::{Path, PathBuf}; |
160 | 223 |
|
161 | 224 | fn make_stash<C>(next: C)
|
162 | 225 | where
|
@@ -258,4 +321,40 @@ mod tests {
|
258 | 321 |
|
259 | 322 | assert!(stash_name.starts_with("WIP on main:"));
|
260 | 323 | }
|
| 324 | + |
| 325 | + fn create_file(r: &Repository, name: &str, data: &str) -> PathBuf { |
| 326 | + let p = Path::new(r.workdir().unwrap()).join(name); |
| 327 | + fs::File::create(&p) |
| 328 | + .unwrap() |
| 329 | + .write(data.as_bytes()) |
| 330 | + .unwrap(); |
| 331 | + p |
| 332 | + } |
| 333 | + |
| 334 | + #[test] |
| 335 | + fn test_stash_save_ext() { |
| 336 | + let (_td, mut repo) = repo_init(); |
| 337 | + let signature = repo.signature().unwrap(); |
| 338 | + |
| 339 | + create_file(&repo, "file_a", "foo"); |
| 340 | + create_file(&repo, "file_b", "foo"); |
| 341 | + |
| 342 | + let mut index = repo.index().unwrap(); |
| 343 | + index |
| 344 | + .add_all(["*"].iter(), IndexAddOption::DEFAULT, None) |
| 345 | + .unwrap(); |
| 346 | + index.write().unwrap(); |
| 347 | + |
| 348 | + assert_eq!(repo.statuses(None).unwrap().len(), 2); |
| 349 | + |
| 350 | + let mut opt = StashSaveOptions::new(signature); |
| 351 | + opt.pathspec("file_a"); |
| 352 | + repo.stash_save_ext(Some(&mut opt)).unwrap(); |
| 353 | + |
| 354 | + assert_eq!(repo.statuses(None).unwrap().len(), 0); |
| 355 | + |
| 356 | + repo.stash_pop(0, None).unwrap(); |
| 357 | + |
| 358 | + assert_eq!(repo.statuses(None).unwrap().len(), 1); |
| 359 | + } |
261 | 360 | }
|
0 commit comments