|
1 | 1 | use libc::{c_int, c_uint, c_void, size_t};
|
2 | 2 | use std::marker;
|
| 3 | +use std::path::Path; |
3 | 4 | use std::ptr;
|
4 | 5 | use std::slice;
|
5 | 6 | use std::str;
|
6 | 7 |
|
| 8 | +use crate::odb::{write_pack_progress_cb, OdbPackwriterCb}; |
7 | 9 | use crate::util::Binding;
|
| 10 | +use crate::IntoCString; |
8 | 11 | use crate::{panic, raw, Buf, Error, Oid, Repository, Revwalk};
|
9 | 12 |
|
10 | 13 | #[derive(PartialEq, Eq, Clone, Debug, Copy)]
|
@@ -84,6 +87,26 @@ impl<'repo> PackBuilder<'repo> {
|
84 | 87 | Ok(())
|
85 | 88 | }
|
86 | 89 |
|
| 90 | + /// Write the new pack and corresponding index file to path. |
| 91 | + /// To set a progress callback, use `set_progress_callback` before calling this method. |
| 92 | + pub fn write(&mut self, path: &Path, mode: u32) -> Result<(), Error> { |
| 93 | + let path = path.into_c_string()?; |
| 94 | + let progress_cb: raw::git_indexer_progress_cb = Some(write_pack_progress_cb); |
| 95 | + let progress_payload = Box::new(OdbPackwriterCb { cb: None }); |
| 96 | + let progress_payload_ptr = Box::into_raw(progress_payload); |
| 97 | + |
| 98 | + unsafe { |
| 99 | + try_call!(raw::git_packbuilder_write( |
| 100 | + self.raw, |
| 101 | + path, |
| 102 | + mode, |
| 103 | + progress_cb, |
| 104 | + progress_payload_ptr as *mut _ |
| 105 | + )); |
| 106 | + } |
| 107 | + Ok(()) |
| 108 | + } |
| 109 | + |
87 | 110 | /// Create the new pack and pass each object to the callback.
|
88 | 111 | pub fn foreach<F>(&mut self, mut cb: F) -> Result<(), Error>
|
89 | 112 | where
|
@@ -270,7 +293,10 @@ extern "C" fn progress_c(
|
270 | 293 |
|
271 | 294 | #[cfg(test)]
|
272 | 295 | mod tests {
|
273 |
| - use crate::Buf; |
| 296 | + use crate::{Buf, Oid}; |
| 297 | + |
| 298 | + // hash of a packfile constructed without any objects in it |
| 299 | + const EMPTY_PACKFILE_OID: &str = "029d08823bd8a8eab510ad6ac75c823cfd3ed31e"; |
274 | 300 |
|
275 | 301 | fn pack_header(len: u8) -> Vec<u8> {
|
276 | 302 | [].iter()
|
@@ -314,6 +340,18 @@ mod tests {
|
314 | 340 | assert_eq!(&*buf, &*empty_pack_header());
|
315 | 341 | }
|
316 | 342 |
|
| 343 | + #[test] |
| 344 | + fn smoke_write() { |
| 345 | + let (_td, repo) = crate::test::repo_init(); |
| 346 | + let mut builder = t!(repo.packbuilder()); |
| 347 | + t!(builder.write(repo.path(), 0)); |
| 348 | + #[allow(deprecated)] |
| 349 | + { |
| 350 | + assert!(builder.hash().unwrap() == Oid::from_str(EMPTY_PACKFILE_OID).unwrap()); |
| 351 | + } |
| 352 | + assert!(builder.name().unwrap() == EMPTY_PACKFILE_OID); |
| 353 | + } |
| 354 | + |
317 | 355 | #[test]
|
318 | 356 | fn smoke_foreach() {
|
319 | 357 | let (_td, repo) = crate::test::repo_init();
|
@@ -367,6 +405,41 @@ mod tests {
|
367 | 405 | assert_eq!(&buf[0..12], &*pack_header(3));
|
368 | 406 | }
|
369 | 407 |
|
| 408 | + #[test] |
| 409 | + fn insert_write() { |
| 410 | + let (_td, repo) = crate::test::repo_init(); |
| 411 | + let mut builder = t!(repo.packbuilder()); |
| 412 | + let (commit, _tree) = crate::test::commit(&repo); |
| 413 | + t!(builder.insert_object(commit, None)); |
| 414 | + assert_eq!(builder.object_count(), 1); |
| 415 | + t!(builder.write(repo.path(), 0)); |
| 416 | + t!(repo.find_commit(commit)); |
| 417 | + } |
| 418 | + |
| 419 | + #[test] |
| 420 | + fn insert_tree_write() { |
| 421 | + let (_td, repo) = crate::test::repo_init(); |
| 422 | + let mut builder = t!(repo.packbuilder()); |
| 423 | + let (_commit, tree) = crate::test::commit(&repo); |
| 424 | + // will insert the tree itself and the blob, 2 objects |
| 425 | + t!(builder.insert_tree(tree)); |
| 426 | + assert_eq!(builder.object_count(), 2); |
| 427 | + t!(builder.write(repo.path(), 0)); |
| 428 | + t!(repo.find_tree(tree)); |
| 429 | + } |
| 430 | + |
| 431 | + #[test] |
| 432 | + fn insert_commit_write() { |
| 433 | + let (_td, repo) = crate::test::repo_init(); |
| 434 | + let mut builder = t!(repo.packbuilder()); |
| 435 | + let (commit, _tree) = crate::test::commit(&repo); |
| 436 | + // will insert the commit, its tree and the blob, 3 objects |
| 437 | + t!(builder.insert_commit(commit)); |
| 438 | + assert_eq!(builder.object_count(), 3); |
| 439 | + t!(builder.write(repo.path(), 0)); |
| 440 | + t!(repo.find_commit(commit)); |
| 441 | + } |
| 442 | + |
370 | 443 | #[test]
|
371 | 444 | fn progress_callback() {
|
372 | 445 | let mut progress_called = false;
|
@@ -402,6 +475,23 @@ mod tests {
|
402 | 475 | assert_eq!(progress_called, false);
|
403 | 476 | }
|
404 | 477 |
|
| 478 | + #[test] |
| 479 | + fn progress_callback_with_write() { |
| 480 | + let mut progress_called = false; |
| 481 | + { |
| 482 | + let (_td, repo) = crate::test::repo_init(); |
| 483 | + let mut builder = t!(repo.packbuilder()); |
| 484 | + let (commit, _tree) = crate::test::commit(&repo); |
| 485 | + t!(builder.set_progress_callback(|_, _, _| { |
| 486 | + progress_called = true; |
| 487 | + true |
| 488 | + })); |
| 489 | + t!(builder.insert_commit(commit)); |
| 490 | + t!(builder.write(repo.path(), 0)); |
| 491 | + } |
| 492 | + assert_eq!(progress_called, true); |
| 493 | + } |
| 494 | + |
405 | 495 | #[test]
|
406 | 496 | fn set_threads() {
|
407 | 497 | let (_td, repo) = crate::test::repo_init();
|
|
0 commit comments