Skip to content

Commit

Permalink
feat(package): preserve file type information in PathEntry
Browse files Browse the repository at this point in the history
So that we can tell whether a path is a symlink and need to
traverse to the actual file to check dirtiness or copy real content.
  • Loading branch information
weihanglo committed Dec 30, 2024
1 parent 42dc4ef commit c8c8223
Showing 1 changed file with 66 additions and 1 deletion.
67 changes: 66 additions & 1 deletion src/cargo/sources/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -404,16 +404,70 @@ impl<'gctx> Source for RecursivePathSource<'gctx> {
}
}

/// Type that abstracts over [`gix::dir::entry::Kind`] and [`fs::FileType`].
#[derive(Debug, Clone, Copy)]
enum FileType {
File,
Dir,
Symlink,
Other,
}

impl From<fs::FileType> for FileType {
fn from(value: fs::FileType) -> Self {
if value.is_file() {
FileType::File
} else if value.is_dir() {
FileType::Dir
} else if value.is_symlink() {
FileType::Symlink
} else {
FileType::Other
}
}
}

impl From<gix::dir::entry::Kind> for FileType {
fn from(value: gix::dir::entry::Kind) -> Self {
use gix::dir::entry::Kind;
match value {
Kind::Untrackable => FileType::Other,
Kind::File => FileType::File,
Kind::Symlink => FileType::Symlink,
Kind::Directory | Kind::Repository => FileType::Dir,
}
}
}

/// [`PathBuf`] with extra metadata.
#[derive(Clone, Debug)]
pub struct PathEntry {
path: PathBuf,
ty: FileType,
}

impl PathEntry {
pub fn into_path_buf(self) -> PathBuf {
self.path
}

/// Similar to [`std::path::Path::is_file`]
/// but doesn't follow the symbolic link nor make any system call
pub fn is_file(&self) -> bool {
matches!(self.ty, FileType::File)
}

/// Similar to [`std::path::Path::is_dir`]
/// but doesn't follow the symbolic link nor make any system call
pub fn is_dir(&self) -> bool {
matches!(self.ty, FileType::Dir)
}

/// Similar to [`std::path::Path::is_symlink`]
/// but doesn't follow the symbolic link nor make any system call
pub fn is_symlink(&self) -> bool {
matches!(self.ty, FileType::Symlink)
}
}

impl std::ops::Deref for PathEntry {
Expand Down Expand Up @@ -727,7 +781,10 @@ fn list_files_gix(
} else if (filter)(&file_path, is_dir) {
assert!(!is_dir);
trace!(" found {}", file_path.display());
files.push(PathEntry { path: file_path });
files.push(PathEntry {
path: file_path,
ty: kind.map(Into::into).unwrap_or(FileType::Other),
});
}
}

Expand Down Expand Up @@ -782,8 +839,15 @@ fn list_files_walk(
Ok(entry) => {
let file_type = entry.file_type();
if file_type.is_file() || file_type.is_symlink() {
// We follow_links(true) here so check if entry was created from a symlink
let ty = if entry.path_is_symlink() {
FileType::Symlink
} else {
file_type.into()
};
ret.push(PathEntry {
path: entry.into_path(),
ty,
});
}
}
Expand All @@ -800,6 +864,7 @@ fn list_files_walk(
// still hit the IO error if they do access it thereafter.
Some(path) => ret.push(PathEntry {
path: path.to_path_buf(),
ty: FileType::Other,
}),
None => return Err(err.into()),
},
Expand Down

0 comments on commit c8c8223

Please sign in to comment.