mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-12 05:15:00 +00:00
Ensure no two worktrees can point to the same root path
This could happen because there was a pause between creating the worktree and adding it to the list of tracked local worktrees, and so we might end up adding the same worktree twice when calling `create_local_worktree` in rapid succession.
This commit is contained in:
parent
d171d8ccc4
commit
1c14168f38
1 changed files with 54 additions and 27 deletions
|
@ -8,7 +8,7 @@ use anyhow::{anyhow, Context, Result};
|
||||||
use client::{proto, Client, PeerId, TypedEnvelope, User, UserStore};
|
use client::{proto, Client, PeerId, TypedEnvelope, User, UserStore};
|
||||||
use clock::ReplicaId;
|
use clock::ReplicaId;
|
||||||
use collections::{hash_map, HashMap, HashSet};
|
use collections::{hash_map, HashMap, HashSet};
|
||||||
use futures::{future::Shared, Future, FutureExt, StreamExt};
|
use futures::{future::Shared, Future, FutureExt, StreamExt, TryFutureExt};
|
||||||
use fuzzy::{PathMatch, PathMatchCandidate, PathMatchCandidateSet};
|
use fuzzy::{PathMatch, PathMatchCandidate, PathMatchCandidateSet};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task,
|
AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task,
|
||||||
|
@ -64,6 +64,8 @@ pub struct Project {
|
||||||
ProjectPath,
|
ProjectPath,
|
||||||
postage::watch::Receiver<Option<Result<ModelHandle<Buffer>, Arc<anyhow::Error>>>>,
|
postage::watch::Receiver<Option<Result<ModelHandle<Buffer>, Arc<anyhow::Error>>>>,
|
||||||
>,
|
>,
|
||||||
|
loading_local_worktrees:
|
||||||
|
HashMap<Arc<Path>, Shared<Task<Result<ModelHandle<Worktree>, Arc<anyhow::Error>>>>>,
|
||||||
opened_buffers: HashMap<u64, OpenBuffer>,
|
opened_buffers: HashMap<u64, OpenBuffer>,
|
||||||
nonce: u128,
|
nonce: u128,
|
||||||
}
|
}
|
||||||
|
@ -282,6 +284,7 @@ impl Project {
|
||||||
opened_buffers: Default::default(),
|
opened_buffers: Default::default(),
|
||||||
shared_buffers: Default::default(),
|
shared_buffers: Default::default(),
|
||||||
loading_buffers: Default::default(),
|
loading_buffers: Default::default(),
|
||||||
|
loading_local_worktrees: Default::default(),
|
||||||
client_state: ProjectClientState::Local {
|
client_state: ProjectClientState::Local {
|
||||||
is_shared: false,
|
is_shared: false,
|
||||||
remote_id_tx,
|
remote_id_tx,
|
||||||
|
@ -336,6 +339,7 @@ impl Project {
|
||||||
loading_buffers: Default::default(),
|
loading_buffers: Default::default(),
|
||||||
opened_buffer: (Rc::new(RefCell::new(opened_buffer_tx)), opened_buffer_rx),
|
opened_buffer: (Rc::new(RefCell::new(opened_buffer_tx)), opened_buffer_rx),
|
||||||
shared_buffers: Default::default(),
|
shared_buffers: Default::default(),
|
||||||
|
loading_local_worktrees: Default::default(),
|
||||||
active_entry: None,
|
active_entry: None,
|
||||||
collaborators: Default::default(),
|
collaborators: Default::default(),
|
||||||
languages,
|
languages,
|
||||||
|
@ -830,7 +834,7 @@ impl Project {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save_buffer_as(
|
pub fn save_buffer_as(
|
||||||
&self,
|
&mut self,
|
||||||
buffer: ModelHandle<Buffer>,
|
buffer: ModelHandle<Buffer>,
|
||||||
abs_path: PathBuf,
|
abs_path: PathBuf,
|
||||||
cx: &mut ModelContext<Project>,
|
cx: &mut ModelContext<Project>,
|
||||||
|
@ -2322,7 +2326,7 @@ impl Project {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_or_create_local_worktree(
|
pub fn find_or_create_local_worktree(
|
||||||
&self,
|
&mut self,
|
||||||
abs_path: impl AsRef<Path>,
|
abs_path: impl AsRef<Path>,
|
||||||
visible: bool,
|
visible: bool,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
|
@ -2362,39 +2366,62 @@ impl Project {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_local_worktree(
|
fn create_local_worktree(
|
||||||
&self,
|
&mut self,
|
||||||
abs_path: impl AsRef<Path>,
|
abs_path: impl AsRef<Path>,
|
||||||
visible: bool,
|
visible: bool,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) -> Task<Result<ModelHandle<Worktree>>> {
|
) -> Task<Result<ModelHandle<Worktree>>> {
|
||||||
let fs = self.fs.clone();
|
let fs = self.fs.clone();
|
||||||
let client = self.client.clone();
|
let client = self.client.clone();
|
||||||
let path = Arc::from(abs_path.as_ref());
|
let path: Arc<Path> = abs_path.as_ref().into();
|
||||||
cx.spawn(|project, mut cx| async move {
|
let task = self
|
||||||
let worktree = Worktree::local(client.clone(), path, visible, fs, &mut cx).await?;
|
.loading_local_worktrees
|
||||||
|
.entry(path.clone())
|
||||||
|
.or_insert_with(|| {
|
||||||
|
cx.spawn(|project, mut cx| {
|
||||||
|
async move {
|
||||||
|
let worktree =
|
||||||
|
Worktree::local(client.clone(), path.clone(), visible, fs, &mut cx)
|
||||||
|
.await;
|
||||||
|
project.update(&mut cx, |project, _| {
|
||||||
|
project.loading_local_worktrees.remove(&path);
|
||||||
|
});
|
||||||
|
let worktree = worktree?;
|
||||||
|
|
||||||
let (remote_project_id, is_shared) = project.update(&mut cx, |project, cx| {
|
let (remote_project_id, is_shared) =
|
||||||
project.add_worktree(&worktree, cx);
|
project.update(&mut cx, |project, cx| {
|
||||||
(project.remote_id(), project.is_shared())
|
project.add_worktree(&worktree, cx);
|
||||||
});
|
(project.remote_id(), project.is_shared())
|
||||||
|
});
|
||||||
|
|
||||||
if let Some(project_id) = remote_project_id {
|
if let Some(project_id) = remote_project_id {
|
||||||
if is_shared {
|
if is_shared {
|
||||||
worktree
|
worktree
|
||||||
.update(&mut cx, |worktree, cx| {
|
.update(&mut cx, |worktree, cx| {
|
||||||
worktree.as_local_mut().unwrap().share(project_id, cx)
|
worktree.as_local_mut().unwrap().share(project_id, cx)
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
} else {
|
} else {
|
||||||
worktree
|
worktree
|
||||||
.update(&mut cx, |worktree, cx| {
|
.update(&mut cx, |worktree, cx| {
|
||||||
worktree.as_local_mut().unwrap().register(project_id, cx)
|
worktree.as_local_mut().unwrap().register(project_id, cx)
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(worktree)
|
||||||
|
}
|
||||||
|
.map_err(|err| Arc::new(err))
|
||||||
|
})
|
||||||
|
.shared()
|
||||||
|
})
|
||||||
|
.clone();
|
||||||
|
cx.foreground().spawn(async move {
|
||||||
|
match task.await {
|
||||||
|
Ok(worktree) => Ok(worktree),
|
||||||
|
Err(err) => Err(anyhow!("{}", err)),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(worktree)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue