@@ -94,7 +94,7 @@ impl<'gctx> PathSource<'gctx> {
94
94
/// use other methods like `.gitignore`, `package.include`, or
95
95
/// `package.exclude` to filter the list of files.
96
96
#[ tracing:: instrument( skip_all) ]
97
- pub fn list_files ( & self , pkg : & Package ) -> CargoResult < Vec < PathBuf > > {
97
+ pub fn list_files ( & self , pkg : & Package ) -> CargoResult < Vec < PathEntry > > {
98
98
list_files ( pkg, self . gctx )
99
99
}
100
100
@@ -278,7 +278,7 @@ impl<'gctx> RecursivePathSource<'gctx> {
278
278
/// are relevant for building this package, but it also contains logic to
279
279
/// use other methods like `.gitignore`, `package.include`, or
280
280
/// `package.exclude` to filter the list of files.
281
- pub fn list_files ( & self , pkg : & Package ) -> CargoResult < Vec < PathBuf > > {
281
+ pub fn list_files ( & self , pkg : & Package ) -> CargoResult < Vec < PathEntry > > {
282
282
list_files ( pkg, self . gctx )
283
283
}
284
284
@@ -404,6 +404,84 @@ impl<'gctx> Source for RecursivePathSource<'gctx> {
404
404
}
405
405
}
406
406
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
+
442
+ /// [`PathBuf`] with extra metadata.
443
+ #[ derive( Clone ) ]
444
+ pub struct PathEntry {
445
+ path : PathBuf ,
446
+ ty : FileType ,
447
+ }
448
+
449
+ impl PathEntry {
450
+ pub fn into_path_buf ( self ) -> PathBuf {
451
+ self . path
452
+ }
453
+
454
+ pub fn as_path_buf ( & self ) -> & PathBuf {
455
+ & self . path
456
+ }
457
+
458
+ pub fn is_file ( & self ) -> bool {
459
+ matches ! ( self . ty, FileType :: File )
460
+ }
461
+
462
+ pub fn is_dir ( & self ) -> bool {
463
+ matches ! ( self . ty, FileType :: Dir )
464
+ }
465
+
466
+ pub fn is_symlink ( & self ) -> bool {
467
+ matches ! ( self . ty, FileType :: Symlink )
468
+ }
469
+ }
470
+
471
+ impl fmt:: Debug for PathEntry {
472
+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
473
+ self . path . fmt ( f)
474
+ }
475
+ }
476
+
477
+ impl std:: ops:: Deref for PathEntry {
478
+ type Target = PathBuf ;
479
+
480
+ fn deref ( & self ) -> & Self :: Target {
481
+ & self . path
482
+ }
483
+ }
484
+
407
485
fn first_package < ' p > (
408
486
pkg_id : PackageId ,
409
487
pkgs : & ' p Vec < Package > ,
@@ -446,7 +524,7 @@ fn first_package<'p>(
446
524
/// are relevant for building this package, but it also contains logic to
447
525
/// use other methods like `.gitignore`, `package.include`, or
448
526
/// `package.exclude` to filter the list of files.
449
- pub fn list_files ( pkg : & Package , gctx : & GlobalContext ) -> CargoResult < Vec < PathBuf > > {
527
+ pub fn list_files ( pkg : & Package , gctx : & GlobalContext ) -> CargoResult < Vec < PathEntry > > {
450
528
_list_files ( pkg, gctx) . with_context ( || {
451
529
format ! (
452
530
"failed to determine list of files in {}" ,
@@ -456,7 +534,7 @@ pub fn list_files(pkg: &Package, gctx: &GlobalContext) -> CargoResult<Vec<PathBu
456
534
}
457
535
458
536
/// See [`PathSource::list_files`].
459
- fn _list_files ( pkg : & Package , gctx : & GlobalContext ) -> CargoResult < Vec < PathBuf > > {
537
+ fn _list_files ( pkg : & Package , gctx : & GlobalContext ) -> CargoResult < Vec < PathEntry > > {
460
538
let root = pkg. root ( ) ;
461
539
let no_include_option = pkg. manifest ( ) . include ( ) . is_empty ( ) ;
462
540
let git_repo = if no_include_option {
@@ -580,7 +658,7 @@ fn list_files_gix(
580
658
repo : & gix:: Repository ,
581
659
filter : & dyn Fn ( & Path , bool ) -> bool ,
582
660
gctx : & GlobalContext ,
583
- ) -> CargoResult < Vec < PathBuf > > {
661
+ ) -> CargoResult < Vec < PathEntry > > {
584
662
debug ! ( "list_files_gix {}" , pkg. package_id( ) ) ;
585
663
let options = repo
586
664
. dirwalk_options ( ) ?
@@ -619,7 +697,7 @@ fn list_files_gix(
619
697
vec ! [ include, exclude]
620
698
} ;
621
699
622
- let mut files = Vec :: < PathBuf > :: new ( ) ;
700
+ let mut files = Vec :: < PathEntry > :: new ( ) ;
623
701
let mut subpackages_found = Vec :: new ( ) ;
624
702
for item in repo
625
703
. dirwalk_iter ( index. clone ( ) , pathspec, Default :: default ( ) , options) ?
@@ -701,7 +779,10 @@ fn list_files_gix(
701
779
} else if ( filter) ( & file_path, is_dir) {
702
780
assert ! ( !is_dir) ;
703
781
trace ! ( " found {}" , file_path. display( ) ) ;
704
- files. push ( file_path) ;
782
+ files. push ( PathEntry {
783
+ path : file_path,
784
+ ty : kind. map ( Into :: into) . unwrap_or ( FileType :: Other ) ,
785
+ } ) ;
705
786
}
706
787
}
707
788
@@ -715,7 +796,7 @@ fn list_files_gix(
715
796
/// is not tracked under a Git repository.
716
797
fn list_files_walk (
717
798
path : & Path ,
718
- ret : & mut Vec < PathBuf > ,
799
+ ret : & mut Vec < PathEntry > ,
719
800
is_root : bool ,
720
801
filter : & dyn Fn ( & Path , bool ) -> bool ,
721
802
gctx : & GlobalContext ,
@@ -756,7 +837,14 @@ fn list_files_walk(
756
837
Ok ( entry) => {
757
838
let file_type = entry. file_type ( ) ;
758
839
if file_type. is_file ( ) || file_type. is_symlink ( ) {
759
- ret. push ( entry. into_path ( ) ) ;
840
+ // We follow_links(true) here so check if entry was created from a symlink
841
+ let ty = if entry. path_is_symlink ( ) {
842
+ FileType :: Symlink
843
+ } else {
844
+ entry. file_type ( ) . into ( )
845
+ } ;
846
+ let path = entry. into_path ( ) ;
847
+ ret. push ( PathEntry { path, ty } ) ;
760
848
}
761
849
}
762
850
Err ( err) if err. loop_ancestor ( ) . is_some ( ) => {
@@ -770,7 +858,10 @@ fn list_files_walk(
770
858
// Otherwise, simply recover from it.
771
859
// Don't worry about error skipping here, the callers would
772
860
// still hit the IO error if they do access it thereafter.
773
- Some ( path) => ret. push ( path. to_path_buf ( ) ) ,
861
+ Some ( path) => ret. push ( PathEntry {
862
+ path : path. to_path_buf ( ) ,
863
+ ty : FileType :: Other ,
864
+ } ) ,
774
865
None => return Err ( err. into ( ) ) ,
775
866
} ,
776
867
}
@@ -801,7 +892,7 @@ fn last_modified_file(
801
892
let mtime = paths:: mtime ( & file) . unwrap_or_else ( |_| FileTime :: zero ( ) ) ;
802
893
if mtime > max {
803
894
max = mtime;
804
- max_path = file;
895
+ max_path = file. into_path_buf ( ) ;
805
896
}
806
897
}
807
898
trace ! ( "last modified file {}: {}" , path. display( ) , max) ;
0 commit comments