11use std:: collections:: HashSet ;
22use std:: fmt:: { self , Debug , Formatter } ;
3- use std:: fs;
43use std:: path:: { Path , PathBuf } ;
54
65use crate :: core:: source:: MaybePackage ;
@@ -11,8 +10,8 @@ use anyhow::Context as _;
1110use cargo_util:: paths;
1211use filetime:: FileTime ;
1312use ignore:: gitignore:: GitignoreBuilder ;
14- use ignore:: Match ;
1513use log:: { trace, warn} ;
14+ use walkdir:: WalkDir ;
1615
1716pub struct PathSource < ' cfg > {
1817 source_id : SourceId ,
@@ -131,39 +130,36 @@ impl<'cfg> PathSource<'cfg> {
131130 }
132131 let ignore_include = include_builder. build ( ) ?;
133132
134- let ignore_should_package = |relative_path : & Path , is_dir : bool | -> CargoResult < bool > {
133+ let ignore_should_package = |relative_path : & Path , is_dir : bool | {
135134 // "Include" and "exclude" options are mutually exclusive.
136135 if no_include_option {
137- match ignore_exclude. matched_path_or_any_parents ( relative_path, is_dir) {
138- Match :: None => Ok ( true ) ,
139- Match :: Ignore ( _) => Ok ( false ) ,
140- Match :: Whitelist ( _) => Ok ( true ) ,
141- }
136+ !ignore_exclude
137+ . matched_path_or_any_parents ( relative_path, is_dir)
138+ . is_ignore ( )
142139 } else {
143140 if is_dir {
144141 // Generally, include directives don't list every
145142 // directory (nor should they!). Just skip all directory
146143 // checks, and only check files.
147- return Ok ( true ) ;
144+ return true ;
148145 }
149- match ignore_include
146+ ignore_include
150147 . matched_path_or_any_parents ( relative_path, /* is_dir */ false )
151- {
152- Match :: None => Ok ( false ) ,
153- Match :: Ignore ( _) => Ok ( true ) ,
154- Match :: Whitelist ( _) => Ok ( false ) ,
155- }
148+ . is_ignore ( )
156149 }
157150 } ;
158151
159- let mut filter = |path : & Path , is_dir : bool | -> CargoResult < bool > {
160- let relative_path = path. strip_prefix ( root) ?;
152+ let mut filter = |path : & Path , is_dir : bool | {
153+ let relative_path = match path. strip_prefix ( root) {
154+ Ok ( p) => p,
155+ Err ( _) => return false ,
156+ } ;
161157
162158 let rel = relative_path. as_os_str ( ) ;
163159 if rel == "Cargo.lock" {
164- return Ok ( pkg. include_lockfile ( ) ) ;
160+ return pkg. include_lockfile ( ) ;
165161 } else if rel == "Cargo.toml" {
166- return Ok ( true ) ;
162+ return true ;
167163 }
168164
169165 ignore_should_package ( relative_path, is_dir)
@@ -225,7 +221,7 @@ impl<'cfg> PathSource<'cfg> {
225221 & self ,
226222 pkg : & Package ,
227223 repo : & git2:: Repository ,
228- filter : & mut dyn FnMut ( & Path , bool ) -> CargoResult < bool > ,
224+ filter : & mut dyn FnMut ( & Path , bool ) -> bool ,
229225 ) -> CargoResult < Vec < PathBuf > > {
230226 warn ! ( "list_files_git {}" , pkg. package_id( ) ) ;
231227 let index = repo. index ( ) ?;
@@ -347,7 +343,7 @@ impl<'cfg> PathSource<'cfg> {
347343 PathSource :: walk ( & file_path, & mut ret, false , filter) ?;
348344 }
349345 }
350- } else if ( * filter) ( & file_path, is_dir) ? {
346+ } else if filter ( & file_path, is_dir) {
351347 assert ! ( !is_dir) ;
352348 // We found a file!
353349 warn ! ( " found {}" , file_path. display( ) ) ;
@@ -379,7 +375,7 @@ impl<'cfg> PathSource<'cfg> {
379375 fn list_files_walk (
380376 & self ,
381377 pkg : & Package ,
382- filter : & mut dyn FnMut ( & Path , bool ) -> CargoResult < bool > ,
378+ filter : & mut dyn FnMut ( & Path , bool ) -> bool ,
383379 ) -> CargoResult < Vec < PathBuf > > {
384380 let mut ret = Vec :: new ( ) ;
385381 PathSource :: walk ( pkg. root ( ) , & mut ret, true , filter) ?;
@@ -390,39 +386,46 @@ impl<'cfg> PathSource<'cfg> {
390386 path : & Path ,
391387 ret : & mut Vec < PathBuf > ,
392388 is_root : bool ,
393- filter : & mut dyn FnMut ( & Path , bool ) -> CargoResult < bool > ,
389+ filter : & mut dyn FnMut ( & Path , bool ) -> bool ,
394390 ) -> CargoResult < ( ) > {
395- let is_dir = path. is_dir ( ) ;
396- if !is_root && !( * filter) ( path, is_dir) ? {
397- return Ok ( ( ) ) ;
398- }
399- if !is_dir {
400- ret. push ( path. to_path_buf ( ) ) ;
401- return Ok ( ( ) ) ;
402- }
403- // Don't recurse into any sub-packages that we have.
404- if !is_root && path. join ( "Cargo.toml" ) . exists ( ) {
405- return Ok ( ( ) ) ;
406- }
391+ let walkdir = WalkDir :: new ( path)
392+ . follow_links ( true )
393+ . into_iter ( )
394+ . filter_entry ( |entry| {
395+ let path = entry. path ( ) ;
396+ let at_root = is_root && entry. depth ( ) == 0 ;
397+ let is_dir = entry. file_type ( ) . is_dir ( ) ;
398+
399+ if !at_root && !filter ( path, is_dir) {
400+ return false ;
401+ }
407402
408- // For package integration tests, we need to sort the paths in a deterministic order to
409- // be able to match stdout warnings in the same order.
410- //
411- // TODO: drop `collect` and sort after transition period and dropping warning tests.
412- // See rust-lang/cargo#4268 and rust-lang/cargo#4270.
413- let mut entries: Vec < PathBuf > = fs:: read_dir ( path)
414- . with_context ( || format ! ( "cannot read {:?}" , path) ) ?
415- . map ( |e| e. unwrap ( ) . path ( ) )
416- . collect ( ) ;
417- entries. sort_unstable_by ( |a, b| a. as_os_str ( ) . cmp ( b. as_os_str ( ) ) ) ;
418- for path in entries {
419- let name = path. file_name ( ) . and_then ( |s| s. to_str ( ) ) ;
420- if is_root && name == Some ( "target" ) {
421- // Skip Cargo artifacts.
422- continue ;
403+ if !is_dir {
404+ return true ;
405+ }
406+
407+ // Don't recurse into any sub-packages that we have.
408+ if !at_root && path. join ( "Cargo.toml" ) . exists ( ) {
409+ return false ;
410+ }
411+
412+ // Skip root Cargo artifacts.
413+ if is_root
414+ && entry. depth ( ) == 1
415+ && path. file_name ( ) . and_then ( |s| s. to_str ( ) ) == Some ( "target" )
416+ {
417+ return false ;
418+ }
419+
420+ true
421+ } ) ;
422+ for entry in walkdir {
423+ let entry = entry?;
424+ if !entry. file_type ( ) . is_dir ( ) {
425+ ret. push ( entry. path ( ) . to_path_buf ( ) ) ;
423426 }
424- PathSource :: walk ( & path, ret, false , filter) ?;
425427 }
428+
426429 Ok ( ( ) )
427430 }
428431
0 commit comments