@@ -69,7 +69,7 @@ use crate::SolverMut;
6969// be a relationship between every component of a package and a "base"
7070// component, to prevent a solve containing a mix of components from different
7171// versions of the same package.
72- #[ derive( Clone , Eq , Hash , PartialEq ) ]
72+ #[ derive( Clone , Debug , Eq , Hash , PartialEq ) ]
7373pub ( crate ) struct PkgNameBufWithComponent {
7474 pub ( crate ) name : PkgNameBuf ,
7575 pub ( crate ) component : SyntheticComponent ,
@@ -128,7 +128,10 @@ impl ResolvoPackageName {
128128 None
129129 }
130130 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 ( ) ;
132135
133136 let root_pkg_request = provider. global_pkg_requests . get ( & pkg_name. name ) ;
134137
@@ -201,23 +204,62 @@ impl ResolvoPackageName {
201204 // when a request for it is found it can act as a
202205 // surrogate that depends on all the individual
203206 // 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+ } ,
205221 ) {
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
208235 {
236+ // Deny components that don't match
237+ // unless it is possible to build from
238+ // source.
209239 continue ;
210240 }
211241
212- located_builds . push ( LocatedBuildIdentWithComponent {
242+ let new_entry = LocatedBuildIdentWithComponent {
213243 ident : located_build_ident. clone ( ) ,
214244 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+ }
218260 }
219261 } else {
220- located_builds. push ( LocatedBuildIdentWithComponent {
262+ located_builds. insert ( LocatedBuildIdentWithComponent {
221263 ident : located_build_ident,
222264 component : SyntheticComponent :: Base ,
223265 requires_build_from_source : false ,
@@ -538,21 +580,21 @@ impl SpkProvider {
538580 fn pkg_request_to_known_dependencies ( & self , pkg_request : & PkgRequest ) -> KnownDependencies {
539581 let mut components = pkg_request. pkg . components . iter ( ) . peekable ( ) ;
540582 let iter = if components. peek ( ) . is_some ( ) {
541- itertools:: Either :: Right ( components. cloned ( ) . map ( SyntheticComponent :: Actual ) )
583+ itertools:: Either :: Right ( components. cloned ( ) )
542584 } else {
543585 itertools:: Either :: Left (
544586 // 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.
546588 if pkg_request
547589 . pkg
548590 . build
549591 . as_ref ( )
550592 . map ( |build| build. is_source ( ) )
551593 . unwrap_or ( false )
552594 {
553- std:: iter:: once ( SyntheticComponent :: Actual ( Component :: Source ) )
595+ std:: iter:: once ( Component :: Source )
554596 } else {
555- std:: iter:: once ( SyntheticComponent :: Actual ( Component :: Run ) )
597+ std:: iter:: once ( Component :: default_for_run ( ) )
556598 } ,
557599 )
558600 } ;
@@ -566,12 +608,14 @@ impl SpkProvider {
566608 . intern_package_name ( ResolvoPackageName :: PkgNameBufWithComponent (
567609 PkgNameBufWithComponent {
568610 name : pkg_request. pkg . name ( ) . to_owned ( ) ,
569- component,
611+ component : SyntheticComponent :: Actual ( component . clone ( ) ) ,
570612 } ,
571613 ) ) ;
614+ let mut pkg_request_with_component = pkg_request. clone ( ) ;
615+ pkg_request_with_component. pkg . components = BTreeSet :: from_iter ( [ component] ) ;
572616 let dep_vs = self . pool . intern_version_set (
573617 dep_name,
574- RequestVS :: SpkRequest ( Request :: Pkg ( pkg_request . clone ( ) ) ) ,
618+ RequestVS :: SpkRequest ( Request :: Pkg ( pkg_request_with_component ) ) ,
575619 ) ;
576620 match pkg_request. inclusion_policy {
577621 spk_schema:: ident:: InclusionPolicy :: Always => {
@@ -761,7 +805,7 @@ impl SpkProvider {
761805
762806 // If neither build has a key, both packages failed to load?
763807 // 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:?} " ) ;
765809
766810 a. 1 . ident . cmp ( & b. 1 . ident )
767811 }
@@ -885,6 +929,22 @@ impl DependencyProvider for SpkProvider {
885929 // a candidate. Source builds that can't be built from
886930 // source are filtered out in `get_candidates`.
887931 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+
888948 if !inverse {
889949 selected. push ( * candidate) ;
890950 }
0 commit comments