From e82ad5fcf03fbb6049df19c5666d038e456a489c Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 11 Nov 2024 16:21:15 -0600 Subject: [PATCH] perf(git): Skip submodules update on existing checkouts Fixes #14603 --- src/cargo/sources/git/utils.rs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/cargo/sources/git/utils.rs b/src/cargo/sources/git/utils.rs index 39cd5616a5f..4f1f873bd8b 100644 --- a/src/cargo/sources/git/utils.rs +++ b/src/cargo/sources/git/utils.rs @@ -181,9 +181,14 @@ impl GitDatabase { .filter(|co| co.is_fresh()) { Some(co) => co, - None => GitCheckout::clone_into(dest, self, rev, gctx)?, + None => { + let (checkout, guard) = GitCheckout::clone_into(dest, self, rev, gctx)?; + checkout.update_submodules(gctx)?; + guard.mark_ok()?; + checkout + } }; - checkout.update_submodules(gctx)?; + Ok(checkout) } @@ -280,7 +285,7 @@ impl<'a> GitCheckout<'a> { database: &'a GitDatabase, revision: git2::Oid, gctx: &GlobalContext, - ) -> CargoResult> { + ) -> CargoResult<(GitCheckout<'a>, CheckoutGuard)> { let dirname = into.parent().unwrap(); paths::create_dir_all(&dirname)?; if into.exists() { @@ -329,8 +334,8 @@ impl<'a> GitCheckout<'a> { let repo = repo.unwrap(); let checkout = GitCheckout::new(database, revision, repo); - checkout.reset(gctx)?; - Ok(checkout) + let guard = checkout.reset(gctx)?; + Ok((checkout, guard)) } /// Checks if the `HEAD` of this checkout points to the expected revision. @@ -355,10 +360,11 @@ impl<'a> GitCheckout<'a> { /// To enable this we have a dummy file in our checkout, [`.cargo-ok`], /// which if present means that the repo has been successfully reset and is /// ready to go. Hence if we start to do a reset, we make sure this file - /// *doesn't* exist, and then once we're done we create the file. + /// *doesn't* exist. The caller of [`reset`] has an option to perform additional operations + /// (e.g. submodule update) before marking the check-out as ready. /// /// [`.cargo-ok`]: CHECKOUT_READY_LOCK - fn reset(&self, gctx: &GlobalContext) -> CargoResult<()> { + fn reset(&self, gctx: &GlobalContext) -> CargoResult { let guard = CheckoutGuard::guard(&self.path); info!("reset {} to {}", self.repo.path().display(), self.revision); @@ -370,8 +376,7 @@ impl<'a> GitCheckout<'a> { let object = self.repo.find_object(self.revision, None)?; reset(&self.repo, &object, gctx)?; - guard.mark_ok()?; - Ok(()) + Ok(guard) } /// Like `git submodule update --recursive` but for this git checkout.