1
+ use std:: cell:: RefCell ;
1
2
use std:: cmp:: PartialEq ;
2
3
use std:: cmp:: { max, min} ;
3
4
use std:: collections:: { BTreeMap , BTreeSet , HashMap , HashSet } ;
4
5
use std:: fmt;
6
+ use std:: fmt:: Write ;
7
+ use std:: rc:: Rc ;
5
8
use std:: time:: Instant ;
6
9
7
10
use cargo:: core:: dependency:: Kind ;
@@ -24,66 +27,80 @@ pub fn resolve(deps: Vec<Dependency>, registry: &[Summary]) -> CargoResult<Vec<P
24
27
pub fn resolve_and_validated (
25
28
deps : Vec < Dependency > ,
26
29
registry : & [ Summary ] ,
27
- sat_resolve : Option < & mut SatResolve > ,
30
+ sat_resolve : Option < SatResolve > ,
28
31
) -> CargoResult < Vec < PackageId > > {
29
- let should_resolve = if let Some ( sat) = sat_resolve {
30
- sat. sat_resolve ( & deps)
31
- } else {
32
- SatResolve :: new ( registry) . sat_resolve ( & deps)
33
- } ;
34
- let resolve = resolve_with_config_raw ( deps, registry, None ) ;
35
- assert_eq ! ( resolve. is_ok( ) , should_resolve) ;
36
-
37
- let resolve = resolve?;
38
- let mut stack = vec ! [ pkg_id( "root" ) ] ;
39
- let mut used = HashSet :: new ( ) ;
40
- let mut links = HashSet :: new ( ) ;
41
- while let Some ( p) = stack. pop ( ) {
42
- assert ! ( resolve. contains( & p) ) ;
43
- if used. insert ( p) {
44
- // in the tests all `links` crates end in `-sys`
45
- if p. name ( ) . ends_with ( "-sys" ) {
46
- assert ! ( links. insert( p. name( ) ) ) ;
32
+ let resolve = resolve_with_config_raw ( deps. clone ( ) , registry, None ) ;
33
+
34
+ match resolve {
35
+ Err ( e) => {
36
+ let sat_resolve = sat_resolve. unwrap_or_else ( || SatResolve :: new ( registry) ) ;
37
+ if sat_resolve. sat_resolve ( & deps) {
38
+ panic ! (
39
+ "the resolve err but the sat_resolve thinks this will work:\n {}" ,
40
+ sat_resolve. use_packages( ) . unwrap( )
41
+ ) ;
47
42
}
48
- stack. extend ( resolve. deps ( p) . map ( |( dp, deps) | {
49
- for d in deps {
50
- assert ! ( d. matches_id( dp) ) ;
51
- }
52
- dp
53
- } ) ) ;
43
+ Err ( e)
54
44
}
55
- }
56
- let out = resolve. sort ( ) ;
57
- assert_eq ! ( out. len( ) , used. len( ) ) ;
58
-
59
- let mut pub_deps: HashMap < PackageId , HashSet < _ > > = HashMap :: new ( ) ;
60
- for & p in out. iter ( ) {
61
- // make the list of `p` public dependencies
62
- let mut self_pub_dep = HashSet :: new ( ) ;
63
- self_pub_dep. insert ( p) ;
64
- for ( dp, deps) in resolve. deps ( p) {
65
- if deps. iter ( ) . any ( |d| d. is_public ( ) ) {
66
- self_pub_dep. extend ( pub_deps[ & dp] . iter ( ) . cloned ( ) )
45
+ Ok ( resolve) => {
46
+ let mut stack = vec ! [ pkg_id( "root" ) ] ;
47
+ let mut used = HashSet :: new ( ) ;
48
+ let mut links = HashSet :: new ( ) ;
49
+ while let Some ( p) = stack. pop ( ) {
50
+ assert ! ( resolve. contains( & p) ) ;
51
+ if used. insert ( p) {
52
+ // in the tests all `links` crates end in `-sys`
53
+ if p. name ( ) . ends_with ( "-sys" ) {
54
+ assert ! ( links. insert( p. name( ) ) ) ;
55
+ }
56
+ stack. extend ( resolve. deps ( p) . map ( |( dp, deps) | {
57
+ for d in deps {
58
+ assert ! ( d. matches_id( dp) ) ;
59
+ }
60
+ dp
61
+ } ) ) ;
62
+ }
67
63
}
68
- }
69
- pub_deps. insert ( p, self_pub_dep) ;
64
+ let out = resolve. sort ( ) ;
65
+ assert_eq ! ( out. len( ) , used. len( ) ) ;
66
+
67
+ let mut pub_deps: HashMap < PackageId , HashSet < _ > > = HashMap :: new ( ) ;
68
+ for & p in out. iter ( ) {
69
+ // make the list of `p` public dependencies
70
+ let mut self_pub_dep = HashSet :: new ( ) ;
71
+ self_pub_dep. insert ( p) ;
72
+ for ( dp, deps) in resolve. deps ( p) {
73
+ if deps. iter ( ) . any ( |d| d. is_public ( ) ) {
74
+ self_pub_dep. extend ( pub_deps[ & dp] . iter ( ) . cloned ( ) )
75
+ }
76
+ }
77
+ pub_deps. insert ( p, self_pub_dep) ;
70
78
71
- // check if `p` has a public dependencies conflicts
72
- let seen_dep: BTreeSet < _ > = resolve
73
- . deps ( p)
74
- . flat_map ( |( dp, _) | pub_deps[ & dp] . iter ( ) . cloned ( ) )
75
- . collect ( ) ;
76
- let seen_dep: Vec < _ > = seen_dep. iter ( ) . collect ( ) ;
77
- for a in seen_dep. windows ( 2 ) {
78
- if a[ 0 ] . name ( ) == a[ 1 ] . name ( ) {
79
+ // check if `p` has a public dependencies conflicts
80
+ let seen_dep: BTreeSet < _ > = resolve
81
+ . deps ( p)
82
+ . flat_map ( |( dp, _) | pub_deps[ & dp] . iter ( ) . cloned ( ) )
83
+ . collect ( ) ;
84
+ let seen_dep: Vec < _ > = seen_dep. iter ( ) . collect ( ) ;
85
+ for a in seen_dep. windows ( 2 ) {
86
+ if a[ 0 ] . name ( ) == a[ 1 ] . name ( ) {
87
+ panic ! (
88
+ "the package {:?} can publicly see {:?} and {:?}" ,
89
+ p, a[ 0 ] , a[ 1 ]
90
+ )
91
+ }
92
+ }
93
+ }
94
+ let sat_resolve = sat_resolve. unwrap_or_else ( || SatResolve :: new ( registry) ) ;
95
+ if !sat_resolve. sat_is_valid_solution ( & out) {
79
96
panic ! (
80
- "the package {:?} can publicly see {:?} and {:?}" ,
81
- p , a [ 0 ] , a [ 1 ]
82
- )
97
+ "the sat_resolve err but the resolve thinks this will work: \n {:?}" ,
98
+ resolve
99
+ ) ;
83
100
}
101
+ Ok ( out)
84
102
}
85
103
}
86
- Ok ( out)
87
104
}
88
105
89
106
pub fn resolve_with_config (
@@ -234,7 +251,9 @@ fn sat_at_most_one_by_key<K: std::hash::Hash + Eq>(
234
251
///
235
252
/// The SAT library dose not optimize for the newer version,
236
253
/// so the selected packages may not match the real resolver.
237
- pub struct SatResolve {
254
+ #[ derive( Clone ) ]
255
+ pub struct SatResolve ( Rc < RefCell < SatResolveInner > > ) ;
256
+ struct SatResolveInner {
238
257
solver : varisat:: Solver < ' static > ,
239
258
var_for_is_packages_used : HashMap < PackageId , varisat:: Var > ,
240
259
by_name : HashMap < & ' static str , Vec < PackageId > > ,
@@ -397,50 +416,86 @@ impl SatResolve {
397
416
solver
398
417
. solve ( )
399
418
. expect ( "docs say it can't error in default config" ) ;
400
-
401
- SatResolve {
419
+ SatResolve ( Rc :: new ( RefCell :: new ( SatResolveInner {
402
420
solver,
403
421
var_for_is_packages_used,
404
422
by_name,
405
- }
423
+ } ) ) )
406
424
}
407
- pub fn sat_resolve ( & mut self , deps : & [ Dependency ] ) -> bool {
425
+ pub fn sat_resolve ( & self , deps : & [ Dependency ] ) -> bool {
426
+ let mut s = self . 0 . borrow_mut ( ) ;
408
427
let mut assumption = vec ! [ ] ;
409
428
let mut this_call = None ;
410
429
411
430
// the starting `deps` need to be satisfied
412
431
for dep in deps. iter ( ) {
413
432
let empty_vec = vec ! [ ] ;
414
- let matches: Vec < varisat:: Lit > = self
433
+ let matches: Vec < varisat:: Lit > = s
415
434
. by_name
416
435
. get ( dep. package_name ( ) . as_str ( ) )
417
436
. unwrap_or ( & empty_vec)
418
437
. iter ( )
419
438
. filter ( |& p| dep. matches_id ( * p) )
420
- . map ( |p| self . var_for_is_packages_used [ p] . positive ( ) )
439
+ . map ( |p| s . var_for_is_packages_used [ p] . positive ( ) )
421
440
. collect ( ) ;
422
441
if matches. is_empty ( ) {
423
442
return false ;
424
443
} else if matches. len ( ) == 1 {
425
444
assumption. extend_from_slice ( & matches)
426
445
} else {
427
446
if this_call. is_none ( ) {
428
- let new_var = self . solver . new_var ( ) ;
447
+ let new_var = s . solver . new_var ( ) ;
429
448
this_call = Some ( new_var) ;
430
449
assumption. push ( new_var. positive ( ) ) ;
431
450
}
432
451
let mut matches = matches;
433
452
matches. push ( this_call. unwrap ( ) . negative ( ) ) ;
434
- self . solver . add_clause ( & matches) ;
453
+ s. solver . add_clause ( & matches) ;
454
+ }
455
+ }
456
+
457
+ s. solver . assume ( & assumption) ;
458
+
459
+ s. solver
460
+ . solve ( )
461
+ . expect ( "docs say it can't error in default config" )
462
+ }
463
+ pub fn sat_is_valid_solution ( & self , pids : & [ PackageId ] ) -> bool {
464
+ let mut s = self . 0 . borrow_mut ( ) ;
465
+ for p in pids {
466
+ if p. name ( ) . as_str ( ) != "root" && !s. var_for_is_packages_used . contains_key ( p) {
467
+ return false ;
435
468
}
436
469
}
470
+ let assumption: Vec < _ > = s
471
+ . var_for_is_packages_used
472
+ . iter ( )
473
+ . map ( |( p, v) | v. lit ( pids. contains ( p) ) )
474
+ . collect ( ) ;
437
475
438
- self . solver . assume ( & assumption) ;
476
+ s . solver . assume ( & assumption) ;
439
477
440
- self . solver
478
+ s . solver
441
479
. solve ( )
442
480
. expect ( "docs say it can't error in default config" )
443
481
}
482
+ fn use_packages ( & self ) -> Option < String > {
483
+ self . 0 . borrow ( ) . solver . model ( ) . map ( |lits| {
484
+ let lits: HashSet < _ > = lits
485
+ . iter ( )
486
+ . filter ( |l| l. is_positive ( ) )
487
+ . map ( |l| l. var ( ) )
488
+ . collect ( ) ;
489
+ let mut out = String :: new ( ) ;
490
+ out. push_str ( "used:\n " ) ;
491
+ for ( p, v) in self . 0 . borrow ( ) . var_for_is_packages_used . iter ( ) {
492
+ if lits. contains ( v) {
493
+ writeln ! ( & mut out, " {}" , p) . unwrap ( ) ;
494
+ }
495
+ }
496
+ out
497
+ } )
498
+ }
444
499
}
445
500
446
501
pub trait ToDep {
0 commit comments