@@ -80,6 +80,25 @@ pub struct GitCheckout<'a> {
80
80
repo : git2:: Repository ,
81
81
}
82
82
83
+ /// See [`GitCheckout::reset`] for rationale on this type.
84
+ #[ must_use]
85
+ struct CheckoutGuard {
86
+ ok_file : PathBuf ,
87
+ }
88
+
89
+ impl CheckoutGuard {
90
+ fn guard ( path : & Path ) -> Self {
91
+ let ok_file = path. join ( CHECKOUT_READY_LOCK ) ;
92
+ let _ = paths:: remove_file ( & ok_file) ;
93
+ Self { ok_file }
94
+ }
95
+
96
+ fn mark_ok ( self ) -> CargoResult < ( ) > {
97
+ let _ = paths:: create ( self . ok_file ) ?;
98
+ Ok ( ( ) )
99
+ }
100
+ }
101
+
83
102
impl GitRemote {
84
103
/// Creates an instance for a remote repository URL.
85
104
pub fn new ( url : & Url ) -> GitRemote {
@@ -175,15 +194,19 @@ impl GitDatabase {
175
194
// A non-fresh checkout can happen if the checkout operation was
176
195
// interrupted. In that case, the checkout gets deleted and a new
177
196
// clone is created.
178
- let checkout = match git2:: Repository :: open ( dest)
197
+ let ( checkout, guard ) = match git2:: Repository :: open ( dest)
179
198
. ok ( )
180
199
. map ( |repo| GitCheckout :: new ( self , rev, repo) )
181
200
. filter ( |co| co. is_fresh ( ) )
182
201
{
183
- Some ( co) => co,
184
- None => GitCheckout :: clone_into ( dest, self , rev, gctx) ?,
202
+ Some ( co) => ( co, None ) ,
203
+ None => GitCheckout :: clone_into ( dest, self , rev, gctx)
204
+ . map ( |( co, guard) | ( co, Some ( guard) ) ) ?,
185
205
} ;
186
206
checkout. update_submodules ( gctx) ?;
207
+ if let Some ( guard) = guard {
208
+ guard. mark_ok ( ) ?;
209
+ }
187
210
Ok ( checkout)
188
211
}
189
212
@@ -280,7 +303,7 @@ impl<'a> GitCheckout<'a> {
280
303
database : & ' a GitDatabase ,
281
304
revision : git2:: Oid ,
282
305
gctx : & GlobalContext ,
283
- ) -> CargoResult < GitCheckout < ' a > > {
306
+ ) -> CargoResult < ( GitCheckout < ' a > , CheckoutGuard ) > {
284
307
let dirname = into. parent ( ) . unwrap ( ) ;
285
308
paths:: create_dir_all ( & dirname) ?;
286
309
if into. exists ( ) {
@@ -329,8 +352,8 @@ impl<'a> GitCheckout<'a> {
329
352
let repo = repo. unwrap ( ) ;
330
353
331
354
let checkout = GitCheckout :: new ( database, revision, repo) ;
332
- checkout. reset ( gctx) ?;
333
- Ok ( checkout)
355
+ let guard = checkout. reset ( gctx) ?;
356
+ Ok ( ( checkout, guard ) )
334
357
}
335
358
336
359
/// Checks if the `HEAD` of this checkout points to the expected revision.
@@ -355,12 +378,12 @@ impl<'a> GitCheckout<'a> {
355
378
/// To enable this we have a dummy file in our checkout, [`.cargo-ok`],
356
379
/// which if present means that the repo has been successfully reset and is
357
380
/// ready to go. Hence if we start to do a reset, we make sure this file
358
- /// *doesn't* exist, and then once we're done we create the file.
381
+ /// *doesn't* exist. The caller of [`reset`] has an option to perform additional operations
382
+ /// (e.g. submodule update) before marking the check-out as ready.
359
383
///
360
384
/// [`.cargo-ok`]: CHECKOUT_READY_LOCK
361
- fn reset ( & self , gctx : & GlobalContext ) -> CargoResult < ( ) > {
362
- let ok_file = self . path . join ( CHECKOUT_READY_LOCK ) ;
363
- let _ = paths:: remove_file ( & ok_file) ;
385
+ fn reset ( & self , gctx : & GlobalContext ) -> CargoResult < CheckoutGuard > {
386
+ let guard = CheckoutGuard :: guard ( & self . path ) ;
364
387
info ! ( "reset {} to {}" , self . repo. path( ) . display( ) , self . revision) ;
365
388
366
389
// Ensure libgit2 won't mess with newlines when we vendor.
@@ -370,8 +393,8 @@ impl<'a> GitCheckout<'a> {
370
393
371
394
let object = self . repo . find_object ( self . revision , None ) ?;
372
395
reset ( & self . repo , & object, gctx) ?;
373
- paths :: create ( ok_file ) ? ;
374
- Ok ( ( ) )
396
+
397
+ Ok ( guard )
375
398
}
376
399
377
400
/// Like `git submodule update --recursive` but for this git checkout.
0 commit comments