@@ -10,7 +10,7 @@ use libc::{c_char, c_int, c_void, size_t};
10
10
11
11
use crate :: panic;
12
12
use crate :: util:: Binding ;
13
- use crate :: { raw, Error , IndexerProgress , Object , ObjectType , Oid , Progress } ;
13
+ use crate :: { raw, Error , IndexerProgress , Mempack , Object , ObjectType , Oid , Progress } ;
14
14
15
15
/// A structure to represent a git object database
16
16
pub struct Odb < ' repo > {
@@ -218,6 +218,47 @@ impl<'repo> Odb<'repo> {
218
218
Ok ( ( ) )
219
219
}
220
220
}
221
+
222
+ /// Create a new mempack backend, and add it to this odb with the given
223
+ /// priority. Higher values give the backend higher precedence. The default
224
+ /// loose and pack backends have priorities 1 and 2 respectively (hard-coded
225
+ /// in libgit2). A reference to the new mempack backend is returned on
226
+ /// success. The lifetime of the backend must be contained within the
227
+ /// lifetime of this odb, since deletion of the odb will also result in
228
+ /// deletion of the mempack backend.
229
+ ///
230
+ /// Here is an example that fails to compile because it tries to hold the
231
+ /// mempack reference beyond the odb's lifetime:
232
+ ///
233
+ /// ```compile_fail
234
+ /// use git2::Odb;
235
+ /// let mempack = {
236
+ /// let odb = Odb::new().unwrap();
237
+ /// odb.add_new_mempack_backend(1000).unwrap()
238
+ /// };
239
+ /// ```
240
+ pub fn add_new_mempack_backend < ' odb > (
241
+ & ' odb self ,
242
+ priority : i32 ,
243
+ ) -> Result < Mempack < ' odb > , Error > {
244
+ unsafe {
245
+ let mut mempack = ptr:: null_mut ( ) ;
246
+ // The mempack backend object in libgit2 is only ever freed by an
247
+ // odb that has the backend in its list. So to avoid potentially
248
+ // leaking the mempack backend, this API ensures that the backend
249
+ // is added to the odb before returning it. The lifetime of the
250
+ // mempack is also bound to the lifetime of the odb, so that users
251
+ // can't end up with a dangling reference to a mempack object that
252
+ // was actually freed when the odb was destroyed.
253
+ try_call ! ( raw:: git_mempack_new( & mut mempack) ) ;
254
+ try_call ! ( raw:: git_odb_add_backend(
255
+ self . raw,
256
+ mempack,
257
+ priority as c_int
258
+ ) ) ;
259
+ Ok ( Mempack :: from_raw ( mempack) )
260
+ }
261
+ }
221
262
}
222
263
223
264
/// An object from the Object Database.
@@ -626,4 +667,45 @@ mod tests {
626
667
}
627
668
assert_eq ! ( progress_called, true ) ;
628
669
}
670
+
671
+ #[ test]
672
+ fn write_with_mempack ( ) {
673
+ use crate :: { Buf , ResetType } ;
674
+ use std:: io:: Write ;
675
+ use std:: path:: Path ;
676
+
677
+ // Create a repo, add a mempack backend
678
+ let ( _td, repo) = crate :: test:: repo_init ( ) ;
679
+ let odb = repo. odb ( ) . unwrap ( ) ;
680
+ let mempack = odb. add_new_mempack_backend ( 1000 ) . unwrap ( ) ;
681
+
682
+ // Sanity check that foo doesn't exist initially
683
+ let foo_file = Path :: new ( repo. workdir ( ) . unwrap ( ) ) . join ( "foo" ) ;
684
+ assert ! ( !foo_file. exists( ) ) ;
685
+
686
+ // Make a commit that adds foo. This writes new stuff into the mempack
687
+ // backend.
688
+ let ( oid1, _id) = crate :: test:: commit ( & repo) ;
689
+ let commit1 = repo. find_commit ( oid1) . unwrap ( ) ;
690
+ t ! ( repo. reset( commit1. as_object( ) , ResetType :: Hard , None ) ) ;
691
+ assert ! ( foo_file. exists( ) ) ;
692
+
693
+ // Dump the mempack modifications into a buf, and reset it. This "erases"
694
+ // commit-related objects from the repository. Ensure the commit appears
695
+ // to have become invalid, by checking for failure in `reset --hard`.
696
+ let mut buf = Buf :: new ( ) ;
697
+ mempack. dump ( & repo, & mut buf) . unwrap ( ) ;
698
+ mempack. reset ( ) . unwrap ( ) ;
699
+ assert ! ( repo
700
+ . reset( commit1. as_object( ) , ResetType :: Hard , None )
701
+ . is_err( ) ) ;
702
+
703
+ // Write the buf into a packfile in the repo. This brings back the
704
+ // missing objects, and we verify everything is good again.
705
+ let mut packwriter = odb. packwriter ( ) . unwrap ( ) ;
706
+ packwriter. write ( & buf) . unwrap ( ) ;
707
+ packwriter. commit ( ) . unwrap ( ) ;
708
+ t ! ( repo. reset( commit1. as_object( ) , ResetType :: Hard , None ) ) ;
709
+ assert ! ( foo_file. exists( ) ) ;
710
+ }
629
711
}
0 commit comments