Skip to content

Commit 996966c

Browse files
committed
Write .cargo_ok after submodule checkout completes successfully
1 parent 7bf11d6 commit 996966c

File tree

1 file changed

+35
-12
lines changed

1 file changed

+35
-12
lines changed

src/cargo/sources/git/utils.rs

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,25 @@ pub struct GitCheckout<'a> {
8080
repo: git2::Repository,
8181
}
8282

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+
83102
impl GitRemote {
84103
/// Creates an instance for a remote repository URL.
85104
pub fn new(url: &Url) -> GitRemote {
@@ -175,15 +194,19 @@ impl GitDatabase {
175194
// A non-fresh checkout can happen if the checkout operation was
176195
// interrupted. In that case, the checkout gets deleted and a new
177196
// clone is created.
178-
let checkout = match git2::Repository::open(dest)
197+
let (checkout, guard) = match git2::Repository::open(dest)
179198
.ok()
180199
.map(|repo| GitCheckout::new(self, rev, repo))
181200
.filter(|co| co.is_fresh())
182201
{
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)))?,
185205
};
186206
checkout.update_submodules(gctx)?;
207+
if let Some(guard) = guard {
208+
guard.mark_ok()?;
209+
}
187210
Ok(checkout)
188211
}
189212

@@ -280,7 +303,7 @@ impl<'a> GitCheckout<'a> {
280303
database: &'a GitDatabase,
281304
revision: git2::Oid,
282305
gctx: &GlobalContext,
283-
) -> CargoResult<GitCheckout<'a>> {
306+
) -> CargoResult<(GitCheckout<'a>, CheckoutGuard)> {
284307
let dirname = into.parent().unwrap();
285308
paths::create_dir_all(&dirname)?;
286309
if into.exists() {
@@ -329,8 +352,8 @@ impl<'a> GitCheckout<'a> {
329352
let repo = repo.unwrap();
330353

331354
let checkout = GitCheckout::new(database, revision, repo);
332-
checkout.reset(gctx)?;
333-
Ok(checkout)
355+
let guard = checkout.reset(gctx)?;
356+
Ok((checkout, guard))
334357
}
335358

336359
/// Checks if the `HEAD` of this checkout points to the expected revision.
@@ -355,12 +378,12 @@ impl<'a> GitCheckout<'a> {
355378
/// To enable this we have a dummy file in our checkout, [`.cargo-ok`],
356379
/// which if present means that the repo has been successfully reset and is
357380
/// 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.
359383
///
360384
/// [`.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);
364387
info!("reset {} to {}", self.repo.path().display(), self.revision);
365388

366389
// Ensure libgit2 won't mess with newlines when we vendor.
@@ -370,8 +393,8 @@ impl<'a> GitCheckout<'a> {
370393

371394
let object = self.repo.find_object(self.revision, None)?;
372395
reset(&self.repo, &object, gctx)?;
373-
paths::create(ok_file)?;
374-
Ok(())
396+
397+
Ok(guard)
375398
}
376399

377400
/// Like `git submodule update --recursive` but for this git checkout.

0 commit comments

Comments
 (0)