@@ -20,13 +20,9 @@ use ignore::gitignore::GitignoreBuilder;
20
20
use tracing:: { debug, trace, warn} ;
21
21
use walkdir:: WalkDir ;
22
22
23
- /// A source represents one or multiple packages gathering from a given root
23
+ /// A source that represents a package gathered at the root
24
24
/// path on the filesystem.
25
25
///
26
- /// It's the cornerstone of every other source --- other implementations
27
- /// eventually need to call `PathSource` to read local packages somewhere on
28
- /// the filesystem.
29
- ///
30
26
/// It also provides convenient methods like [`PathSource::list_files`] to
31
27
/// list all files in a package, given its ability to walk the filesystem.
32
28
pub struct PathSource < ' gctx > {
@@ -39,7 +35,6 @@ pub struct PathSource<'gctx> {
39
35
/// Packages that this sources has discovered.
40
36
packages : Vec < Package > ,
41
37
/// Whether this source should discover nested packages recursively.
42
- /// See [`PathSource::new_recursive`] for more.
43
38
recursive : bool ,
44
39
gctx : & ' gctx GlobalContext ,
45
40
}
@@ -60,6 +55,191 @@ impl<'gctx> PathSource<'gctx> {
60
55
}
61
56
}
62
57
58
+ /// Preloads a package for this source. The source is assumed that it has
59
+ /// yet loaded any other packages.
60
+ pub fn preload_with ( & mut self , pkg : Package ) {
61
+ assert ! ( !self . updated) ;
62
+ assert ! ( !self . recursive) ;
63
+ assert ! ( self . packages. is_empty( ) ) ;
64
+ self . updated = true ;
65
+ self . packages . push ( pkg) ;
66
+ }
67
+
68
+ /// Gets the package on the root path.
69
+ pub fn root_package ( & mut self ) -> CargoResult < Package > {
70
+ trace ! ( "root_package; source={:?}" , self ) ;
71
+
72
+ self . update ( ) ?;
73
+
74
+ match self . packages . iter ( ) . find ( |p| p. root ( ) == & * self . path ) {
75
+ Some ( pkg) => Ok ( pkg. clone ( ) ) ,
76
+ None => Err ( internal ( format ! (
77
+ "no package found in source {:?}" ,
78
+ self . path
79
+ ) ) ) ,
80
+ }
81
+ }
82
+
83
+ /// Returns the packages discovered by this source. It may walk the
84
+ /// filesystem if package information haven't yet updated.
85
+ pub fn read_packages ( & self ) -> CargoResult < Vec < Package > > {
86
+ if self . updated {
87
+ Ok ( self . packages . clone ( ) )
88
+ } else if self . recursive {
89
+ ops:: read_packages ( & self . path , self . source_id , self . gctx )
90
+ } else {
91
+ let path = self . path . join ( "Cargo.toml" ) ;
92
+ let pkg = ops:: read_package ( & path, self . source_id , self . gctx ) ?;
93
+ Ok ( vec ! [ pkg] )
94
+ }
95
+ }
96
+
97
+ /// List all files relevant to building this package inside this source.
98
+ ///
99
+ /// This function will use the appropriate methods to determine the
100
+ /// set of files underneath this source's directory which are relevant for
101
+ /// building `pkg`.
102
+ ///
103
+ /// The basic assumption of this method is that all files in the directory
104
+ /// are relevant for building this package, but it also contains logic to
105
+ /// use other methods like `.gitignore`, `package.include`, or
106
+ /// `package.exclude` to filter the list of files.
107
+ pub fn list_files ( & self , pkg : & Package ) -> CargoResult < Vec < PathBuf > > {
108
+ list_files ( pkg, self . gctx )
109
+ }
110
+
111
+ /// Gets the last modified file in a package.
112
+ pub fn last_modified_file ( & self , pkg : & Package ) -> CargoResult < ( FileTime , PathBuf ) > {
113
+ if !self . updated {
114
+ return Err ( internal ( format ! (
115
+ "BUG: source `{:?}` was not updated" ,
116
+ self . path
117
+ ) ) ) ;
118
+ }
119
+ last_modified_file ( & self . path , pkg, self . gctx )
120
+ }
121
+
122
+ /// Returns the root path of this source.
123
+ pub fn path ( & self ) -> & Path {
124
+ & self . path
125
+ }
126
+
127
+ /// Discovers packages inside this source if it hasn't yet done.
128
+ pub fn update ( & mut self ) -> CargoResult < ( ) > {
129
+ if !self . updated {
130
+ let packages = self . read_packages ( ) ?;
131
+ self . packages . extend ( packages. into_iter ( ) ) ;
132
+ self . updated = true ;
133
+ }
134
+
135
+ Ok ( ( ) )
136
+ }
137
+ }
138
+
139
+ impl < ' gctx > Debug for PathSource < ' gctx > {
140
+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
141
+ write ! ( f, "the paths source" )
142
+ }
143
+ }
144
+
145
+ impl < ' gctx > Source for PathSource < ' gctx > {
146
+ fn query (
147
+ & mut self ,
148
+ dep : & Dependency ,
149
+ kind : QueryKind ,
150
+ f : & mut dyn FnMut ( IndexSummary ) ,
151
+ ) -> Poll < CargoResult < ( ) > > {
152
+ self . update ( ) ?;
153
+ for s in self . packages . iter ( ) . map ( |p| p. summary ( ) ) {
154
+ let matched = match kind {
155
+ QueryKind :: Exact => dep. matches ( s) ,
156
+ QueryKind :: Alternatives => true ,
157
+ QueryKind :: Normalized => dep. matches ( s) ,
158
+ } ;
159
+ if matched {
160
+ f ( IndexSummary :: Candidate ( s. clone ( ) ) )
161
+ }
162
+ }
163
+ Poll :: Ready ( Ok ( ( ) ) )
164
+ }
165
+
166
+ fn supports_checksums ( & self ) -> bool {
167
+ false
168
+ }
169
+
170
+ fn requires_precise ( & self ) -> bool {
171
+ false
172
+ }
173
+
174
+ fn source_id ( & self ) -> SourceId {
175
+ self . source_id
176
+ }
177
+
178
+ fn download ( & mut self , id : PackageId ) -> CargoResult < MaybePackage > {
179
+ trace ! ( "getting packages; id={}" , id) ;
180
+ self . update ( ) ?;
181
+ let pkg = self . packages . iter ( ) . find ( |pkg| pkg. package_id ( ) == id) ;
182
+ pkg. cloned ( )
183
+ . map ( MaybePackage :: Ready )
184
+ . ok_or_else ( || internal ( format ! ( "failed to find {} in path source" , id) ) )
185
+ }
186
+
187
+ fn finish_download ( & mut self , _id : PackageId , _data : Vec < u8 > ) -> CargoResult < Package > {
188
+ panic ! ( "no download should have started" )
189
+ }
190
+
191
+ fn fingerprint ( & self , pkg : & Package ) -> CargoResult < String > {
192
+ let ( max, max_path) = self . last_modified_file ( pkg) ?;
193
+ // Note that we try to strip the prefix of this package to get a
194
+ // relative path to ensure that the fingerprint remains consistent
195
+ // across entire project directory renames.
196
+ let max_path = max_path. strip_prefix ( & self . path ) . unwrap_or ( & max_path) ;
197
+ Ok ( format ! ( "{} ({})" , max, max_path. display( ) ) )
198
+ }
199
+
200
+ fn describe ( & self ) -> String {
201
+ match self . source_id . url ( ) . to_file_path ( ) {
202
+ Ok ( path) => path. display ( ) . to_string ( ) ,
203
+ Err ( _) => self . source_id . to_string ( ) ,
204
+ }
205
+ }
206
+
207
+ fn add_to_yanked_whitelist ( & mut self , _pkgs : & [ PackageId ] ) { }
208
+
209
+ fn is_yanked ( & mut self , _pkg : PackageId ) -> Poll < CargoResult < bool > > {
210
+ Poll :: Ready ( Ok ( false ) )
211
+ }
212
+
213
+ fn block_until_ready ( & mut self ) -> CargoResult < ( ) > {
214
+ self . update ( )
215
+ }
216
+
217
+ fn invalidate_cache ( & mut self ) {
218
+ // Path source has no local cache.
219
+ }
220
+
221
+ fn set_quiet ( & mut self , _quiet : bool ) {
222
+ // Path source does not display status
223
+ }
224
+ }
225
+
226
+ /// A source that represents one or multiple packages gathered from a given root
227
+ /// path on the filesystem.
228
+ pub struct RecursivePathSource < ' gctx > {
229
+ /// The unique identifier of this source.
230
+ source_id : SourceId ,
231
+ /// The root path of this source.
232
+ path : PathBuf ,
233
+ /// Whether this source has updated all package information it may contain.
234
+ updated : bool ,
235
+ /// Packages that this sources has discovered.
236
+ packages : Vec < Package > ,
237
+ /// Whether this source should discover nested packages recursively.
238
+ recursive : bool ,
239
+ gctx : & ' gctx GlobalContext ,
240
+ }
241
+
242
+ impl < ' gctx > RecursivePathSource < ' gctx > {
63
243
/// Creates a new source which is walked recursively to discover packages.
64
244
///
65
245
/// This is similar to the [`PathSource::new`] method except that instead
@@ -68,10 +248,14 @@ impl<'gctx> PathSource<'gctx> {
68
248
///
69
249
/// Note that this should be used with care and likely shouldn't be chosen
70
250
/// by default!
71
- pub fn new_recursive ( root : & Path , id : SourceId , gctx : & ' gctx GlobalContext ) -> Self {
251
+ pub fn new ( root : & Path , source_id : SourceId , gctx : & ' gctx GlobalContext ) -> Self {
72
252
Self {
253
+ source_id,
254
+ path : root. to_path_buf ( ) ,
255
+ updated : false ,
256
+ packages : Vec :: new ( ) ,
257
+ gctx,
73
258
recursive : true ,
74
- ..Self :: new ( root, id, gctx)
75
259
}
76
260
}
77
261
@@ -156,13 +340,13 @@ impl<'gctx> PathSource<'gctx> {
156
340
}
157
341
}
158
342
159
- impl < ' gctx > Debug for PathSource < ' gctx > {
343
+ impl < ' gctx > Debug for RecursivePathSource < ' gctx > {
160
344
fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
161
345
write ! ( f, "the paths source" )
162
346
}
163
347
}
164
348
165
- impl < ' gctx > Source for PathSource < ' gctx > {
349
+ impl < ' gctx > Source for RecursivePathSource < ' gctx > {
166
350
fn query (
167
351
& mut self ,
168
352
dep : & Dependency ,
0 commit comments