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 ;
@@ -17,92 +20,99 @@ use proptest::sample::Index;
17
20
use proptest:: string:: string_regex;
18
21
use varisat:: { self , ExtendFormula } ;
19
22
20
- pub fn resolve (
21
- pkg : PackageId ,
22
- deps : Vec < Dependency > ,
23
- registry : & [ Summary ] ,
24
- ) -> CargoResult < Vec < PackageId > > {
25
- resolve_with_config ( pkg, deps, registry, None )
23
+ pub fn resolve ( deps : Vec < Dependency > , registry : & [ Summary ] ) -> CargoResult < Vec < PackageId > > {
24
+ resolve_with_config ( deps, registry, None )
26
25
}
27
26
28
27
pub fn resolve_and_validated (
29
- pkg : PackageId ,
30
28
deps : Vec < Dependency > ,
31
29
registry : & [ Summary ] ,
32
- sat_resolve : Option < & mut SatResolve > ,
30
+ sat_resolve : Option < SatResolve > ,
33
31
) -> CargoResult < Vec < PackageId > > {
34
- let should_resolve = if let Some ( sat) = sat_resolve {
35
- sat. sat_resolve ( & deps)
36
- } else {
37
- SatResolve :: new ( registry) . sat_resolve ( & deps)
38
- } ;
39
- let resolve = resolve_with_config_raw ( pkg, deps, registry, None ) ;
40
- assert_eq ! ( resolve. is_ok( ) , should_resolve) ;
41
-
42
- let resolve = resolve?;
43
- let mut stack = vec ! [ pkg] ;
44
- let mut used = HashSet :: new ( ) ;
45
- let mut links = HashSet :: new ( ) ;
46
- while let Some ( p) = stack. pop ( ) {
47
- assert ! ( resolve. contains( & p) ) ;
48
- if used. insert ( p) {
49
- // in the tests all `links` crates end in `-sys`
50
- if p. name ( ) . ends_with ( "-sys" ) {
51
- 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
+ ) ;
52
42
}
53
- stack. extend ( resolve. deps ( p) . map ( |( dp, deps) | {
54
- for d in deps {
55
- assert ! ( d. matches_id( dp) ) ;
56
- }
57
- dp
58
- } ) ) ;
43
+ Err ( e)
59
44
}
60
- }
61
- let out = resolve. sort ( ) ;
62
- assert_eq ! ( out. len( ) , used. len( ) ) ;
63
-
64
- let mut pub_deps: HashMap < PackageId , HashSet < _ > > = HashMap :: new ( ) ;
65
- for & p in out. iter ( ) {
66
- // make the list of `p` public dependencies
67
- let mut self_pub_dep = HashSet :: new ( ) ;
68
- self_pub_dep. insert ( p) ;
69
- for ( dp, deps) in resolve. deps ( p) {
70
- if deps. iter ( ) . any ( |d| d. is_public ( ) ) {
71
- 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
+ }
72
63
}
73
- }
74
- 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) ;
75
78
76
- // check if `p` has a public dependencies conflicts
77
- let seen_dep: BTreeSet < _ > = resolve
78
- . deps ( p)
79
- . flat_map ( |( dp, _) | pub_deps[ & dp] . iter ( ) . cloned ( ) )
80
- . collect ( ) ;
81
- let seen_dep: Vec < _ > = seen_dep. iter ( ) . collect ( ) ;
82
- for a in seen_dep. windows ( 2 ) {
83
- 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) {
84
96
panic ! (
85
- "the package {:?} can publicly see {:?} and {:?}" ,
86
- p , a [ 0 ] , a [ 1 ]
87
- )
97
+ "the sat_resolve err but the resolve thinks this will work: \n {:?}" ,
98
+ resolve
99
+ ) ;
88
100
}
101
+ Ok ( out)
89
102
}
90
103
}
91
- Ok ( out)
92
104
}
93
105
94
106
pub fn resolve_with_config (
95
- pkg : PackageId ,
96
107
deps : Vec < Dependency > ,
97
108
registry : & [ Summary ] ,
98
109
config : Option < & Config > ,
99
110
) -> CargoResult < Vec < PackageId > > {
100
- let resolve = resolve_with_config_raw ( pkg , deps, registry, config) ?;
111
+ let resolve = resolve_with_config_raw ( deps, registry, config) ?;
101
112
Ok ( resolve. sort ( ) )
102
113
}
103
114
104
115
pub fn resolve_with_config_raw (
105
- pkg : PackageId ,
106
116
deps : Vec < Dependency > ,
107
117
registry : & [ Summary ] ,
108
118
config : Option < & Config > ,
@@ -158,7 +168,7 @@ pub fn resolve_with_config_raw(
158
168
used : HashSet :: new ( ) ,
159
169
} ;
160
170
let summary = Summary :: new (
161
- pkg ,
171
+ pkg_id ( "root" ) ,
162
172
deps,
163
173
& BTreeMap :: < String , Vec < String > > :: new ( ) ,
164
174
None :: < String > ,
@@ -241,7 +251,9 @@ fn sat_at_most_one_by_key<K: std::hash::Hash + Eq>(
241
251
///
242
252
/// The SAT library dose not optimize for the newer version,
243
253
/// so the selected packages may not match the real resolver.
244
- pub struct SatResolve {
254
+ #[ derive( Clone ) ]
255
+ pub struct SatResolve ( Rc < RefCell < SatResolveInner > > ) ;
256
+ struct SatResolveInner {
245
257
solver : varisat:: Solver < ' static > ,
246
258
var_for_is_packages_used : HashMap < PackageId , varisat:: Var > ,
247
259
by_name : HashMap < & ' static str , Vec < PackageId > > ,
@@ -404,50 +416,86 @@ impl SatResolve {
404
416
solver
405
417
. solve ( )
406
418
. expect ( "docs say it can't error in default config" ) ;
407
-
408
- SatResolve {
419
+ SatResolve ( Rc :: new ( RefCell :: new ( SatResolveInner {
409
420
solver,
410
421
var_for_is_packages_used,
411
422
by_name,
412
- }
423
+ } ) ) )
413
424
}
414
- 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 ( ) ;
415
427
let mut assumption = vec ! [ ] ;
416
428
let mut this_call = None ;
417
429
418
430
// the starting `deps` need to be satisfied
419
431
for dep in deps. iter ( ) {
420
432
let empty_vec = vec ! [ ] ;
421
- let matches: Vec < varisat:: Lit > = self
433
+ let matches: Vec < varisat:: Lit > = s
422
434
. by_name
423
435
. get ( dep. package_name ( ) . as_str ( ) )
424
436
. unwrap_or ( & empty_vec)
425
437
. iter ( )
426
438
. filter ( |& p| dep. matches_id ( * p) )
427
- . map ( |p| self . var_for_is_packages_used [ p] . positive ( ) )
439
+ . map ( |p| s . var_for_is_packages_used [ p] . positive ( ) )
428
440
. collect ( ) ;
429
441
if matches. is_empty ( ) {
430
442
return false ;
431
443
} else if matches. len ( ) == 1 {
432
444
assumption. extend_from_slice ( & matches)
433
445
} else {
434
446
if this_call. is_none ( ) {
435
- let new_var = self . solver . new_var ( ) ;
447
+ let new_var = s . solver . new_var ( ) ;
436
448
this_call = Some ( new_var) ;
437
449
assumption. push ( new_var. positive ( ) ) ;
438
450
}
439
451
let mut matches = matches;
440
452
matches. push ( this_call. unwrap ( ) . negative ( ) ) ;
441
- 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 ;
442
468
}
443
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 ( ) ;
444
475
445
- self . solver . assume ( & assumption) ;
476
+ s . solver . assume ( & assumption) ;
446
477
447
- self . solver
478
+ s . solver
448
479
. solve ( )
449
480
. expect ( "docs say it can't error in default config" )
450
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
+ }
451
499
}
452
500
453
501
pub trait ToDep {
@@ -856,7 +904,6 @@ fn meta_test_deep_trees_from_strategy() {
856
904
let reg = registry ( input. clone ( ) ) ;
857
905
for this in input. iter ( ) . rev ( ) . take ( 10 ) {
858
906
let res = resolve (
859
- pkg_id ( "root" ) ,
860
907
vec ! [ dep_req( & this. name( ) , & format!( "={}" , this. version( ) ) ) ] ,
861
908
& reg,
862
909
) ;
@@ -898,7 +945,6 @@ fn meta_test_multiple_versions_strategy() {
898
945
let reg = registry ( input. clone ( ) ) ;
899
946
for this in input. iter ( ) . rev ( ) . take ( 10 ) {
900
947
let res = resolve (
901
- pkg_id ( "root" ) ,
902
948
vec ! [ dep_req( & this. name( ) , & format!( "={}" , this. version( ) ) ) ] ,
903
949
& reg,
904
950
) ;
0 commit comments