Skip to content

Commit 8adbe0e

Browse files
committed
refactor(package): preserve file type information in PathEntry
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.
1 parent 1df629b commit 8adbe0e

File tree

1 file changed

+66
-1
lines changed

1 file changed

+66
-1
lines changed

src/cargo/sources/path.rs

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,16 +404,70 @@ impl<'gctx> Source for RecursivePathSource<'gctx> {
404404
}
405405
}
406406

407+
/// Type that abstracts over [`gix::dir::entry::Kind`] and [`fs::FileType`].
408+
#[derive(Debug, Clone, Copy)]
409+
enum FileType {
410+
File,
411+
Dir,
412+
Symlink,
413+
Other,
414+
}
415+
416+
impl From<fs::FileType> for FileType {
417+
fn from(value: fs::FileType) -> Self {
418+
if value.is_file() {
419+
FileType::File
420+
} else if value.is_dir() {
421+
FileType::Dir
422+
} else if value.is_symlink() {
423+
FileType::Symlink
424+
} else {
425+
FileType::Other
426+
}
427+
}
428+
}
429+
430+
impl From<gix::dir::entry::Kind> for FileType {
431+
fn from(value: gix::dir::entry::Kind) -> Self {
432+
use gix::dir::entry::Kind;
433+
match value {
434+
Kind::Untrackable => FileType::Other,
435+
Kind::File => FileType::File,
436+
Kind::Symlink => FileType::Symlink,
437+
Kind::Directory | Kind::Repository => FileType::Dir,
438+
}
439+
}
440+
}
441+
407442
/// [`PathBuf`] with extra metadata.
408443
#[derive(Clone, Debug)]
409444
pub struct PathEntry {
410445
path: PathBuf,
446+
ty: FileType,
411447
}
412448

413449
impl PathEntry {
414450
pub fn into_path_buf(self) -> PathBuf {
415451
self.path
416452
}
453+
454+
/// Similar to [`std::path::Path::is_file`]
455+
/// but doesn't follow the symbolic link nor make any system call
456+
pub fn is_file(&self) -> bool {
457+
matches!(self.ty, FileType::File)
458+
}
459+
460+
/// Similar to [`std::path::Path::is_dir`]
461+
/// but doesn't follow the symbolic link nor make any system call
462+
pub fn is_dir(&self) -> bool {
463+
matches!(self.ty, FileType::Dir)
464+
}
465+
466+
/// Similar to [`std::path::Path::is_symlink`]
467+
/// but doesn't follow the symbolic link nor make any system call
468+
pub fn is_symlink(&self) -> bool {
469+
matches!(self.ty, FileType::Symlink)
470+
}
417471
}
418472

419473
impl std::ops::Deref for PathEntry {
@@ -727,7 +781,10 @@ fn list_files_gix(
727781
} else if (filter)(&file_path, is_dir) {
728782
assert!(!is_dir);
729783
trace!(" found {}", file_path.display());
730-
files.push(PathEntry { path: file_path });
784+
files.push(PathEntry {
785+
path: file_path,
786+
ty: kind.map(Into::into).unwrap_or(FileType::Other),
787+
});
731788
}
732789
}
733790

@@ -782,8 +839,15 @@ fn list_files_walk(
782839
Ok(entry) => {
783840
let file_type = entry.file_type();
784841
if file_type.is_file() || file_type.is_symlink() {
842+
// We follow_links(true) here so check if entry was created from a symlink
843+
let ty = if entry.path_is_symlink() {
844+
FileType::Symlink
845+
} else {
846+
file_type.into()
847+
};
785848
ret.push(PathEntry {
786849
path: entry.into_path(),
850+
ty,
787851
});
788852
}
789853
}
@@ -800,6 +864,7 @@ fn list_files_walk(
800864
// still hit the IO error if they do access it thereafter.
801865
Some(path) => ret.push(PathEntry {
802866
path: path.to_path_buf(),
867+
ty: FileType::Other,
803868
}),
804869
None => return Err(err.into()),
805870
},

0 commit comments

Comments
 (0)