@@ -49,6 +49,15 @@ def _add_to_dict(d, k, v):
4949def _fq_crate (name , version ):
5050 return name + "-" + version
5151
52+ _INTERNAL_RUSTC_PLACEHOLDER_CRATES = [
53+ "rustc-std-workspace-alloc" ,
54+ "rustc-std-workspace-core" ,
55+ "rustc-std-workspace-std" ,
56+ ]
57+
58+ def _is_internal_rustc_placeholder (crate_name ):
59+ return crate_name in _INTERNAL_RUSTC_PLACEHOLDER_CRATES
60+
5261def _new_feature_resolutions (package_index , possible_deps , possible_features , platform_triples ):
5362 return struct (
5463 features_enabled = {triple : set () for triple in platform_triples },
@@ -145,6 +154,53 @@ Make sure you point to the `Cargo.toml` of the workspace, not of `{name}`!”
145154 return inherited
146155 return _spec_to_dep_dict_inner (dep , spec , is_build )
147156
157+ def _cargo_metadata_dep_to_dep_dict (dep ):
158+ rename = dep .get ("rename" )
159+ converted = {
160+ "name" : rename or dep ["name" ],
161+ "optional" : dep .get ("optional" , False ),
162+ "default_features" : dep .get ("uses_default_features" , True ),
163+ "features" : list (dep .get ("features" , [])),
164+ }
165+
166+ req = dep .get ("req" )
167+ if req :
168+ converted ["req" ] = req
169+
170+ kind = dep .get ("kind" )
171+ if kind and kind != "normal" :
172+ converted ["kind" ] = kind
173+
174+ target = dep .get ("target" )
175+ if target :
176+ converted ["target" ] = target
177+
178+ if rename :
179+ converted ["package" ] = dep ["name" ]
180+
181+ return converted
182+
183+ def _prepare_possible_deps (dependencies , converter = None ):
184+ possible_deps = []
185+
186+ for dep in dependencies :
187+ if converter :
188+ dep = converter (dep )
189+
190+ if dep .get ("kind" ) == "dev" :
191+ continue
192+
193+ dep_package = dep .get ("package" ) or dep ["name" ]
194+ if _is_internal_rustc_placeholder (dep_package ):
195+ continue
196+
197+ if dep .get ("default_features" , True ):
198+ _add_to_dict (dep , "features" , "default" )
199+
200+ possible_deps .append (dep )
201+
202+ return possible_deps
203+
148204def _generate_hub_and_spokes (
149205 mctx ,
150206 hub_name ,
@@ -404,27 +460,49 @@ def _generate_hub_and_spokes(
404460 fail ("Unknown source %s for crate %s" % (source , name ))
405461
406462 possible_features = fact ["features" ]
407- possible_deps = [
408- dep
409- for dep in fact ["dependencies" ]
410- if dep .get ("kind" ) != "dev" and
411- dep .get ("package" ) not in [
412- # Internal rustc placeholder crates.
413- "rustc-std-workspace-alloc" ,
414- "rustc-std-workspace-core" ,
415- "rustc-std-workspace-std" ,
416- ]
417- ]
418-
419- for dep in possible_deps :
420- if dep .get ("default_features" , True ):
421- _add_to_dict (dep , "features" , "default" )
422-
463+ possible_deps = _prepare_possible_deps (fact ["dependencies" ])
423464 feature_resolutions = _new_feature_resolutions (package_index , possible_deps , possible_features , platform_triples )
424465 package ["feature_resolutions" ] = feature_resolutions
425466 feature_resolutions_by_fq_crate [_fq_crate (name , version )] = feature_resolutions
426467
427- for package in packages :
468+ # Keep a resolver-only view that can include workspace members, unlike `versions_by_name`
469+ # which is used for spoke/hub emission.
470+ resolver_versions_by_name = {name : versions [:] for name , versions in versions_by_name .items ()}
471+
472+ workspace_members_by_key = {(package ["name" ], package ["version" ]): package for package in workspace_members }
473+ resolver_packages = packages [:]
474+ for package in cargo_metadata ["packages" ]:
475+ name = package ["name" ]
476+ version = package ["version" ]
477+
478+ versions = resolver_versions_by_name .get (name , [])
479+ if version not in versions :
480+ if versions :
481+ versions .append (version )
482+ else :
483+ resolver_versions_by_name [name ] = [version ]
484+
485+ possible_features = package .get ("features" , {})
486+ possible_deps = _prepare_possible_deps (
487+ package .get ("dependencies" , []),
488+ converter = _cargo_metadata_dep_to_dep_dict ,
489+ )
490+
491+ package_index = len (resolver_packages )
492+ lockfile_pkg = workspace_members_by_key .get ((name , version ), {})
493+ resolver_package = {
494+ "name" : name ,
495+ "version" : version ,
496+ "dependencies" : lockfile_pkg .get ("dependencies" , []),
497+ }
498+
499+ feature_resolutions = _new_feature_resolutions (package_index , possible_deps , possible_features , platform_triples )
500+ resolver_package ["feature_resolutions" ] = feature_resolutions
501+ feature_resolutions_by_fq_crate [_fq_crate (name , version )] = feature_resolutions
502+
503+ resolver_packages .append (resolver_package )
504+
505+ for package in resolver_packages :
428506 name = package ["name" ]
429507 deps_by_name = {}
430508 for maybe_fq_dep in package .get ("dependencies" , []):
@@ -439,24 +517,25 @@ def _generate_hub_and_spokes(
439517 if not dep_package :
440518 dep_package = dep ["name" ]
441519
442- versions = versions_by_name .get (dep_package )
520+ versions = resolver_versions_by_name .get (dep_package )
443521 if not versions :
444522 continue
523+ constrained_versions = deps_by_name .get (dep_package )
524+ if constrained_versions :
525+ versions = constrained_versions
526+
445527 if len (versions ) == 1 :
446528 resolved_version = versions [0 ]
447529 else :
448- versions = deps_by_name .get (dep_package )
449- if not versions :
530+ req = dep .get ("req" )
531+ if not req :
532+ continue
533+
534+ resolved_version = select_matching_version (req , versions )
535+ if not resolved_version :
536+ if not dep .get ("optional" ):
537+ print ("WARNING: %s: could not resolve %s %s among %s" % (name , dep_package , req , versions ))
450538 continue
451- if len (versions ) == 1 :
452- # TODO(zbarsky): validate?
453- resolved_version = versions [0 ]
454- else :
455- resolved_version = select_matching_version (dep ["req" ], versions )
456- if not resolved_version :
457- if not dep .get ("optional" ):
458- print ("WARNING: %s: could not resolve %s %s among %s" % (name , dep_package , dep ["req" ], versions ))
459- continue
460539
461540 dep_fq = _fq_crate (dep_package , resolved_version )
462541 dep ["bazel_target" ] = "@%s//:%s" % (hub_name , dep_fq )
@@ -473,7 +552,7 @@ def _generate_hub_and_spokes(
473552
474553 _date (mctx , "set up resolutions" )
475554
476- workspace_fq_deps = _compute_workspace_fq_deps (workspace_members , versions_by_name )
555+ workspace_fq_deps = _compute_workspace_fq_deps (workspace_members , resolver_versions_by_name )
477556
478557 workspace_dep_versions_by_name = {}
479558 workspace_dep_labels_by_triple = {triple : set () for triple in platform_triples }
@@ -495,9 +574,7 @@ def _generate_hub_and_spokes(
495574 dep_version = None
496575 if dep_fq :
497576 dep_version = dep_fq [len (dep_name ) + 1 :]
498-
499- if not source and dep_version and (dep_name , dep_version ) in workspace_member_keys :
500- continue
577+ is_first_party_dep = not source and dep_version and (dep_name , dep_version ) in workspace_member_keys
501578
502579 if validate_lockfile and source and source .startswith ("registry+" ):
503580 req = dep ["req" ]
@@ -521,20 +598,24 @@ def _generate_hub_and_spokes(
521598 if not dep_fq :
522599 continue
523600
524- dep ["bazel_target" ] = "@%s//:%s" % (hub_name , dep_fq )
601+ if not is_first_party_dep :
602+ dep ["bazel_target" ] = "@%s//:%s" % (hub_name , dep_fq )
603+
525604 feature_resolutions = feature_resolutions_by_fq_crate [dep_fq ]
526605
527- versions = workspace_dep_versions_by_name .get (dep_name )
528- if not versions :
529- versions = set ()
530- workspace_dep_versions_by_name [dep_name ] = versions
531- versions .add (dep_fq )
606+ if not is_first_party_dep :
607+ versions = workspace_dep_versions_by_name .get (dep_name )
608+ if not versions :
609+ versions = set ()
610+ workspace_dep_versions_by_name [dep_name ] = versions
611+ versions .add (dep_fq )
532612
533613 target = dep .get ("target" )
534614 match_info = _cfg_match_info_for_target (target , platform_cfg_attrs , cfg_match_cache )
535615
536616 for triple in match_info .matches :
537- workspace_dep_labels_by_triple [triple ].add (":" + dep_name )
617+ if not is_first_party_dep :
618+ workspace_dep_labels_by_triple [triple ].add (":" + dep_name )
538619 feature_resolutions .features_enabled [triple ].update (features )
539620
540621 # Set initial set of features from annotations
@@ -558,7 +639,7 @@ def _generate_hub_and_spokes(
558639
559640 _date (mctx , "set up initial deps!" )
560641
561- resolve (mctx , packages , feature_resolutions_by_fq_crate , platform_cfg_attrs_by_triple , debug )
642+ resolve (mctx , resolver_packages , feature_resolutions_by_fq_crate , platform_cfg_attrs_by_triple , debug )
562643
563644 # Validate that we aren't trying to enable any `dep:foo` features that were not even in the lockfile.
564645 for package in packages :
0 commit comments