Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions crates/driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub use resolver::workspace::{ExpandedWorkspaceMember, expand_workspace_members}
use resolver::{
files::FilesResolutionDiagnostic,
git::{GitDescription, GitResolver},
graph::{GraphResolver, GraphResolverImpl},
graph::{AsyncGraphResolverImpl, GraphResolver},
ingot::{IngotDescriptor, IngotResolutionError, IngotResolverImpl, RemoteProgress},
};
use url::Url;
Expand Down Expand Up @@ -109,7 +109,9 @@ fn init_ingot_graph(db: &mut DriverDataBase, ingot_url: &Url) -> bool {
let mut handler = IngotHandler::new(db)
.with_stdout(true)
.with_verbose(resolver_verbose());
let mut ingot_graph_resolver = GraphResolverImpl::new(ingot_resolver(checkout_root));
let checkout_root_clone = checkout_root.clone();
let mut ingot_graph_resolver =
AsyncGraphResolverImpl::new(move || ingot_resolver(checkout_root_clone.clone()));

// Root ingot resolution should never fail since directory existence is validated earlier.
// If it fails, it indicates a bug in the resolver or an unexpected system condition.
Expand Down
22 changes: 20 additions & 2 deletions crates/resolver/src/git.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use std::{fmt, fs, io};
use std::{
collections::HashMap,
fmt, fs, io,
sync::{Arc, Mutex, OnceLock},
};

use camino::{Utf8Path, Utf8PathBuf};
use git2::{Repository, build::CheckoutBuilder};
Expand Down Expand Up @@ -49,6 +53,17 @@ pub struct GitResolver {
pub checkout_root: Utf8PathBuf,
}

static CHECKOUT_LOCKS: OnceLock<Mutex<HashMap<Utf8PathBuf, Arc<Mutex<()>>>>> = OnceLock::new();

fn checkout_lock(checkout_path: &Utf8PathBuf) -> Arc<Mutex<()>> {
let locks = CHECKOUT_LOCKS.get_or_init(|| Mutex::new(HashMap::new()));
let mut locks = locks.lock().expect("checkout locks mutex");
locks
.entry(checkout_path.clone())
.or_insert_with(|| Arc::new(Mutex::new(())))
.clone()
}

impl GitResolver {
pub fn new(checkout_root: impl Into<Utf8PathBuf>) -> Self {
Self {
Expand Down Expand Up @@ -89,8 +104,11 @@ impl GitResolver {
&self,
description: &GitDescription,
) -> Result<GitResource, GitResolutionError> {
self.ensure_checkout_root()?;
let checkout_path = self.checkout_path(description);
let lock = checkout_lock(&checkout_path);
let _guard = lock.lock().expect("checkout lock");

self.ensure_checkout_root()?;
let status = self.ensure_checkout(description, &checkout_path)?;
Ok(GitResource {
reused_checkout: matches!(status, CheckoutStatus::Existing),
Expand Down
Loading