1
1
#![ allow( clippy:: print_stderr) ]
2
2
3
- use std:: cell:: RefCell ;
4
3
use std:: cmp:: { max, min} ;
5
4
use std:: collections:: { BTreeMap , HashMap , HashSet } ;
6
5
use std:: fmt;
7
6
use std:: fmt:: Write ;
8
- use std:: rc:: Rc ;
9
7
use std:: sync:: OnceLock ;
10
8
use std:: task:: Poll ;
11
9
use std:: time:: Instant ;
@@ -19,7 +17,6 @@ use cargo::core::{GitReference, SourceId};
19
17
use cargo:: sources:: source:: QueryKind ;
20
18
use cargo:: sources:: IndexSummary ;
21
19
use cargo:: util:: { CargoResult , GlobalContext , IntoUrl } ;
22
- use cargo_util_schemas:: manifest:: RustVersion ;
23
20
24
21
use proptest:: collection:: { btree_map, vec} ;
25
22
use proptest:: prelude:: * ;
@@ -35,18 +32,17 @@ pub fn resolve(deps: Vec<Dependency>, registry: &[Summary]) -> CargoResult<Vec<P
35
32
pub fn resolve_and_validated (
36
33
deps : Vec < Dependency > ,
37
34
registry : & [ Summary ] ,
38
- sat_resolve : Option < SatResolve > ,
35
+ sat_resolver : & mut SatResolver ,
39
36
) -> CargoResult < Vec < PackageId > > {
40
37
let resolve =
41
38
resolve_with_global_context_raw ( deps. clone ( ) , registry, & GlobalContext :: default ( ) . unwrap ( ) ) ;
42
39
43
40
match resolve {
44
41
Err ( e) => {
45
- let sat_resolve = sat_resolve. unwrap_or_else ( || SatResolve :: new ( registry) ) ;
46
- if sat_resolve. sat_resolve ( & deps) {
42
+ if sat_resolver. sat_resolve ( & deps) {
47
43
panic ! (
48
- "the resolve err but the sat_resolve thinks this will work:\n {}" ,
49
- sat_resolve . use_packages ( ) . unwrap( )
44
+ "` resolve()` returned an error but the sat resolver thinks this will work:\n {}" ,
45
+ sat_resolver . used_packages ( ) . unwrap( )
50
46
) ;
51
47
}
52
48
Err ( e)
@@ -73,11 +69,10 @@ pub fn resolve_and_validated(
73
69
let out = resolve. sort ( ) ;
74
70
assert_eq ! ( out. len( ) , used. len( ) ) ;
75
71
76
- let sat_resolve = sat_resolve. unwrap_or_else ( || SatResolve :: new ( registry) ) ;
77
- if !sat_resolve. sat_is_valid_solution ( & out) {
72
+ if !sat_resolver. sat_is_valid_solution ( & out) {
78
73
panic ! (
79
- "the sat_resolve err but the resolve thinks this will work: \n {:?}" ,
80
- resolve
74
+ "` resolve()` thinks this will work, but the solution is \
75
+ invalid according to the sat resolver: \n { resolve:?}" ,
81
76
) ;
82
77
}
83
78
Ok ( out)
@@ -158,31 +153,35 @@ pub fn resolve_with_global_context_raw(
158
153
list : registry,
159
154
used : HashSet :: new ( ) ,
160
155
} ;
161
- let summary = Summary :: new (
156
+
157
+ let root_summary = Summary :: new (
162
158
pkg_id ( "root" ) ,
163
159
deps,
164
160
& BTreeMap :: new ( ) ,
165
161
None :: < & String > ,
166
- None :: < RustVersion > ,
162
+ None ,
167
163
)
168
164
. unwrap ( ) ;
165
+
169
166
let opts = ResolveOpts :: everything ( ) ;
167
+
170
168
let start = Instant :: now ( ) ;
171
169
let mut version_prefs = VersionPreferences :: default ( ) ;
172
170
if gctx. cli_unstable ( ) . minimal_versions {
173
171
version_prefs. version_ordering ( VersionOrdering :: MinimumVersionsFirst )
174
172
}
173
+
175
174
let resolve = resolver:: resolve (
176
- & [ ( summary , opts) ] ,
175
+ & [ ( root_summary , opts) ] ,
177
176
& [ ] ,
178
177
& mut registry,
179
178
& version_prefs,
180
179
ResolveVersion :: with_rust_version ( None ) ,
181
180
Some ( gctx) ,
182
181
) ;
183
182
184
- // The largest test in our suite takes less then 30 sec .
185
- // So lets fail the test if we have ben running for two long .
183
+ // The largest test in our suite takes less then 30 secs .
184
+ // So let's fail the test if we have been running for more than 60 secs .
186
185
assert ! ( start. elapsed( ) . as_secs( ) < 60 ) ;
187
186
resolve
188
187
}
@@ -249,18 +248,15 @@ fn sat_at_most_one_by_key<K: std::hash::Hash + Eq>(
249
248
/// find a valid resolution if one exists. The big thing that the real resolver does,
250
249
/// that this one does not do is work with features and optional dependencies.
251
250
///
252
- /// The SAT library dose not optimize for the newer version,
251
+ /// The SAT library does not optimize for the newer version,
253
252
/// so the selected packages may not match the real resolver.
254
- #[ derive( Clone ) ]
255
- pub struct SatResolve ( Rc < RefCell < SatResolveInner > > ) ;
256
-
257
- struct SatResolveInner {
253
+ pub struct SatResolver {
258
254
solver : varisat:: Solver < ' static > ,
259
255
var_for_is_packages_used : HashMap < PackageId , varisat:: Var > ,
260
256
by_name : HashMap < & ' static str , Vec < PackageId > > ,
261
257
}
262
258
263
- impl SatResolve {
259
+ impl SatResolver {
264
260
pub fn new ( registry : & [ Summary ] ) -> Self {
265
261
let mut cnf = varisat:: CnfFormula :: new ( ) ;
266
262
// That represents each package version which is set to "true" if the packages in the lock file and "false" if it is unused.
@@ -325,79 +321,81 @@ impl SatResolve {
325
321
solver
326
322
. solve ( )
327
323
. expect ( "docs say it can't error in default config" ) ;
328
- SatResolve ( Rc :: new ( RefCell :: new ( SatResolveInner {
324
+
325
+ SatResolver {
329
326
solver,
330
327
var_for_is_packages_used,
331
328
by_name,
332
- } ) ) )
329
+ }
333
330
}
334
- pub fn sat_resolve ( & self , deps : & [ Dependency ] ) -> bool {
335
- let mut s = self . 0 . borrow_mut ( ) ;
331
+
332
+ pub fn sat_resolve ( & mut self , root_dependencies : & [ Dependency ] ) -> bool {
336
333
let mut assumption = vec ! [ ] ;
337
334
let mut this_call = None ;
338
335
339
336
// the starting `deps` need to be satisfied
340
- for dep in deps . iter ( ) {
337
+ for dep in root_dependencies {
341
338
let empty_vec = vec ! [ ] ;
342
- let matches: Vec < varisat:: Lit > = s
339
+ let matches: Vec < varisat:: Lit > = self
343
340
. by_name
344
341
. get ( dep. package_name ( ) . as_str ( ) )
345
342
. unwrap_or ( & empty_vec)
346
343
. iter ( )
347
344
. filter ( |& p| dep. matches_id ( * p) )
348
- . map ( |p| s . var_for_is_packages_used [ p] . positive ( ) )
345
+ . map ( |p| self . var_for_is_packages_used [ p] . positive ( ) )
349
346
. collect ( ) ;
350
347
if matches. is_empty ( ) {
351
348
return false ;
352
349
} else if matches. len ( ) == 1 {
353
350
assumption. extend_from_slice ( & matches)
354
351
} else {
355
352
if this_call. is_none ( ) {
356
- let new_var = s . solver . new_var ( ) ;
353
+ let new_var = self . solver . new_var ( ) ;
357
354
this_call = Some ( new_var) ;
358
355
assumption. push ( new_var. positive ( ) ) ;
359
356
}
360
357
let mut matches = matches;
361
358
matches. push ( this_call. unwrap ( ) . negative ( ) ) ;
362
- s . solver . add_clause ( & matches) ;
359
+ self . solver . add_clause ( & matches) ;
363
360
}
364
361
}
365
362
366
- s . solver . assume ( & assumption) ;
363
+ self . solver . assume ( & assumption) ;
367
364
368
- s . solver
365
+ self . solver
369
366
. solve ( )
370
367
. expect ( "docs say it can't error in default config" )
371
368
}
372
- pub fn sat_is_valid_solution ( & self , pids : & [ PackageId ] ) -> bool {
373
- let mut s = self . 0 . borrow_mut ( ) ;
369
+
370
+ pub fn sat_is_valid_solution ( & mut self , pids : & [ PackageId ] ) -> bool {
374
371
for p in pids {
375
- if p. name ( ) . as_str ( ) != "root" && !s . var_for_is_packages_used . contains_key ( p) {
372
+ if p. name ( ) . as_str ( ) != "root" && !self . var_for_is_packages_used . contains_key ( p) {
376
373
return false ;
377
374
}
378
375
}
379
- let assumption: Vec < _ > = s
376
+ let assumption: Vec < _ > = self
380
377
. var_for_is_packages_used
381
378
. iter ( )
382
379
. map ( |( p, v) | v. lit ( pids. contains ( p) ) )
383
380
. collect ( ) ;
384
381
385
- s . solver . assume ( & assumption) ;
382
+ self . solver . assume ( & assumption) ;
386
383
387
- s . solver
384
+ self . solver
388
385
. solve ( )
389
386
. expect ( "docs say it can't error in default config" )
390
387
}
391
- fn use_packages ( & self ) -> Option < String > {
392
- self . 0 . borrow ( ) . solver . model ( ) . map ( |lits| {
388
+
389
+ fn used_packages ( & self ) -> Option < String > {
390
+ self . solver . model ( ) . map ( |lits| {
393
391
let lits: HashSet < _ > = lits
394
392
. iter ( )
395
393
. filter ( |l| l. is_positive ( ) )
396
394
. map ( |l| l. var ( ) )
397
395
. collect ( ) ;
398
396
let mut out = String :: new ( ) ;
399
397
out. push_str ( "used:\n " ) ;
400
- for ( p, v) in self . 0 . borrow ( ) . var_for_is_packages_used . iter ( ) {
398
+ for ( p, v) in self . var_for_is_packages_used . iter ( ) {
401
399
if lits. contains ( v) {
402
400
writeln ! ( & mut out, " {}" , p) . unwrap ( ) ;
403
401
}
@@ -409,18 +407,40 @@ impl SatResolve {
409
407
410
408
pub trait ToDep {
411
409
fn to_dep ( self ) -> Dependency ;
410
+ fn to_opt_dep ( self ) -> Dependency ;
411
+ fn to_dep_with ( self , features : & [ & ' static str ] ) -> Dependency ;
412
412
}
413
413
414
414
impl ToDep for & ' static str {
415
415
fn to_dep ( self ) -> Dependency {
416
416
Dependency :: parse ( self , Some ( "1.0.0" ) , registry_loc ( ) ) . unwrap ( )
417
417
}
418
+ fn to_opt_dep ( self ) -> Dependency {
419
+ let mut dep = self . to_dep ( ) ;
420
+ dep. set_optional ( true ) ;
421
+ dep
422
+ }
423
+ fn to_dep_with ( self , features : & [ & ' static str ] ) -> Dependency {
424
+ let mut dep = self . to_dep ( ) ;
425
+ dep. set_default_features ( false ) ;
426
+ dep. set_features ( features. into_iter ( ) . copied ( ) ) ;
427
+ dep
428
+ }
418
429
}
419
430
420
431
impl ToDep for Dependency {
421
432
fn to_dep ( self ) -> Dependency {
422
433
self
423
434
}
435
+ fn to_opt_dep ( mut self ) -> Dependency {
436
+ self . set_optional ( true ) ;
437
+ self
438
+ }
439
+ fn to_dep_with ( mut self , features : & [ & ' static str ] ) -> Dependency {
440
+ self . set_default_features ( false ) ;
441
+ self . set_features ( features. into_iter ( ) . copied ( ) ) ;
442
+ self
443
+ }
424
444
}
425
445
426
446
pub trait ToPkgId {
@@ -448,8 +468,8 @@ impl<T: AsRef<str>, U: AsRef<str>> ToPkgId for (T, U) {
448
468
449
469
#[ macro_export]
450
470
macro_rules! pkg {
451
- ( $pkgid: expr => [ $( $deps: expr) ,+ $( , ) * ] ) => ( {
452
- let d: Vec <Dependency > = vec![ $( $deps. to_dep( ) ) ,+ ] ;
471
+ ( $pkgid: expr => [ $( $deps: expr) ,* $( , ) ? ] ) => ( {
472
+ let d: Vec <Dependency > = vec![ $( $deps. to_dep( ) ) ,* ] ;
453
473
$crate:: pkg_dep( $pkgid, d)
454
474
} ) ;
455
475
@@ -473,18 +493,29 @@ pub fn pkg<T: ToPkgId>(name: T) -> Summary {
473
493
pub fn pkg_dep < T : ToPkgId > ( name : T , dep : Vec < Dependency > ) -> Summary {
474
494
let pkgid = name. to_pkgid ( ) ;
475
495
let link = if pkgid. name ( ) . ends_with ( "-sys" ) {
476
- Some ( pkgid. name ( ) . as_str ( ) )
496
+ Some ( pkgid. name ( ) )
477
497
} else {
478
498
None
479
499
} ;
480
- Summary :: new (
481
- name. to_pkgid ( ) ,
482
- dep,
483
- & BTreeMap :: new ( ) ,
484
- link,
485
- None :: < RustVersion > ,
486
- )
487
- . unwrap ( )
500
+ Summary :: new ( name. to_pkgid ( ) , dep, & BTreeMap :: new ( ) , link, None ) . unwrap ( )
501
+ }
502
+
503
+ pub fn pkg_dep_with < T : ToPkgId > (
504
+ name : T ,
505
+ dep : Vec < Dependency > ,
506
+ features : & [ ( & ' static str , & [ & ' static str ] ) ] ,
507
+ ) -> Summary {
508
+ let pkgid = name. to_pkgid ( ) ;
509
+ let link = if pkgid. name ( ) . ends_with ( "-sys" ) {
510
+ Some ( pkgid. name ( ) )
511
+ } else {
512
+ None
513
+ } ;
514
+ let features = features
515
+ . into_iter ( )
516
+ . map ( |& ( name, values) | ( name. into ( ) , values. into_iter ( ) . map ( |& v| v. into ( ) ) . collect ( ) ) )
517
+ . collect ( ) ;
518
+ Summary :: new ( name. to_pkgid ( ) , dep, & features, link, None ) . unwrap ( )
488
519
}
489
520
490
521
pub fn pkg_id ( name : & str ) -> PackageId {
@@ -510,7 +541,7 @@ pub fn pkg_loc(name: &str, loc: &str) -> Summary {
510
541
Vec :: new ( ) ,
511
542
& BTreeMap :: new ( ) ,
512
543
link,
513
- None :: < RustVersion > ,
544
+ None ,
514
545
)
515
546
. unwrap ( )
516
547
}
@@ -519,14 +550,7 @@ pub fn remove_dep(sum: &Summary, ind: usize) -> Summary {
519
550
let mut deps = sum. dependencies ( ) . to_vec ( ) ;
520
551
deps. remove ( ind) ;
521
552
// note: more things will need to be copied over in the future, but it works for now.
522
- Summary :: new (
523
- sum. package_id ( ) ,
524
- deps,
525
- & BTreeMap :: new ( ) ,
526
- sum. links ( ) . map ( |a| a. as_str ( ) ) ,
527
- None :: < RustVersion > ,
528
- )
529
- . unwrap ( )
553
+ Summary :: new ( sum. package_id ( ) , deps, & BTreeMap :: new ( ) , sum. links ( ) , None ) . unwrap ( )
530
554
}
531
555
532
556
pub fn dep ( name : & str ) -> Dependency {
@@ -629,7 +653,7 @@ fn meta_test_deep_pretty_print_registry() {
629
653
pkg!( ( "foo" , "1.0.0" ) => [ dep_req( "bar" , "2" ) ] ) ,
630
654
pkg!( ( "foo" , "2.0.0" ) => [ dep_req( "bar" , "*" ) ] ) ,
631
655
pkg!( ( "bar" , "1.0.0" ) => [ dep_req( "baz" , "=1.0.2" ) ,
632
- dep_req( "other" , "1" ) ] ) ,
656
+ dep_req( "other" , "1" ) ] ) ,
633
657
pkg!( ( "bar" , "2.0.0" ) => [ dep_req( "baz" , "=1.0.1" ) ] ) ,
634
658
pkg!( ( "baz" , "1.0.2" ) => [ dep_req( "other" , "2" ) ] ) ,
635
659
pkg!( ( "baz" , "1.0.1" ) ) ,
@@ -654,8 +678,8 @@ fn meta_test_deep_pretty_print_registry() {
654
678
}
655
679
656
680
/// This generates a random registry index.
657
- /// Unlike vec((Name, Ver, vec((Name, VerRq), ..), ..)
658
- /// This strategy has a high probability of having valid dependencies
681
+ /// Unlike ` vec((Name, Ver, vec((Name, VerRq), ..), ..)`,
682
+ /// this strategy has a high probability of having valid dependencies.
659
683
pub fn registry_strategy (
660
684
max_crates : usize ,
661
685
max_versions : usize ,
0 commit comments