@@ -110,7 +110,10 @@ def cargo_metadata_dep_to_dep_dict(dep):
110110
111111def _cargo_toml_dep_to_dep_dict_inner (dep , spec , is_build = False , target = None ):
112112 if type (spec ) == "string" :
113- converted = {"name" : dep }
113+ converted = {
114+ "name" : dep ,
115+ "req" : spec ,
116+ }
114117 else :
115118 converted = {
116119 "name" : dep ,
@@ -120,6 +123,8 @@ def _cargo_toml_dep_to_dep_dict_inner(dep, spec, is_build = False, target = None
120123 }
121124 if "package" in spec :
122125 converted ["package" ] = spec ["package" ]
126+ if spec .get ("version" ):
127+ converted ["req" ] = spec ["version" ]
123128
124129 if is_build :
125130 converted ["kind" ] = "build"
@@ -205,8 +210,11 @@ def prepare_possible_deps(dependencies, converter = None, skip_internal_rustc_pl
205210
206211 return possible_deps
207212
213+ def dep_package_name (dep ):
214+ return dep .get ("package" ) or dep ["name" ]
215+
208216def compute_package_fq_deps (package , versions_by_name , strict = True ):
209- possible_dep_fq_crate_by_name = {}
217+ possible_dep_fq_crates_by_name = {}
210218
211219 for maybe_fq_dep in package .get ("dependencies" , []):
212220 idx = maybe_fq_dep .find (" " )
@@ -222,9 +230,36 @@ def compute_package_fq_deps(package, versions_by_name, strict = True):
222230 dep = maybe_fq_dep [:idx ]
223231 resolved_version = maybe_fq_dep [idx + 1 :]
224232
225- possible_dep_fq_crate_by_name [dep ] = fq_crate (dep , resolved_version )
233+ existing = possible_dep_fq_crates_by_name .get (dep )
234+ if not existing :
235+ existing = []
236+ possible_dep_fq_crates_by_name [dep ] = existing
237+ existing .append (fq_crate (dep , resolved_version ))
238+
239+ return possible_dep_fq_crates_by_name
240+
241+ def select_package_fq_dep (dep , fq_deps ):
242+ dep_package = dep_package_name (dep )
243+ candidates = fq_deps .get (dep_package )
244+ if not candidates :
245+ return None
246+
247+ if len (candidates ) == 1 :
248+ return candidates [0 ]
226249
227- return possible_dep_fq_crate_by_name
250+ req = dep .get ("req" )
251+ if not req :
252+ return None
253+
254+ versions = [
255+ candidate [len (dep_package ) + 1 :]
256+ for candidate in candidates
257+ ]
258+ version = select_matching_version (req , versions )
259+ if not version :
260+ return None
261+
262+ return fq_crate (dep_package , version )
228263
229264def compute_workspace_fq_deps (workspace_members , versions_by_name ):
230265 workspace_fq_deps = {}
@@ -255,41 +290,55 @@ def _relative_to_workspace(path, workspace_root):
255290 rel_parts = [".." ] * (len (root_parts ) - common ) + path_parts [common :]
256291 return "/" .join (rel_parts ) if rel_parts else "."
257292
258- def split_lockfile_packages (hub_name , cargo_metadata , workspace_cargo_toml_json , all_packages ):
259- workspace_root = normalize_path (cargo_metadata ["workspace_root" ])
260- workspace_root_prefix = workspace_root + "/"
261-
262- workspace_member_keys = {}
263- for package in cargo_metadata ["packages" ]:
264- workspace_member_keys [(package ["name" ], package ["version" ])] = True
293+ def cargo_metadata_dep_paths_by_name (cargo_metadata , workspace_root ):
294+ package_dirs = {}
265295
266- dep_paths_by_name = {}
267296 for package in cargo_metadata ["packages" ]:
268297 for dep in package .get ("dependencies" , []):
269298 dep_path = dep .get ("path" )
270- if dep_path :
271- dep_paths_by_name [dep ["name" ]] = _relative_to_workspace (dep_path , workspace_root )
299+ if not dep_path :
300+ continue
301+
302+ package_dirs [dep ["name" ]] = _relative_to_workspace (dep_path , workspace_root )
303+
304+ return package_dirs
305+
306+ def cargo_toml_patch_paths_by_name (workspace_cargo_toml , workspace_root , workspace_package_dir = "" ):
307+ workspace_root = normalize_path (workspace_root )
308+ workspace_root_prefix = workspace_root + "/"
309+ package_dirs = {}
272310
273- patch_paths_by_name = {}
274- for registry_patches in workspace_cargo_toml_json .get ("patch" , {}).values ():
275- for name , spec in registry_patches .items ():
311+ for patches in workspace_cargo_toml .get ("patch" , {}).values ():
312+ for name , spec in patches .items ():
276313 if type (spec ) != "dict" :
277314 continue
278315
279316 patch_path = spec .get ("path" )
280317 if not patch_path :
281318 continue
282319
283- if patch_path .startswith ("/" ):
320+ package = spec .get ("package" ) or name
321+ if paths .is_absolute (patch_path ):
284322 normalized = normalize_path (patch_path )
285323 if not normalized .startswith (workspace_root_prefix ):
286324 fail ("Patch path for %s points outside the workspace: %s" % (name , patch_path ))
287- rel_patch_path = normalized .removeprefix (workspace_root_prefix )
325+ package_dirs [ package ] = normalized .removeprefix (workspace_root_prefix )
288326 else :
289- rel_patch_path = normalize_path (paths .normalize (patch_path ))
327+ package_dirs [ package ] = normalize_path (paths .normalize (paths . join ( workspace_package_dir , patch_path ) ))
290328
291- patch_paths_by_name [ name ] = rel_patch_path
329+ return package_dirs
292330
331+ def split_lockfile_packages (hub_name , cargo_metadata , workspace_cargo_toml , all_packages , repo_root = None , workspace_package_dir = "" ):
332+ if repo_root == None :
333+ repo_root = cargo_metadata ["workspace_root" ]
334+ repo_root = normalize_path (repo_root )
335+
336+ workspace_member_keys = {}
337+ for package in cargo_metadata ["packages" ]:
338+ workspace_member_keys [(package ["name" ], package ["version" ])] = True
339+
340+ dep_paths_by_name = cargo_metadata_dep_paths_by_name (cargo_metadata , repo_root )
341+ patch_paths_by_name = cargo_toml_patch_paths_by_name (workspace_cargo_toml , repo_root , workspace_package_dir )
293342 workspace_members = []
294343 packages = []
295344
@@ -308,21 +357,22 @@ def split_lockfile_packages(hub_name, cargo_metadata, workspace_cargo_toml_json,
308357 rel_path = patch_paths_by_name .get (pkg ["name" ]) or dep_paths_by_name .get (pkg ["name" ])
309358 local_path = rel_path
310359 if rel_path and not rel_path .startswith ("/" ):
311- local_path = paths .join (workspace_root , rel_path )
360+ local_path = paths .join (repo_root , rel_path )
312361
313362 if not local_path :
314363 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" ]))
315364
316365 pkg ["source" ] = "path+" + hub_name + "/" + rel_path
317366 pkg ["local_path" ] = local_path
367+ pkg ["package_dir" ] = rel_path
318368 packages .append (pkg )
319369
320370 return struct (
321371 packages = packages ,
322372 workspace_members = workspace_members ,
323373 )
324374
325- def resolve_package_facts (packages , facts_by_fq_crate , platform_triples ):
375+ def resolve_package_facts (packages , facts_by_fq_crate , platform_triples , skip_internal_rustc_placeholder_crates = True ):
326376 feature_resolutions_by_fq_crate = {}
327377 versions_by_name = {}
328378
@@ -335,7 +385,10 @@ def resolve_package_facts(packages, facts_by_fq_crate, platform_triples):
335385
336386 fact = facts_by_fq_crate [fq_crate (name , version )]
337387 possible_features = fact ["features" ]
338- possible_deps = prepare_possible_deps (fact ["dependencies" ])
388+ possible_deps = prepare_possible_deps (
389+ fact ["dependencies" ],
390+ skip_internal_rustc_placeholder_crates = skip_internal_rustc_placeholder_crates ,
391+ )
339392 feature_resolutions = new_feature_resolutions (package_index , possible_deps , possible_features , platform_triples )
340393 package ["feature_resolutions" ] = feature_resolutions
341394 feature_resolutions_by_fq_crate [fq_crate (name , version )] = feature_resolutions
@@ -423,6 +476,7 @@ def resolve_cargo_workspace_members(
423476 debug ,
424477 dep_label_prefix = None ,
425478 allow_missing_resolved_deps = False ,
479+ skip_internal_rustc_placeholder_crates = True ,
426480 watch_manifests = False ,
427481 use_legacy_rules_rust_platforms = False ):
428482 platform_cfg_attrs = [triple_to_cfg_attrs (triple ) for triple in platform_triples ]
@@ -454,6 +508,7 @@ def resolve_cargo_workspace_members(
454508 possible_deps = prepare_possible_deps (
455509 package .get ("dependencies" , []),
456510 converter = cargo_metadata_dep_to_dep_dict ,
511+ skip_internal_rustc_placeholder_crates = skip_internal_rustc_placeholder_crates ,
457512 )
458513
459514 package_index = len (resolver_packages )
@@ -500,11 +555,12 @@ def resolve_cargo_workspace_members(
500555 for dep in package ["dependencies" ]:
501556 source = dep .get ("source" )
502557 dep_name = dep ["name" ]
503- dep_fq = fq_deps .get (dep_name )
558+ dep_package = dep_package_name (dep )
559+ dep_fq = select_package_fq_dep (dep , fq_deps )
504560 dep_version = None
505561 if dep_fq :
506- dep_version = dep_fq [len (dep_name ) + 1 :]
507- is_first_party_dep = not source and dep_version and (dep_name , dep_version ) in workspace_member_keys
562+ dep_version = dep_fq [len (dep_package ) + 1 :]
563+ is_first_party_dep = not source and dep_version and (dep_package , dep_version ) in workspace_member_keys
508564
509565 if dep_fq and dep_fq not in feature_resolutions_by_fq_crate and allow_missing_resolved_deps :
510566 continue
@@ -513,13 +569,13 @@ def resolve_cargo_workspace_members(
513569 req = dep ["req" ]
514570 fq = dep_fq
515571 if req and fq :
516- locked_version = fq [len (dep_name ) + 1 :]
572+ locked_version = fq [len (dep_package ) + 1 :]
517573 if not select_matching_version (req , [locked_version ]):
518574 fail (("ERROR: Cargo.lock out of sync: %s requires %s %s but Cargo.lock has %s.\n \n " +
519575 "If this is incorrect, please set `validate_lockfile = False` in `crate.from_cargo`\n " +
520576 "and file a bug at https://github.com/hermeticbuild/rules_rs/issues/new" ) % (
521577 package ["name" ],
522- dep_name ,
578+ dep_package ,
523579 req ,
524580 locked_version ,
525581 ))
0 commit comments