rust-status: explicitly track bad file types
authorSpencer Baugh <sbaugh@janestreet.com>
Wed, 02 Aug 2023 10:07:00 -0400
changeset 50862 5efccea9cf38
parent 50861 090658724abf
child 50863 264072107105
rust-status: explicitly track bad file types Before this, we silently skipped bad file types. Now, we check to see if a path is an exact_match in our matcher, and if so, print an error for it, and only then do we skip it. A path will be an exact match when it's specified as an explicit command line argument, and this error-printing behavior is necessary for compatibility with Python status.
rust/hg-core/src/dirstate/status.rs
rust/hg-core/src/dirstate_tree/status.rs
--- a/rust/hg-core/src/dirstate/status.rs	Mon Aug 14 09:25:36 2023 -0400
+++ b/rust/hg-core/src/dirstate/status.rs	Wed Aug 02 10:07:00 2023 -0400
@@ -20,7 +20,7 @@
 
 /// Wrong type of file from a `BadMatch`
 /// Note: a lot of those don't exist on all platforms.
-#[derive(Debug, Copy, Clone)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
 pub enum BadType {
     CharacterDevice,
     BlockDevice,
--- a/rust/hg-core/src/dirstate_tree/status.rs	Mon Aug 14 09:25:36 2023 -0400
+++ b/rust/hg-core/src/dirstate_tree/status.rs	Wed Aug 02 10:07:00 2023 -0400
@@ -14,6 +14,7 @@
 use crate::utils::files::get_path_from_bytes;
 use crate::utils::hg_path::HgPath;
 use crate::BadMatch;
+use crate::BadType;
 use crate::DirstateStatus;
 use crate::HgPathCow;
 use crate::PatternFileWarning;
@@ -24,6 +25,7 @@
 use sha1::{Digest, Sha1};
 use std::borrow::Cow;
 use std::io;
+use std::os::unix::prelude::FileTypeExt;
 use std::path::Path;
 use std::path::PathBuf;
 use std::sync::Mutex;
@@ -388,11 +390,7 @@
                     ));
                     match std::fs::symlink_metadata(&fs_path) {
                         Ok(fs_metadata) => {
-                            let file_type =
-                                match fs_metadata.file_type().try_into() {
-                                    Ok(file_type) => file_type,
-                                    Err(_) => return Ok(()),
-                                };
+                            let file_type = fs_metadata.file_type().into();
                             let entry = DirEntry {
                                 hg_path: Cow::Borrowed(
                                     dirstate_node
@@ -513,6 +511,15 @@
             // replaced by a directory or something else.
             self.mark_removed_or_deleted_if_file(&dirstate_node)?;
         }
+        if let Some(bad_type) = fs_entry.is_bad() {
+            if self.matcher.exact_match(hg_path) {
+                let path = dirstate_node.full_path(self.dmap.on_disk)?;
+                self.outcome.lock().unwrap().bad.push((
+                    path.to_owned().into(),
+                    BadMatch::BadType(bad_type),
+                ))
+            }
+        }
         if fs_entry.is_dir() {
             if self.options.collect_traversed_dirs {
                 self.outcome
@@ -866,21 +873,27 @@
     File,
     Directory,
     Symlink,
+    BadType(BadType),
 }
 
-impl TryFrom<std::fs::FileType> for FakeFileType {
-    type Error = ();
-
-    fn try_from(f: std::fs::FileType) -> Result<Self, Self::Error> {
+impl From<std::fs::FileType> for FakeFileType {
+    fn from(f: std::fs::FileType) -> Self {
         if f.is_dir() {
-            Ok(Self::Directory)
+            Self::Directory
         } else if f.is_file() {
-            Ok(Self::File)
+            Self::File
         } else if f.is_symlink() {
-            Ok(Self::Symlink)
+            Self::Symlink
+        } else if f.is_fifo() {
+            Self::BadType(BadType::FIFO)
+        } else if f.is_block_device() {
+            Self::BadType(BadType::BlockDevice)
+        } else if f.is_char_device() {
+            Self::BadType(BadType::CharacterDevice)
+        } else if f.is_socket() {
+            Self::BadType(BadType::Socket)
         } else {
-            // Things like FIFO etc.
-            Err(())
+            Self::BadType(BadType::Unknown)
         }
     }
 }
@@ -942,10 +955,7 @@
             };
             let filename =
                 Cow::Owned(get_bytes_from_os_string(file_name).into());
-            let file_type = match FakeFileType::try_from(file_type) {
-                Ok(file_type) => file_type,
-                Err(_) => continue,
-            };
+            let file_type = FakeFileType::from(file_type);
             results.push(DirEntry {
                 hg_path: filename,
                 fs_path: Cow::Owned(full_path.to_path_buf()),
@@ -974,6 +984,13 @@
     fn is_symlink(&self) -> bool {
         self.file_type == FakeFileType::Symlink
     }
+
+    fn is_bad(&self) -> Option<BadType> {
+        match self.file_type {
+            FakeFileType::BadType(ty) => Some(ty),
+            _ => None,
+        }
+    }
 }
 
 /// Return the `mtime` of a temporary file newly-created in the `.hg` directory