@@ -6,7 +6,7 @@ use git2;
6
6
7
7
use core:: { Package , PackageId , Summary , SourceId , Source , Dependency , Registry } ;
8
8
use ops;
9
- use util:: { CargoResult , internal, internal_error} ;
9
+ use util:: { CargoResult , internal, internal_error, human , ChainError } ;
10
10
11
11
pub struct PathSource {
12
12
id : SourceId ,
@@ -71,34 +71,46 @@ impl PathSource {
71
71
pub fn list_files ( & self , pkg : & Package ) -> CargoResult < Vec < Path > > {
72
72
let root = pkg. get_manifest_path ( ) . dir_path ( ) ;
73
73
74
- // Check whether the package itself is a git repository.
75
- let candidates = match git2:: Repository :: open ( & root) {
76
- Ok ( repo) => try!( self . list_files_git ( pkg, repo) ) ,
74
+ let exclude = pkg. get_manifest ( ) . get_exclude ( ) . iter ( ) . map ( |p| {
75
+ Pattern :: new ( p. as_slice ( ) )
76
+ } ) . collect :: < Vec < Pattern > > ( ) ;
77
+ let include = pkg. get_manifest ( ) . get_include ( ) . iter ( ) . map ( |p| {
78
+ Pattern :: new ( p. as_slice ( ) )
79
+ } ) . collect :: < Vec < Pattern > > ( ) ;
77
80
78
- // If not, check whether the package is in a sub-directory of the main repository.
79
- Err ( ..) if self . path . is_ancestor_of ( & root) => {
80
- match git2:: Repository :: open ( & self . path ) {
81
- Ok ( repo) => try!( self . list_files_git ( pkg, repo) ) ,
82
- _ => try!( self . list_files_walk ( pkg) )
83
- }
81
+ let mut filter = |& mut : p: & Path | {
82
+ let relative_path = p. path_relative_from ( & root) . unwrap ( ) ;
83
+ include. iter ( ) . any ( |p| p. matches_path ( & relative_path) ) || {
84
+ include. len ( ) == 0 &&
85
+ !exclude. iter ( ) . any ( |p| p. matches_path ( & relative_path) )
84
86
}
85
- // If neither is true, fall back to walking the filesystem.
86
- _ => try!( self . list_files_walk ( pkg) )
87
87
} ;
88
88
89
- let pats = pkg. get_manifest ( ) . get_exclude ( ) . iter ( ) . map ( |p| {
90
- Pattern :: new ( p. as_slice ( ) )
91
- } ) . collect :: < Vec < Pattern > > ( ) ;
92
-
93
- Ok ( candidates. into_iter ( ) . filter ( |candidate| {
94
- let relative_path = candidate. path_relative_from ( & root) . unwrap ( ) ;
95
- !pats. iter ( ) . any ( |p| p. matches_path ( & relative_path) ) &&
96
- candidate. is_file ( )
97
- } ) . collect ( ) )
89
+ // If this package is a git repository, then we really do want to query
90
+ // the git repository as it takes into account items such as .gitignore.
91
+ // We're not quite sure where the git repository is, however, so we do a
92
+ // bit of a probe.
93
+ //
94
+ // We check all packages in this source that are ancestors of the
95
+ // specified package (including the same package) to see if they're at
96
+ // the root of the git repository. This isn't always true, but it'll get
97
+ // us there most of the time!.
98
+ let repo = self . packages . iter ( )
99
+ . map ( |pkg| pkg. get_root ( ) )
100
+ . filter ( |path| path. is_ancestor_of ( & root) )
101
+ . filter_map ( |path| git2:: Repository :: open ( & path) . ok ( ) )
102
+ . next ( ) ;
103
+ match repo {
104
+ Some ( repo) => self . list_files_git ( pkg, repo, & mut filter) ,
105
+ None => self . list_files_walk ( pkg, filter) ,
106
+ }
98
107
}
99
108
100
- fn list_files_git ( & self , pkg : & Package , repo : git2:: Repository )
101
- -> CargoResult < Vec < Path > > {
109
+ fn list_files_git < F > ( & self , pkg : & Package , repo : git2:: Repository ,
110
+ filter : & mut F )
111
+ -> CargoResult < Vec < Path > >
112
+ where F : FnMut ( & Path ) -> bool
113
+ {
102
114
warn ! ( "list_files_git {}" , pkg. get_package_id( ) ) ;
103
115
let index = try!( repo. index ( ) ) ;
104
116
let root = match repo. workdir ( ) {
@@ -108,8 +120,7 @@ impl PathSource {
108
120
let pkg_path = pkg. get_manifest_path ( ) . dir_path ( ) ;
109
121
110
122
let mut ret = Vec :: new ( ) ;
111
- ' outer: for i in range ( 0 , index. len ( ) ) {
112
- let entry = match index. get ( i) { Some ( e) => e, None => continue } ;
123
+ ' outer: for entry in index. iter ( ) {
113
124
let fname = entry. path . as_bytes_no_nul ( ) ;
114
125
let file_path = root. join ( fname) ;
115
126
@@ -123,30 +134,52 @@ impl PathSource {
123
134
// Filter out sub-packages of this package
124
135
for other_pkg in self . packages . iter ( ) . filter ( |p| * p != pkg) {
125
136
let other_path = other_pkg. get_manifest_path ( ) . dir_path ( ) ;
126
- if pkg_path. is_ancestor_of ( & other_path) && other_path. is_ancestor_of ( & file_path) {
137
+ if pkg_path. is_ancestor_of ( & other_path) &&
138
+ other_path. is_ancestor_of ( & file_path) {
127
139
continue ' outer;
128
140
}
129
141
}
130
142
131
- // We found a file!
132
- warn ! ( " found {}" , file_path. display( ) ) ;
133
- ret. push ( file_path) ;
143
+ // TODO: the `entry` has a mode we should be able to look at instead
144
+ // of just calling stat() again
145
+ if file_path. is_dir ( ) {
146
+ warn ! ( " found submodule {}" , file_path. display( ) ) ;
147
+ let rel = file_path. path_relative_from ( & root) . unwrap ( ) ;
148
+ let rel = try!( rel. as_str ( ) . chain_error ( || {
149
+ human ( format ! ( "invalid utf-8 filename: {}" , rel. display( ) ) )
150
+ } ) ) ;
151
+ let submodule = try!( repo. find_submodule ( rel) ) ;
152
+ let repo = try!( submodule. open ( ) ) ;
153
+ let files = try!( self . list_files_git ( pkg, repo, filter) ) ;
154
+ ret. extend ( files. into_iter ( ) ) ;
155
+ } else if ( * filter) ( & file_path) {
156
+ // We found a file!
157
+ warn ! ( " found {}" , file_path. display( ) ) ;
158
+ ret. push ( file_path) ;
159
+ }
134
160
}
135
161
Ok ( ret)
136
162
}
137
163
138
- fn list_files_walk ( & self , pkg : & Package ) -> CargoResult < Vec < Path > > {
164
+ fn list_files_walk < F > ( & self , pkg : & Package , mut filter : F )
165
+ -> CargoResult < Vec < Path > >
166
+ where F : FnMut ( & Path ) -> bool
167
+ {
139
168
let mut ret = Vec :: new ( ) ;
140
169
for pkg in self . packages . iter ( ) . filter ( |p| * p == pkg) {
141
170
let loc = pkg. get_manifest_path ( ) . dir_path ( ) ;
142
- try!( walk ( & loc, & mut ret, true ) ) ;
171
+ try!( walk ( & loc, & mut ret, true , & mut filter ) ) ;
143
172
}
144
173
return Ok ( ret) ;
145
174
146
- fn walk ( path : & Path , ret : & mut Vec < Path > ,
147
- is_root : bool ) -> CargoResult < ( ) > {
175
+ fn walk < F > ( path : & Path , ret : & mut Vec < Path > ,
176
+ is_root : bool , filter : & mut F ) -> CargoResult < ( ) >
177
+ where F : FnMut ( & Path ) -> bool
178
+ {
148
179
if !path. is_dir ( ) {
149
- ret. push ( path. clone ( ) ) ;
180
+ if ( * filter) ( path) {
181
+ ret. push ( path. clone ( ) ) ;
182
+ }
150
183
return Ok ( ( ) )
151
184
}
152
185
// Don't recurse into any sub-packages that we have
@@ -158,7 +191,7 @@ impl PathSource {
158
191
( true , Some ( "Cargo.lock" ) ) => continue ,
159
192
_ => { }
160
193
}
161
- try!( walk ( dir, ret, false ) ) ;
194
+ try!( walk ( dir, ret, false , filter ) ) ;
162
195
}
163
196
return Ok ( ( ) )
164
197
}
0 commit comments