Maintain remote worktrees correctly when building updates

Antonio Scandurra created

This accidentally regressed in 53327e2.

Change summary

crates/project/src/worktree.rs |  8 +++-----
crates/server/src/rpc/store.rs | 24 +++++++++++++++++++++++-
2 files changed, 26 insertions(+), 6 deletions(-)

Detailed changes

crates/project/src/worktree.rs 🔗

@@ -768,15 +768,13 @@ impl LocalWorktree {
         if self.share.is_some() {
             let _ = share_tx.try_send(Ok(()));
         } else {
-            let snapshot = self.snapshot();
             let rpc = self.client.clone();
             let worktree_id = cx.model_id() as u64;
-
             let maintain_remote_snapshot = cx.background().spawn({
                 let rpc = rpc.clone();
                 let diagnostic_summaries = self.diagnostic_summaries.clone();
                 async move {
-                    match snapshots_to_send_rx.recv().await {
+                    let mut prev_snapshot = match snapshots_to_send_rx.recv().await {
                         Ok(snapshot) => {
                             if let Err(error) = rpc
                                 .request(proto::UpdateWorktree {
@@ -797,13 +795,14 @@ impl LocalWorktree {
                                 return Err(anyhow!("failed to send initial update worktree"));
                             } else {
                                 let _ = share_tx.try_send(Ok(()));
+                                snapshot
                             }
                         }
                         Err(error) => {
                             let _ = share_tx.try_send(Err(error.into()));
                             return Err(anyhow!("failed to send initial update worktree"));
                         }
-                    }
+                    };
 
                     for (path, summary) in diagnostic_summaries.iter() {
                         rpc.send(proto::UpdateDiagnosticSummary {
@@ -813,7 +812,6 @@ impl LocalWorktree {
                         })?;
                     }
 
-                    let mut prev_snapshot = snapshot;
                     while let Ok(snapshot) = snapshots_to_send_rx.recv().await {
                         let message =
                             snapshot.build_update(&prev_snapshot, project_id, worktree_id, false);

crates/server/src/rpc/store.rs 🔗

@@ -534,7 +534,12 @@ impl Store {
         for entry in updated_entries {
             worktree.entries.insert(entry.id, entry.clone());
         }
-        Ok(project.connection_ids())
+        let connection_ids = project.connection_ids();
+
+        #[cfg(test)]
+        self.check_invariants();
+
+        Ok(connection_ids)
     }
 
     pub fn project_connection_ids(
@@ -619,6 +624,23 @@ impl Store {
                         .guests
                         .contains_key(connection_id));
                 }
+
+                if let Some(share) = project.share.as_ref() {
+                    for (worktree_id, worktree) in share.worktrees.iter() {
+                        let mut paths = HashMap::default();
+                        for entry in worktree.entries.values() {
+                            let prev_entry = paths.insert(&entry.path, entry);
+                            assert_eq!(
+                                prev_entry,
+                                None,
+                                "worktree {:?}, duplicate path for entries {:?} and {:?}",
+                                worktree_id,
+                                prev_entry.unwrap(),
+                                entry
+                            );
+                        }
+                    }
+                }
             }
             for channel_id in &connection.channels {
                 let channel = self.channels.get(channel_id).unwrap();