@@ -69,7 +69,7 @@ use crate::AbstractSolverMut;
69
69
// be a relationship between every component of a package and a "base"
70
70
// component, to prevent a solve containing a mix of components from different
71
71
// versions of the same package.
72
- #[ derive( Clone , Eq , Hash , PartialEq ) ]
72
+ #[ derive( Clone , Debug , Eq , Hash , PartialEq ) ]
73
73
pub ( crate ) struct PkgNameBufWithComponent {
74
74
pub ( crate ) name : PkgNameBuf ,
75
75
pub ( crate ) component : SyntheticComponent ,
@@ -128,7 +128,10 @@ impl ResolvoPackageName {
128
128
None
129
129
}
130
130
ResolvoPackageName :: PkgNameBufWithComponent ( pkg_name) => {
131
- let mut located_builds = Vec :: new ( ) ;
131
+ // Prevent duplicate solvables by using a set. Ties (same build
132
+ // but "requires_build_from_source" differs) are resolved with
133
+ // "requires_build_from_source" being true.
134
+ let mut located_builds = HashSet :: new ( ) ;
132
135
133
136
let root_pkg_request = provider. global_pkg_requests . get ( & pkg_name. name ) ;
134
137
@@ -201,23 +204,62 @@ impl ResolvoPackageName {
201
204
// when a request for it is found it can act as a
202
205
// surrogate that depends on all the individual
203
206
// components.
204
- [ Component :: All ] ,
207
+ {
208
+ if !build. is_source ( ) {
209
+ itertools:: Either :: Left ( [ Component :: All ] . into_iter ( ) )
210
+ } else {
211
+ // XXX: Unclear if this is the right
212
+ // approach but without this special
213
+ // case the Solution can incorrectly
214
+ // end up with a src build marked as
215
+ // requires_build_from_source for
216
+ // requests that are asking for
217
+ // :src.
218
+ itertools:: Either :: Right ( [ ] . into_iter ( ) )
219
+ }
220
+ } ,
205
221
) {
206
- if component != * pkg_name_component
207
- && ( provider. binary_only || !component. is_source ( ) )
222
+ let requires_build_from_source = build. is_source ( )
223
+ && ( component != * pkg_name_component
224
+ || pkg_name_component. is_all ( ) ) ;
225
+
226
+ if requires_build_from_source && provider. binary_only {
227
+ // Deny anything that requires build
228
+ // from source when binary_only is
229
+ // enabled.
230
+ continue ;
231
+ }
232
+
233
+ if ( !requires_build_from_source || !build. is_source ( ) )
234
+ && component != * pkg_name_component
208
235
{
236
+ // Deny components that don't match
237
+ // unless it is possible to build from
238
+ // source.
209
239
continue ;
210
240
}
211
241
212
- located_builds . push ( LocatedBuildIdentWithComponent {
242
+ let new_entry = LocatedBuildIdentWithComponent {
213
243
ident : located_build_ident. clone ( ) ,
214
244
component : pkg_name. component . clone ( ) ,
215
- requires_build_from_source : component
216
- != * pkg_name_component,
217
- } ) ;
245
+ requires_build_from_source,
246
+ } ;
247
+
248
+ if requires_build_from_source {
249
+ // _replace_ any existing entry, which
250
+ // might have
251
+ // requires_build_from_source == false,
252
+ // so it now is true.
253
+ located_builds. replace ( new_entry) ;
254
+ } else {
255
+ // _insert_ to not overwrite any
256
+ // existing entry that might have
257
+ // requires_build_from_source == true.
258
+ located_builds. insert ( new_entry) ;
259
+ }
218
260
}
219
261
} else {
220
- located_builds. push ( LocatedBuildIdentWithComponent {
262
+ located_builds. insert ( LocatedBuildIdentWithComponent {
221
263
ident : located_build_ident,
222
264
component : SyntheticComponent :: Base ,
223
265
requires_build_from_source : false ,
@@ -538,21 +580,21 @@ impl SpkProvider {
538
580
fn pkg_request_to_known_dependencies ( & self , pkg_request : & PkgRequest ) -> KnownDependencies {
539
581
let mut components = pkg_request. pkg . components . iter ( ) . peekable ( ) ;
540
582
let iter = if components. peek ( ) . is_some ( ) {
541
- itertools:: Either :: Right ( components. cloned ( ) . map ( SyntheticComponent :: Actual ) )
583
+ itertools:: Either :: Right ( components. cloned ( ) )
542
584
} else {
543
585
itertools:: Either :: Left (
544
586
// A request with no components is assumed to be a request for
545
- // the run (or source) component.
587
+ // the default_for_run (or source) component.
546
588
if pkg_request
547
589
. pkg
548
590
. build
549
591
. as_ref ( )
550
592
. map ( |build| build. is_source ( ) )
551
593
. unwrap_or ( false )
552
594
{
553
- std:: iter:: once ( SyntheticComponent :: Actual ( Component :: Source ) )
595
+ std:: iter:: once ( Component :: Source )
554
596
} else {
555
- std:: iter:: once ( SyntheticComponent :: Actual ( Component :: Run ) )
597
+ std:: iter:: once ( Component :: default_for_run ( ) )
556
598
} ,
557
599
)
558
600
} ;
@@ -566,12 +608,14 @@ impl SpkProvider {
566
608
. intern_package_name ( ResolvoPackageName :: PkgNameBufWithComponent (
567
609
PkgNameBufWithComponent {
568
610
name : pkg_request. pkg . name ( ) . to_owned ( ) ,
569
- component,
611
+ component : SyntheticComponent :: Actual ( component . clone ( ) ) ,
570
612
} ,
571
613
) ) ;
614
+ let mut pkg_request_with_component = pkg_request. clone ( ) ;
615
+ pkg_request_with_component. pkg . components = BTreeSet :: from_iter ( [ component] ) ;
572
616
let dep_vs = self . pool . intern_version_set (
573
617
dep_name,
574
- RequestVS :: SpkRequest ( Request :: Pkg ( pkg_request . clone ( ) ) ) ,
618
+ RequestVS :: SpkRequest ( Request :: Pkg ( pkg_request_with_component ) ) ,
575
619
) ;
576
620
match pkg_request. inclusion_policy {
577
621
spk_schema:: ident:: InclusionPolicy :: Always => {
@@ -761,7 +805,7 @@ impl SpkProvider {
761
805
762
806
// If neither build has a key, both packages failed to load?
763
807
// Add debug assert to see if this ever happens.
764
- debug_assert ! ( false , "builds without keys" ) ;
808
+ debug_assert ! ( false , "builds without keys {a:?} {b:?} " ) ;
765
809
766
810
a. 1 . ident . cmp ( & b. 1 . ident )
767
811
}
@@ -885,6 +929,22 @@ impl DependencyProvider for SpkProvider {
885
929
// a candidate. Source builds that can't be built from
886
930
// source are filtered out in `get_candidates`.
887
931
if located_build_ident_with_component. requires_build_from_source {
932
+ // However, building from source is not a suitable
933
+ // candidate for a request for a specific component
934
+ // of an existing build, such as when finding the
935
+ // members of the :all component of a build.
936
+ if pkg_request
937
+ . pkg
938
+ . build
939
+ . as_ref ( )
940
+ . is_some_and ( |b| b. is_buildid ( ) )
941
+ {
942
+ if inverse {
943
+ selected. push ( * candidate) ;
944
+ }
945
+ continue ;
946
+ }
947
+
888
948
if !inverse {
889
949
selected. push ( * candidate) ;
890
950
}
0 commit comments