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.
--- 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