@@ -9,6 +9,7 @@ use crate::cert::Cert;
9
9
use crate :: util:: Binding ;
10
10
use crate :: {
11
11
panic, raw, Cred , CredentialType , Error , IndexerProgress , Oid , PackBuilderStage , Progress ,
12
+ PushUpdate ,
12
13
} ;
13
14
14
15
/// A structure to contain the callbacks which are invoked when a repository is
@@ -25,6 +26,7 @@ pub struct RemoteCallbacks<'a> {
25
26
update_tips : Option < Box < UpdateTips < ' a > > > ,
26
27
certificate_check : Option < Box < CertificateCheck < ' a > > > ,
27
28
push_update_reference : Option < Box < PushUpdateReference < ' a > > > ,
29
+ push_negotiation : Option < Box < PushNegotiation < ' a > > > ,
28
30
}
29
31
30
32
/// Callback used to acquire credentials for when a remote is fetched.
@@ -87,6 +89,14 @@ pub type PushTransferProgress<'a> = dyn FnMut(usize, usize, usize) + 'a;
87
89
/// * total
88
90
pub type PackProgress < ' a > = dyn FnMut ( PackBuilderStage , usize , usize ) + ' a ;
89
91
92
+ /// Callback used to inform of upcoming updates.
93
+ ///
94
+ /// The argument is a slice containing the updates which will be sent as
95
+ /// commands to the destination.
96
+ ///
97
+ /// The push is cancelled if an error is returned.
98
+ pub type PushNegotiation < ' a > = dyn FnMut ( & [ PushUpdate < ' _ > ] ) -> Result < ( ) , Error > + ' a ;
99
+
90
100
impl < ' a > Default for RemoteCallbacks < ' a > {
91
101
fn default ( ) -> Self {
92
102
Self :: new ( )
@@ -105,6 +115,7 @@ impl<'a> RemoteCallbacks<'a> {
105
115
certificate_check : None ,
106
116
push_update_reference : None ,
107
117
push_progress : None ,
118
+ push_negotiation : None ,
108
119
}
109
120
}
110
121
@@ -211,6 +222,16 @@ impl<'a> RemoteCallbacks<'a> {
211
222
self . pack_progress = Some ( Box :: new ( cb) as Box < PackProgress < ' a > > ) ;
212
223
self
213
224
}
225
+
226
+ /// The callback is called once between the negotiation step and the upload.
227
+ /// It provides information about what updates will be performed.
228
+ pub fn push_negotiation < F > ( & mut self , cb : F ) -> & mut RemoteCallbacks < ' a >
229
+ where
230
+ F : FnMut ( & [ PushUpdate < ' _ > ] ) -> Result < ( ) , Error > + ' a ,
231
+ {
232
+ self . push_negotiation = Some ( Box :: new ( cb) as Box < PushNegotiation < ' a > > ) ;
233
+ self
234
+ }
214
235
}
215
236
216
237
impl < ' a > Binding for RemoteCallbacks < ' a > {
@@ -256,6 +277,9 @@ impl<'a> Binding for RemoteCallbacks<'a> {
256
277
) -> c_int = update_tips_cb;
257
278
callbacks. update_tips = Some ( f) ;
258
279
}
280
+ if self . push_negotiation . is_some ( ) {
281
+ callbacks. push_negotiation = Some ( push_negotiation_cb) ;
282
+ }
259
283
callbacks. payload = self as * const _ as * mut _ ;
260
284
callbacks
261
285
}
@@ -471,3 +495,24 @@ extern "C" fn pack_progress_cb(
471
495
} )
472
496
. unwrap_or ( -1 )
473
497
}
498
+
499
+ extern "C" fn push_negotiation_cb (
500
+ updates : * mut * const raw:: git_push_update ,
501
+ len : size_t ,
502
+ payload : * mut c_void ,
503
+ ) -> c_int {
504
+ panic:: wrap ( || unsafe {
505
+ let payload = & mut * ( payload as * mut RemoteCallbacks < ' _ > ) ;
506
+ let callback = match payload. push_negotiation {
507
+ Some ( ref mut c) => c,
508
+ None => return 0 ,
509
+ } ;
510
+
511
+ let updates = slice:: from_raw_parts ( updates as * mut PushUpdate < ' _ > , len) ;
512
+ match callback ( updates) {
513
+ Ok ( ( ) ) => 0 ,
514
+ Err ( e) => e. raw_code ( ) ,
515
+ }
516
+ } )
517
+ . unwrap_or ( -1 )
518
+ }
0 commit comments