@@ -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 ) ]
409444pub struct PathEntry {
410445 path : PathBuf ,
446+ ty : FileType ,
411447}
412448
413449impl 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
419473impl 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