@@ -79,10 +79,10 @@ pub struct DependencyGraph {
79
79
/// `DependencyMode::Always` edges in `package_graph`).
80
80
pub always_deps : BTreeSet < PM :: PackageName > ,
81
81
82
- /// A hash of the manifest file content this lock file was generated from, if any .
83
- pub manifest_digest : Option < String > ,
84
- /// A hash of all the dependencies (their lock file content) this lock file depends on, if any .
85
- pub deps_digest : Option < String > ,
82
+ /// A hash of the manifest file content this lock file was generated from.
83
+ pub manifest_digest : String ,
84
+ /// A hash of all the dependencies (their lock file content) this lock file depends on.
85
+ pub deps_digest : String ,
86
86
}
87
87
88
88
/// A helper to store additional information about a dependency graph
@@ -163,88 +163,52 @@ pub struct DependencyGraphBuilder<Progress: Write> {
163
163
pub progress_output : Progress ,
164
164
/// A chain of visited dependencies used for cycle detection
165
165
visited_dependencies : VecDeque < ( PM :: PackageName , PM :: InternalDependency ) > ,
166
+ /// Installation directory for compiled artifacts (from BuildConfig).
167
+ install_dir : PathBuf ,
166
168
}
167
169
168
170
impl < Progress : Write > DependencyGraphBuilder < Progress > {
169
- pub fn new ( skip_fetch_latest_git_deps : bool , progress_output : Progress ) -> Self {
171
+ pub fn new (
172
+ skip_fetch_latest_git_deps : bool ,
173
+ progress_output : Progress ,
174
+ install_dir : PathBuf ,
175
+ ) -> Self {
170
176
DependencyGraphBuilder {
171
177
dependency_cache : DependencyCache :: new ( skip_fetch_latest_git_deps) ,
172
178
progress_output,
173
179
visited_dependencies : VecDeque :: new ( ) ,
180
+ install_dir,
174
181
}
175
182
}
176
183
177
- /// Get a graph from the Move.lock file, if Move.lock file is present and up-to-date
178
- /// (additionally returning false), otherwise compute a new graph based on the content of the
179
- /// Move.toml (manifest) file (additionally returning true).
184
+ /// Get a new graph by either reading it from Move.lock file ( if this file is up-to-date, in
185
+ /// which case also return false) or by computing a new graph based on the content of the
186
+ /// Move.toml (manifest) file (in which case also return true).
180
187
pub fn get_graph (
181
188
& mut self ,
182
189
parent : & PM :: DependencyKind ,
183
190
root_path : PathBuf ,
184
191
manifest_string : String ,
185
- lock_string : Option < String > ,
192
+ lock_string_opt : Option < String > ,
186
193
) -> Result < ( DependencyGraph , bool ) > {
187
194
let toml_manifest = parse_move_manifest_string ( manifest_string. clone ( ) ) ?;
188
- let manifest = parse_source_manifest ( toml_manifest) ?;
195
+ let root_manifest = parse_source_manifest ( toml_manifest) ?;
189
196
190
197
// compute digests eagerly as even if we can't reuse existing lock file, they need to become
191
198
// part of the newly computed dependency graph
192
- let new_manifest_digest_opt = Some ( digest_str ( manifest_string. into_bytes ( ) . as_slice ( ) ) ) ;
193
-
194
- let new_deps_digest_opt = self . dependency_digest ( root_path. clone ( ) , & manifest) ?;
195
- if let Some ( lock_contents) = lock_string {
196
- let schema:: Header {
197
- version : _,
198
- manifest_digest : manifest_digest_opt,
199
- deps_digest : deps_digest_opt,
200
- } = schema:: read_header ( & lock_contents) ?;
201
-
202
- // check if manifest file and dependencies haven't changed and we can use existing lock
203
- // file to create the dependency graph
204
- if new_manifest_digest_opt == manifest_digest_opt {
205
- // manifest file hasn't changed
206
- if let Some ( deps_digest) = deps_digest_opt {
207
- // dependencies digest exists in the lock file
208
- if Some ( deps_digest) == new_deps_digest_opt {
209
- // dependencies have not changed
210
- return Ok ( (
211
- DependencyGraph :: read_from_lock (
212
- root_path,
213
- manifest. package . name ,
214
- & mut lock_contents. as_bytes ( ) ,
215
- None ,
216
- ) ?,
217
- false ,
218
- ) ) ;
219
- }
220
- }
221
- }
222
- }
223
-
224
- Ok ( (
225
- self . new_graph (
226
- parent,
227
- & manifest,
228
- root_path,
229
- new_manifest_digest_opt,
230
- new_deps_digest_opt,
231
- ) ?,
232
- true ,
233
- ) )
234
- }
199
+ let new_manifest_digest = digest_str ( manifest_string. into_bytes ( ) . as_slice ( ) ) ;
200
+ let ( old_manifest_digest_opt, old_deps_digest_opt, lock_string) = match lock_string_opt {
201
+ Some ( lock_string) => match schema:: read_header ( & lock_string) {
202
+ Ok ( header) => (
203
+ Some ( header. manifest_digest ) ,
204
+ Some ( header. deps_digest ) ,
205
+ Some ( lock_string) ,
206
+ ) ,
207
+ Err ( _) => ( None , None , None ) , // malformed header - regenerate lock file
208
+ } ,
209
+ None => ( None , None , None ) ,
210
+ } ;
235
211
236
- /// Build a graph from the transitive dependencies and dev-dependencies of `root_package`.
237
- ///
238
- /// `progress_output` is an output stream that is written to while generating the graph, to
239
- /// provide human-readable progress updates.
240
- pub fn new_graph (
241
- & mut self ,
242
- parent : & PM :: DependencyKind ,
243
- root_manifest : & PM :: SourceManifest ,
244
- root_path : PathBuf ,
245
- manifest_digest : Option < String > ,
246
- deps_digest : Option < String > ,
247
- ) -> Result < DependencyGraph > {
248
212
// collect sub-graphs for "regular" and "dev" dependencies
249
213
let mut dep_graphs = self . collect_graphs (
250
214
parent,
@@ -253,6 +217,10 @@ impl<Progress: Write> DependencyGraphBuilder<Progress> {
253
217
DependencyMode :: Always ,
254
218
& root_manifest. dependencies ,
255
219
) ?;
220
+ let dep_lock_files = dep_graphs
221
+ . values ( )
222
+ . map ( |graph_info| graph_info. g . write_to_lock ( self . install_dir . clone ( ) ) )
223
+ . collect :: < Result < Vec < LockFile > > > ( ) ?;
256
224
let dev_dep_graphs = self . collect_graphs (
257
225
parent,
258
226
root_manifest. package . name ,
@@ -261,6 +229,30 @@ impl<Progress: Write> DependencyGraphBuilder<Progress> {
261
229
& root_manifest. dev_dependencies ,
262
230
) ?;
263
231
232
+ let dev_dep_lock_files = dev_dep_graphs
233
+ . values ( )
234
+ . map ( |graph_info| graph_info. g . write_to_lock ( self . install_dir . clone ( ) ) )
235
+ . collect :: < Result < Vec < LockFile > > > ( ) ?;
236
+ let new_deps_digest = self . dependency_digest ( dep_lock_files, dev_dep_lock_files) ?;
237
+ let ( manifest_digest, deps_digest) =
238
+ match ( old_manifest_digest_opt, old_deps_digest_opt, lock_string) {
239
+ ( Some ( old_manifest_digest) , Some ( old_deps_digest) , Some ( lock_string) )
240
+ if old_manifest_digest == new_manifest_digest
241
+ && old_deps_digest == new_deps_digest =>
242
+ {
243
+ return Ok ( (
244
+ DependencyGraph :: read_from_lock (
245
+ root_path,
246
+ root_manifest. package . name ,
247
+ & mut lock_string. as_bytes ( ) , // safe since old_deps_digest exists
248
+ None ,
249
+ ) ?,
250
+ false ,
251
+ ) ) ;
252
+ }
253
+ _ => ( new_manifest_digest, new_deps_digest) ,
254
+ } ;
255
+
264
256
dep_graphs. extend ( dev_dep_graphs) ;
265
257
266
258
let mut combined_graph = DependencyGraph {
@@ -309,7 +301,7 @@ impl<Progress: Write> DependencyGraphBuilder<Progress> {
309
301
combined_graph. check_acyclic ( ) ?;
310
302
combined_graph. discover_always_deps ( ) ;
311
303
312
- Ok ( combined_graph)
304
+ Ok ( ( combined_graph, true ) )
313
305
}
314
306
315
307
/// Given all dependencies from the parent manifest file, collects all the sub-graphs
@@ -405,66 +397,33 @@ impl<Progress: Write> DependencyGraphBuilder<Progress> {
405
397
Ok ( ( pkg_graph, is_override, is_external) )
406
398
}
407
399
408
- /// Computes dependency hashes but may return None if information about some dependencies is not
409
- /// available or if there are no dependencies.
410
- fn dependency_hashes (
411
- & mut self ,
412
- root_path : PathBuf ,
413
- dependencies : & PM :: Dependencies ,
414
- ) -> Result < Option < Vec < String > > > {
400
+ /// Computes dependency hashes.
401
+ fn dependency_hashes ( & mut self , lock_files : Vec < LockFile > ) -> Result < Vec < String > > {
415
402
let mut hashed_lock_files = Vec :: new ( ) ;
416
-
417
- for ( pkg_name, dep) in dependencies {
418
- let internal_dep = match dep {
419
- // bail if encountering external dependency that would require running the external
420
- // resolver
421
- // TODO: should we consider handling this here?
422
- PM :: Dependency :: External ( _) => return Ok ( None ) ,
423
- PM :: Dependency :: Internal ( d) => d,
424
- } ;
425
-
426
- self . dependency_cache
427
- . download_and_update_if_remote (
428
- * pkg_name,
429
- & internal_dep. kind ,
430
- & mut self . progress_output ,
431
- )
432
- . with_context ( || format ! ( "Fetching '{}'" , * pkg_name) ) ?;
433
- let pkg_path = root_path. join ( local_path ( & internal_dep. kind ) ) ;
434
-
435
- let Ok ( lock_contents) = std:: fs:: read_to_string ( pkg_path. join ( SourcePackageLayout :: Lock . path ( ) ) ) else {
436
- return Ok ( None ) ;
437
- } ;
438
- hashed_lock_files. push ( digest_str ( lock_contents. as_bytes ( ) ) ) ;
403
+ for mut lock_file in lock_files {
404
+ let mut lock_string: String = "" . to_string ( ) ;
405
+ lock_file. read_to_string ( & mut lock_string) ?;
406
+ hashed_lock_files. push ( digest_str ( lock_string. as_bytes ( ) ) ) ;
439
407
}
440
-
441
- Ok ( if hashed_lock_files. is_empty ( ) {
442
- None
443
- } else {
444
- Some ( hashed_lock_files)
445
- } )
408
+ Ok ( hashed_lock_files)
446
409
}
447
410
448
- /// Computes a digest of all dependencies in a manifest file but may return None if information
449
- /// about some dependencies is not available .
411
+ /// Computes a digest of all dependencies in a manifest file (or digest of empty list if there
412
+ /// are no dependencies) .
450
413
fn dependency_digest (
451
414
& mut self ,
452
- root_path : PathBuf ,
453
- manifest : & PM :: SourceManifest ,
454
- ) -> Result < Option < String > > {
455
- let mut dep_hashes = self
456
- . dependency_hashes ( root_path. clone ( ) , & manifest. dependencies ) ?
457
- . unwrap_or_default ( ) ;
458
-
459
- let dev_dep_hashes = self
460
- . dependency_hashes ( root_path, & manifest. dev_dependencies ) ?
461
- . unwrap_or_default ( ) ;
462
-
463
- if dep_hashes. is_empty ( ) {
464
- Ok ( None )
415
+ dep_lock_files : Vec < LockFile > ,
416
+ dev_dep_lock_files : Vec < LockFile > ,
417
+ ) -> Result < String > {
418
+ let mut dep_hashes = self . dependency_hashes ( dep_lock_files) ?;
419
+
420
+ let dev_dep_hashes = self . dependency_hashes ( dev_dep_lock_files) ?;
421
+
422
+ if dep_hashes. is_empty ( ) && dev_dep_hashes. is_empty ( ) {
423
+ Ok ( digest_str ( & [ ] ) )
465
424
} else {
466
425
dep_hashes. extend ( dev_dep_hashes) ;
467
- Ok ( Some ( hashed_files_digest ( dep_hashes) ) )
426
+ Ok ( hashed_files_digest ( dep_hashes) )
468
427
}
469
428
}
470
429
}
0 commit comments