Fix fifo files hanging the project wide search (#16039)

TheCub3 created

Release Notes:

- Fixed the issue related to the project wide search being stuck when
project contains .fifo files
- Might potentially solve the following issue
https://github.com/zed-industries/zed/issues/7360

Change summary

crates/collab/migrations.sqlite/20221109000000_test_schema.sql              |  1 
crates/collab/migrations/20240823155956_add_is_fifo_to_worktree_entries.sql |  2 
crates/collab/src/db/queries/projects.rs                                    |  2 
crates/collab/src/db/queries/rooms.rs                                       |  1 
crates/collab/src/db/tables/worktree_entry.rs                               |  1 
crates/fs/src/fs.rs                                                         | 13 
crates/project/src/project.rs                                               | 11 
crates/project_panel/src/project_panel.rs                                   |  1 
crates/proto/proto/zed.proto                                                |  1 
crates/worktree/src/worktree.rs                                             |  4 
10 files changed, 34 insertions(+), 3 deletions(-)

Detailed changes

crates/collab/migrations.sqlite/20221109000000_test_schema.sql 🔗

@@ -86,6 +86,7 @@ CREATE TABLE "worktree_entries" (
     "is_ignored" BOOL NOT NULL,
     "is_deleted" BOOL NOT NULL,
     "git_status" INTEGER,
+    "is_fifo" BOOL NOT NULL,
     PRIMARY KEY(project_id, worktree_id, id),
     FOREIGN KEY(project_id, worktree_id) REFERENCES worktrees (project_id, id) ON DELETE CASCADE
 );

crates/collab/src/db/queries/projects.rs 🔗

@@ -319,6 +319,7 @@ impl Database {
                         git_status: ActiveValue::set(entry.git_status.map(|status| status as i64)),
                         is_deleted: ActiveValue::set(false),
                         scan_id: ActiveValue::set(update.scan_id as i64),
+                        is_fifo: ActiveValue::set(entry.is_fifo),
                     }
                 }))
                 .on_conflict(
@@ -727,6 +728,7 @@ impl Database {
                         is_ignored: db_entry.is_ignored,
                         is_external: db_entry.is_external,
                         git_status: db_entry.git_status.map(|status| status as i32),
+                        is_fifo: db_entry.is_fifo,
                     });
                 }
             }

crates/collab/src/db/queries/rooms.rs 🔗

@@ -663,6 +663,7 @@ impl Database {
                             is_ignored: db_entry.is_ignored,
                             is_external: db_entry.is_external,
                             git_status: db_entry.git_status.map(|status| status as i32),
+                            is_fifo: db_entry.is_fifo,
                         });
                     }
                 }

crates/fs/src/fs.rs 🔗

@@ -9,6 +9,9 @@ use std::{fs::File, os::fd::AsFd};
 #[cfg(unix)]
 use std::os::unix::fs::MetadataExt;
 
+#[cfg(unix)]
+use std::os::unix::fs::FileTypeExt;
+
 use async_tar::Archive;
 use futures::{future::BoxFuture, AsyncRead, Stream, StreamExt};
 use git::repository::{GitRepository, RealGitRepository};
@@ -149,6 +152,7 @@ pub struct Metadata {
     pub mtime: SystemTime,
     pub is_symlink: bool,
     pub is_dir: bool,
+    pub is_fifo: bool,
 }
 
 #[derive(Default)]
@@ -428,11 +432,18 @@ impl Fs for RealFs {
         #[cfg(windows)]
         let inode = file_id(path).await?;
 
+        #[cfg(windows)]
+        let is_fifo = false;
+
+        #[cfg(unix)]
+        let is_fifo = metadata.file_type().is_fifo();
+
         Ok(Some(Metadata {
             inode,
             mtime: metadata.modified().unwrap(),
             is_symlink,
             is_dir: metadata.file_type().is_dir(),
+            is_fifo,
         }))
     }
 
@@ -1537,12 +1548,14 @@ impl Fs for FakeFs {
                     mtime: *mtime,
                     is_dir: false,
                     is_symlink,
+                    is_fifo: false,
                 },
                 FakeFsEntry::Dir { inode, mtime, .. } => Metadata {
                     inode: *inode,
                     mtime: *mtime,
                     is_dir: true,
                     is_symlink,
+                    is_fifo: false,
                 },
                 FakeFsEntry::Symlink { .. } => unreachable!(),
             }))

crates/project/src/project.rs 🔗

@@ -10969,10 +10969,15 @@ async fn search_snapshots(
                     abs_path.clear();
                     abs_path.push(&snapshot.abs_path());
                     abs_path.push(&entry.path);
-                    if let Some(file) = fs.open_sync(&abs_path).await.log_err() {
-                        query.detect(file).unwrap_or(false)
-                    } else {
+
+                    if entry.is_fifo {
                         false
+                    } else {
+                        if let Some(file) = fs.open_sync(&abs_path).await.log_err() {
+                            query.detect(file).unwrap_or(false)
+                        } else {
+                            false
+                        }
                     }
                 } else {
                     false

crates/project_panel/src/project_panel.rs 🔗

@@ -1678,6 +1678,7 @@ impl ProjectPanel {
                         canonical_path: entry.canonical_path.clone(),
                         is_symlink: entry.is_symlink,
                         char_bag: entry.char_bag,
+                        is_fifo: entry.is_fifo,
                     });
                 }
                 if expanded_dir_ids.binary_search(&entry.id).is_err()

crates/proto/proto/zed.proto 🔗

@@ -1814,6 +1814,7 @@ message Entry {
     bool is_ignored = 7;
     bool is_external = 8;
     optional GitStatus git_status = 9;
+    bool is_fifo = 10;
 }
 
 message RepositoryEntry {

crates/worktree/src/worktree.rs 🔗

@@ -3186,6 +3186,7 @@ pub struct Entry {
     /// Whether this entry is considered to be a `.env` file.
     pub is_private: bool,
     pub char_bag: CharBag,
+    pub is_fifo: bool,
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
@@ -3246,6 +3247,7 @@ impl Entry {
             is_private: false,
             git_status: None,
             char_bag,
+            is_fifo: metadata.is_fifo,
         }
     }
 
@@ -5106,6 +5108,7 @@ impl<'a> From<&'a Entry> for proto::Entry {
             is_ignored: entry.is_ignored,
             is_external: entry.is_external,
             git_status: entry.git_status.map(git_status_to_proto),
+            is_fifo: entry.is_fifo,
         }
     }
 }
@@ -5134,6 +5137,7 @@ impl<'a> TryFrom<(&'a CharBag, proto::Entry)> for Entry {
             is_private: false,
             is_symlink: entry.is_symlink,
             char_bag,
+            is_fifo: entry.is_fifo,
         })
     }
 }