@@ -131,7 +131,10 @@ def cargo_toml_dep_to_dep_dict(dep, spec, package_name, workspace_cargo_toml_jso
131131 return inherited
132132
133133 if type (spec ) == "string" :
134- converted = {"name" : dep }
134+ converted = {
135+ "name" : dep ,
136+ "req" : spec ,
137+ }
135138 else :
136139 converted = {
137140 "name" : dep ,
@@ -141,6 +144,8 @@ def cargo_toml_dep_to_dep_dict(dep, spec, package_name, workspace_cargo_toml_jso
141144 }
142145 if "package" in spec :
143146 converted ["package" ] = spec ["package" ]
147+ if spec .get ("version" ):
148+ converted ["req" ] = spec ["version" ]
144149
145150 if is_build :
146151 converted ["kind" ] = "build"
@@ -202,8 +207,11 @@ def prepare_possible_deps(dependencies, converter = None, skip_internal_rustc_pl
202207
203208 return possible_deps
204209
210+ def dep_package_name (dep ):
211+ return dep .get ("package" ) or dep ["name" ]
212+
205213def compute_package_fq_deps (package , versions_by_name , strict = True ):
206- possible_dep_fq_crate_by_name = {}
214+ possible_dep_fq_crates_by_name = {}
207215
208216 for maybe_fq_dep in package .get ("dependencies" , []):
209217 idx = maybe_fq_dep .find (" " )
@@ -219,9 +227,36 @@ def compute_package_fq_deps(package, versions_by_name, strict = True):
219227 dep = maybe_fq_dep [:idx ]
220228 resolved_version = maybe_fq_dep [idx + 1 :]
221229
222- possible_dep_fq_crate_by_name [dep ] = fq_crate (dep , resolved_version )
230+ existing = possible_dep_fq_crates_by_name .get (dep )
231+ if not existing :
232+ existing = []
233+ possible_dep_fq_crates_by_name [dep ] = existing
234+ existing .append (fq_crate (dep , resolved_version ))
235+
236+ return possible_dep_fq_crates_by_name
237+
238+ def select_package_fq_dep (dep , fq_deps ):
239+ dep_package = dep_package_name (dep )
240+ candidates = fq_deps .get (dep_package )
241+ if not candidates :
242+ return None
243+
244+ if len (candidates ) == 1 :
245+ return candidates [0 ]
223246
224- return possible_dep_fq_crate_by_name
247+ req = dep .get ("req" )
248+ if not req :
249+ return None
250+
251+ versions = [
252+ candidate [len (dep_package ) + 1 :]
253+ for candidate in candidates
254+ ]
255+ version = select_matching_version (req , versions )
256+ if not version :
257+ return None
258+
259+ return fq_crate (dep_package , version )
225260
226261def compute_workspace_fq_deps (workspace_members , versions_by_name ):
227262 workspace_fq_deps = {}
@@ -252,41 +287,55 @@ def _relative_to_workspace(path, workspace_root):
252287 rel_parts = [".." ] * (len (root_parts ) - common ) + path_parts [common :]
253288 return "/" .join (rel_parts ) if rel_parts else "."
254289
255- def split_lockfile_packages (hub_name , cargo_metadata , workspace_cargo_toml_json , all_packages ):
256- workspace_root = normalize_path (cargo_metadata ["workspace_root" ])
257- workspace_root_prefix = workspace_root + "/"
258-
259- workspace_member_keys = {}
260- for package in cargo_metadata ["packages" ]:
261- workspace_member_keys [(package ["name" ], package ["version" ])] = True
290+ def cargo_metadata_dep_paths_by_name (cargo_metadata , workspace_root ):
291+ package_dirs = {}
262292
263- dep_paths_by_name = {}
264293 for package in cargo_metadata ["packages" ]:
265294 for dep in package .get ("dependencies" , []):
266295 dep_path = dep .get ("path" )
267- if dep_path :
268- dep_paths_by_name [dep ["name" ]] = _relative_to_workspace (dep_path , workspace_root )
296+ if not dep_path :
297+ continue
298+
299+ package_dirs [dep ["name" ]] = _relative_to_workspace (dep_path , workspace_root )
300+
301+ return package_dirs
302+
303+ def cargo_toml_patch_paths_by_name (workspace_cargo_toml , workspace_root , workspace_package_dir = "" ):
304+ workspace_root = normalize_path (workspace_root )
305+ workspace_root_prefix = workspace_root + "/"
306+ package_dirs = {}
269307
270- patch_paths_by_name = {}
271- for registry_patches in workspace_cargo_toml_json .get ("patch" , {}).values ():
272- for name , spec in registry_patches .items ():
308+ for patches in workspace_cargo_toml .get ("patch" , {}).values ():
309+ for name , spec in patches .items ():
273310 if type (spec ) != "dict" :
274311 continue
275312
276313 patch_path = spec .get ("path" )
277314 if not patch_path :
278315 continue
279316
280- if patch_path .startswith ("/" ):
317+ package = spec .get ("package" ) or name
318+ if paths .is_absolute (patch_path ):
281319 normalized = normalize_path (patch_path )
282320 if not normalized .startswith (workspace_root_prefix ):
283321 fail ("Patch path for %s points outside the workspace: %s" % (name , patch_path ))
284- rel_patch_path = normalized .removeprefix (workspace_root_prefix )
322+ package_dirs [ package ] = normalized .removeprefix (workspace_root_prefix )
285323 else :
286- rel_patch_path = normalize_path (paths .normalize (patch_path ))
324+ package_dirs [ package ] = normalize_path (paths .normalize (paths . join ( workspace_package_dir , patch_path ) ))
287325
288- patch_paths_by_name [ name ] = rel_patch_path
326+ return package_dirs
289327
328+ def split_lockfile_packages (hub_name , cargo_metadata , workspace_cargo_toml , all_packages , repo_root = None , workspace_package_dir = "" ):
329+ if repo_root == None :
330+ repo_root = cargo_metadata ["workspace_root" ]
331+ repo_root = normalize_path (repo_root )
332+
333+ workspace_member_keys = {}
334+ for package in cargo_metadata ["packages" ]:
335+ workspace_member_keys [(package ["name" ], package ["version" ])] = True
336+
337+ dep_paths_by_name = cargo_metadata_dep_paths_by_name (cargo_metadata , repo_root )
338+ patch_paths_by_name = cargo_toml_patch_paths_by_name (workspace_cargo_toml , repo_root , workspace_package_dir )
290339 workspace_members = []
291340 packages = []
292341
@@ -305,21 +354,22 @@ def split_lockfile_packages(hub_name, cargo_metadata, workspace_cargo_toml_json,
305354 rel_path = patch_paths_by_name .get (pkg ["name" ]) or dep_paths_by_name .get (pkg ["name" ])
306355 local_path = rel_path
307356 if rel_path and not rel_path .startswith ("/" ):
308- local_path = paths .join (workspace_root , rel_path )
357+ local_path = paths .join (repo_root , rel_path )
309358
310359 if not local_path :
311360 fail ("Found a path dependency on %s %s but could not determine its path from Cargo.toml. Please declare it in [patch] or as a path dependency." % (pkg ["name" ], pkg ["version" ]))
312361
313362 pkg ["source" ] = "path+" + hub_name + "/" + rel_path
314363 pkg ["local_path" ] = local_path
364+ pkg ["package_dir" ] = rel_path
315365 packages .append (pkg )
316366
317367 return struct (
318368 packages = packages ,
319369 workspace_members = workspace_members ,
320370 )
321371
322- def resolve_package_facts (packages , facts_by_fq_crate , platform_triples ):
372+ def resolve_package_facts (packages , facts_by_fq_crate , platform_triples , skip_internal_rustc_placeholder_crates = True ):
323373 feature_resolutions_by_fq_crate = {}
324374 versions_by_name = {}
325375
@@ -332,7 +382,10 @@ def resolve_package_facts(packages, facts_by_fq_crate, platform_triples):
332382
333383 fact = facts_by_fq_crate [fq_crate (name , version )]
334384 possible_features = fact ["features" ]
335- possible_deps = prepare_possible_deps (fact ["dependencies" ])
385+ possible_deps = prepare_possible_deps (
386+ fact ["dependencies" ],
387+ skip_internal_rustc_placeholder_crates = skip_internal_rustc_placeholder_crates ,
388+ )
336389 feature_resolutions = new_feature_resolutions (package_index , possible_deps , possible_features , platform_triples )
337390 package ["feature_resolutions" ] = feature_resolutions
338391 feature_resolutions_by_fq_crate [fq_crate (name , version )] = feature_resolutions
@@ -420,6 +473,7 @@ def resolve_cargo_workspace_members(
420473 debug ,
421474 dep_label_prefix = None ,
422475 allow_missing_resolved_deps = False ,
476+ skip_internal_rustc_placeholder_crates = True ,
423477 watch_manifests = False ,
424478 use_legacy_rules_rust_platforms = False ):
425479 platform_cfg_attrs = [triple_to_cfg_attrs (triple ) for triple in platform_triples ]
@@ -451,6 +505,7 @@ def resolve_cargo_workspace_members(
451505 possible_deps = prepare_possible_deps (
452506 package .get ("dependencies" , []),
453507 converter = cargo_metadata_dep_to_dep_dict ,
508+ skip_internal_rustc_placeholder_crates = skip_internal_rustc_placeholder_crates ,
454509 )
455510
456511 package_index = len (resolver_packages )
@@ -497,11 +552,12 @@ def resolve_cargo_workspace_members(
497552 for dep in package ["dependencies" ]:
498553 source = dep .get ("source" )
499554 dep_name = dep ["name" ]
500- dep_fq = fq_deps .get (dep_name )
555+ dep_package = dep_package_name (dep )
556+ dep_fq = select_package_fq_dep (dep , fq_deps )
501557 dep_version = None
502558 if dep_fq :
503- dep_version = dep_fq [len (dep_name ) + 1 :]
504- is_first_party_dep = not source and dep_version and (dep_name , dep_version ) in workspace_member_keys
559+ dep_version = dep_fq [len (dep_package ) + 1 :]
560+ is_first_party_dep = not source and dep_version and (dep_package , dep_version ) in workspace_member_keys
505561
506562 if dep_fq and dep_fq not in feature_resolutions_by_fq_crate and allow_missing_resolved_deps :
507563 continue
@@ -510,13 +566,13 @@ def resolve_cargo_workspace_members(
510566 req = dep ["req" ]
511567 fq = dep_fq
512568 if req and fq :
513- locked_version = fq [len (dep_name ) + 1 :]
569+ locked_version = fq [len (dep_package ) + 1 :]
514570 if not select_matching_version (req , [locked_version ]):
515571 fail (("ERROR: Cargo.lock out of sync: %s requires %s %s but Cargo.lock has %s.\n \n " +
516572 "If this is incorrect, please set `validate_lockfile = False` in `crate.from_cargo`\n " +
517573 "and file a bug at https://github.com/hermeticbuild/rules_rs/issues/new" ) % (
518574 package ["name" ],
519- dep_name ,
575+ dep_package ,
520576 req ,
521577 locked_version ,
522578 ))
0 commit comments