@@ -73,7 +73,9 @@ use std::cmp;
73
73
use std:: error:: Error ;
74
74
use std:: fmt;
75
75
use std:: fs;
76
+ use std:: fs:: DirEntry ;
76
77
use std:: io;
78
+ use std:: ops:: Deref ;
77
79
use std:: path:: { self , Component , Path , PathBuf } ;
78
80
use std:: str:: FromStr ;
79
81
@@ -96,8 +98,8 @@ pub struct Paths {
96
98
dir_patterns : Vec < Pattern > ,
97
99
require_dir : bool ,
98
100
options : MatchOptions ,
99
- todo : Vec < Result < ( PathBuf , usize ) , GlobError > > ,
100
- scope : Option < PathBuf > ,
101
+ todo : Vec < Result < ( PathWrapper , usize ) , GlobError > > ,
102
+ scope : Option < PathWrapper > ,
101
103
}
102
104
103
105
/// Return an iterator that produces all the `Path`s that match the given
@@ -242,6 +244,7 @@ pub fn glob_with(pattern: &str, options: MatchOptions) -> Result<Paths, PatternE
242
244
}
243
245
244
246
let scope = root. map_or_else ( || PathBuf :: from ( "." ) , to_scope) ;
247
+ let scope = PathWrapper :: from_path ( scope) ;
245
248
246
249
let mut dir_patterns = Vec :: new ( ) ;
247
250
let components =
@@ -323,8 +326,44 @@ impl fmt::Display for GlobError {
323
326
}
324
327
}
325
328
326
- fn is_dir ( p : & Path ) -> bool {
327
- fs:: metadata ( p) . map ( |m| m. is_dir ( ) ) . unwrap_or ( false )
329
+ #[ derive( Debug ) ]
330
+ struct PathWrapper {
331
+ path : PathBuf ,
332
+ is_directory : bool ,
333
+ }
334
+
335
+ impl PathWrapper {
336
+ fn from_dir_entry ( path : PathBuf , e : DirEntry ) -> Self {
337
+ let is_directory = e
338
+ . file_type ( )
339
+ . ok ( )
340
+ . map ( |file_type| file_type. is_dir ( ) )
341
+ . or_else ( || fs:: metadata ( & path) . map ( |m| m. is_dir ( ) ) . ok ( ) )
342
+ . unwrap_or ( false ) ;
343
+ Self { path, is_directory }
344
+ }
345
+ fn from_path ( path : PathBuf ) -> Self {
346
+ let is_directory = fs:: metadata ( & path) . map ( |m| m. is_dir ( ) ) . unwrap_or ( false ) ;
347
+ Self { path, is_directory }
348
+ }
349
+
350
+ fn into_path ( self ) -> PathBuf {
351
+ self . path
352
+ }
353
+ }
354
+
355
+ impl Deref for PathWrapper {
356
+ type Target = Path ;
357
+
358
+ fn deref ( & self ) -> & Self :: Target {
359
+ self . path . deref ( )
360
+ }
361
+ }
362
+
363
+ impl AsRef < Path > for PathWrapper {
364
+ fn as_ref ( & self ) -> & Path {
365
+ self . path . as_ref ( )
366
+ }
328
367
}
329
368
330
369
/// An alias for a glob iteration result.
@@ -363,10 +402,10 @@ impl Iterator for Paths {
363
402
// idx -1: was already checked by fill_todo, maybe path was '.' or
364
403
// '..' that we can't match here because of normalization.
365
404
if idx == !0 as usize {
366
- if self . require_dir && !is_dir ( & path) {
405
+ if self . require_dir && !path. is_directory {
367
406
continue ;
368
407
}
369
- return Some ( Ok ( path) ) ;
408
+ return Some ( Ok ( path. into_path ( ) ) ) ;
370
409
}
371
410
372
411
if self . dir_patterns [ idx] . is_recursive {
@@ -379,7 +418,7 @@ impl Iterator for Paths {
379
418
next += 1 ;
380
419
}
381
420
382
- if is_dir ( & path) {
421
+ if path. is_directory {
383
422
// the path is a directory, so it's a match
384
423
385
424
// push this directory's contents
@@ -394,7 +433,7 @@ impl Iterator for Paths {
394
433
if next == self . dir_patterns . len ( ) - 1 {
395
434
// pattern ends in recursive pattern, so return this
396
435
// directory as a result
397
- return Some ( Ok ( path) ) ;
436
+ return Some ( Ok ( path. into_path ( ) ) ) ;
398
437
} else {
399
438
// advanced to the next pattern for this path
400
439
idx = next + 1 ;
@@ -427,8 +466,8 @@ impl Iterator for Paths {
427
466
// *AND* its children so we don't need to check the
428
467
// children
429
468
430
- if !self . require_dir || is_dir ( & path) {
431
- return Some ( Ok ( path) ) ;
469
+ if !self . require_dir || path. is_directory {
470
+ return Some ( Ok ( path. into_path ( ) ) ) ;
432
471
}
433
472
} else {
434
473
fill_todo (
@@ -817,10 +856,10 @@ impl Pattern {
817
856
// special-casing patterns to match `.` and `..`, and avoiding `readdir()`
818
857
// calls when there are no metacharacters in the pattern.
819
858
fn fill_todo (
820
- todo : & mut Vec < Result < ( PathBuf , usize ) , GlobError > > ,
859
+ todo : & mut Vec < Result < ( PathWrapper , usize ) , GlobError > > ,
821
860
patterns : & [ Pattern ] ,
822
861
idx : usize ,
823
- path : & Path ,
862
+ path : & PathWrapper ,
824
863
options : MatchOptions ,
825
864
) {
826
865
// convert a pattern that's just many Char(_) to a string
@@ -836,7 +875,7 @@ fn fill_todo(
836
875
Some ( s)
837
876
}
838
877
839
- let add = |todo : & mut Vec < _ > , next_path : PathBuf | {
878
+ let add = |todo : & mut Vec < _ > , next_path : PathWrapper | {
840
879
if idx + 1 == patterns. len ( ) {
841
880
// We know it's good, so don't make the iterator match this path
842
881
// against the pattern again. In particular, it can't match
@@ -848,8 +887,8 @@ fn fill_todo(
848
887
} ;
849
888
850
889
let pattern = & patterns[ idx] ;
851
- let is_dir = is_dir ( path) ;
852
- let curdir = path == Path :: new ( "." ) ;
890
+ let is_dir = path. is_directory ;
891
+ let curdir = path. as_ref ( ) == Path :: new ( "." ) ;
853
892
match pattern_as_str ( pattern) {
854
893
Some ( s) => {
855
894
// This pattern component doesn't have any metacharacters, so we
@@ -863,6 +902,7 @@ fn fill_todo(
863
902
} else {
864
903
path. join ( & s)
865
904
} ;
905
+ let next_path = PathWrapper :: from_path ( next_path) ;
866
906
if ( special && is_dir)
867
907
|| ( !special
868
908
&& ( fs:: metadata ( & next_path) . is_ok ( )
@@ -875,19 +915,21 @@ fn fill_todo(
875
915
let dirs = fs:: read_dir ( path) . and_then ( |d| {
876
916
d. map ( |e| {
877
917
e. map ( |e| {
878
- if curdir {
918
+ let path = if curdir {
879
919
PathBuf :: from ( e. path ( ) . file_name ( ) . unwrap ( ) )
880
920
} else {
881
921
e. path ( )
882
- }
922
+ } ;
923
+ PathWrapper :: from_dir_entry ( path, e)
883
924
} )
884
925
} )
885
926
. collect :: < Result < Vec < _ > , _ > > ( )
886
927
} ) ;
887
928
match dirs {
888
929
Ok ( mut children) => {
889
930
if options. require_literal_leading_dot {
890
- children. retain ( |x| !x. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . starts_with ( "." ) ) ;
931
+ children
932
+ . retain ( |x| !x. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . starts_with ( "." ) ) ;
891
933
}
892
934
children. sort_by ( |p1, p2| p2. file_name ( ) . cmp ( & p1. file_name ( ) ) ) ;
893
935
todo. extend ( children. into_iter ( ) . map ( |x| Ok ( ( x, idx) ) ) ) ;
@@ -900,7 +942,7 @@ fn fill_todo(
900
942
if !pattern. tokens . is_empty ( ) && pattern. tokens [ 0 ] == Char ( '.' ) {
901
943
for & special in & [ "." , ".." ] {
902
944
if pattern. matches_with ( special, options) {
903
- add ( todo, path. join ( special) ) ;
945
+ add ( todo, PathWrapper :: from_path ( path. join ( special) ) ) ;
904
946
}
905
947
}
906
948
}
0 commit comments