@@ -130,7 +130,10 @@ def cargo_toml_dep_to_dep_dict(dep, spec, workspace_cargo_toml_json = None, is_b
130130 return inherited
131131
132132 if type (spec ) == "string" :
133- converted = {"name" : dep }
133+ converted = {
134+ "name" : dep ,
135+ "req" : spec ,
136+ }
134137 else :
135138 converted = {
136139 "name" : dep ,
@@ -140,6 +143,8 @@ def cargo_toml_dep_to_dep_dict(dep, spec, workspace_cargo_toml_json = None, is_b
140143 }
141144 if "package" in spec :
142145 converted ["package" ] = spec ["package" ]
146+ if spec .get ("version" ):
147+ converted ["req" ] = spec ["version" ]
143148
144149 if is_build :
145150 converted ["kind" ] = "build"
@@ -199,8 +204,11 @@ def prepare_possible_deps(dependencies, converter = None, skip_internal_rustc_pl
199204
200205 return possible_deps
201206
207+ def dep_package_name (dep ):
208+ return dep .get ("package" ) or dep ["name" ]
209+
202210def compute_package_fq_deps (package , versions_by_name , strict = True ):
203- possible_dep_fq_crate_by_name = {}
211+ possible_dep_fq_crates_by_name = {}
204212
205213 for maybe_fq_dep in package .get ("dependencies" , []):
206214 idx = maybe_fq_dep .find (" " )
@@ -216,9 +224,36 @@ def compute_package_fq_deps(package, versions_by_name, strict = True):
216224 dep = maybe_fq_dep [:idx ]
217225 resolved_version = maybe_fq_dep [idx + 1 :]
218226
219- possible_dep_fq_crate_by_name [dep ] = fq_crate (dep , resolved_version )
227+ existing = possible_dep_fq_crates_by_name .get (dep )
228+ if not existing :
229+ existing = []
230+ possible_dep_fq_crates_by_name [dep ] = existing
231+ existing .append (fq_crate (dep , resolved_version ))
232+
233+ return possible_dep_fq_crates_by_name
234+
235+ def select_package_fq_dep (dep , fq_deps ):
236+ dep_package = dep_package_name (dep )
237+ candidates = fq_deps .get (dep_package )
238+ if not candidates :
239+ return None
240+
241+ if len (candidates ) == 1 :
242+ return candidates [0 ]
220243
221- return possible_dep_fq_crate_by_name
244+ req = dep .get ("req" )
245+ if not req :
246+ return None
247+
248+ versions = [
249+ candidate [len (dep_package ) + 1 :]
250+ for candidate in candidates
251+ ]
252+ version = select_matching_version (req , versions )
253+ if not version :
254+ return None
255+
256+ return fq_crate (dep_package , version )
222257
223258def compute_workspace_fq_deps (workspace_members , versions_by_name ):
224259 workspace_fq_deps = {}
@@ -249,41 +284,55 @@ def _relative_to_workspace(path, workspace_root):
249284 rel_parts = [".." ] * (len (root_parts ) - common ) + path_parts [common :]
250285 return "/" .join (rel_parts ) if rel_parts else "."
251286
252- def split_lockfile_packages (hub_name , cargo_metadata , workspace_cargo_toml_json , all_packages ):
253- workspace_root = normalize_path (cargo_metadata ["workspace_root" ])
254- workspace_root_prefix = workspace_root + "/"
255-
256- workspace_member_keys = {}
257- for package in cargo_metadata ["packages" ]:
258- workspace_member_keys [(package ["name" ], package ["version" ])] = True
287+ def cargo_metadata_dep_paths_by_name (cargo_metadata , workspace_root ):
288+ package_dirs = {}
259289
260- dep_paths_by_name = {}
261290 for package in cargo_metadata ["packages" ]:
262291 for dep in package .get ("dependencies" , []):
263292 dep_path = dep .get ("path" )
264- if dep_path :
265- dep_paths_by_name [dep ["name" ]] = _relative_to_workspace (dep_path , workspace_root )
293+ if not dep_path :
294+ continue
295+
296+ package_dirs [dep ["name" ]] = _relative_to_workspace (dep_path , workspace_root )
297+
298+ return package_dirs
299+
300+ def cargo_toml_patch_paths_by_name (workspace_cargo_toml , workspace_root , workspace_package_dir = "" ):
301+ workspace_root = normalize_path (workspace_root )
302+ workspace_root_prefix = workspace_root + "/"
303+ package_dirs = {}
266304
267- patch_paths_by_name = {}
268- for registry_patches in workspace_cargo_toml_json .get ("patch" , {}).values ():
269- for name , spec in registry_patches .items ():
305+ for patches in workspace_cargo_toml .get ("patch" , {}).values ():
306+ for name , spec in patches .items ():
270307 if type (spec ) != "dict" :
271308 continue
272309
273310 patch_path = spec .get ("path" )
274311 if not patch_path :
275312 continue
276313
277- if patch_path .startswith ("/" ):
314+ package = spec .get ("package" ) or name
315+ if paths .is_absolute (patch_path ):
278316 normalized = normalize_path (patch_path )
279317 if not normalized .startswith (workspace_root_prefix ):
280318 fail ("Patch path for %s points outside the workspace: %s" % (name , patch_path ))
281- rel_patch_path = normalized .removeprefix (workspace_root_prefix )
319+ package_dirs [ package ] = normalized .removeprefix (workspace_root_prefix )
282320 else :
283- rel_patch_path = normalize_path (paths .normalize (patch_path ))
321+ package_dirs [ package ] = normalize_path (paths .normalize (paths . join ( workspace_package_dir , patch_path ) ))
284322
285- patch_paths_by_name [ name ] = rel_patch_path
323+ return package_dirs
286324
325+ def split_lockfile_packages (hub_name , cargo_metadata , workspace_cargo_toml , all_packages , repo_root = None , workspace_package_dir = "" ):
326+ if repo_root == None :
327+ repo_root = cargo_metadata ["workspace_root" ]
328+ repo_root = normalize_path (repo_root )
329+
330+ workspace_member_keys = {}
331+ for package in cargo_metadata ["packages" ]:
332+ workspace_member_keys [(package ["name" ], package ["version" ])] = True
333+
334+ dep_paths_by_name = cargo_metadata_dep_paths_by_name (cargo_metadata , repo_root )
335+ patch_paths_by_name = cargo_toml_patch_paths_by_name (workspace_cargo_toml , repo_root , workspace_package_dir )
287336 workspace_members = []
288337 packages = []
289338
@@ -302,13 +351,14 @@ def split_lockfile_packages(hub_name, cargo_metadata, workspace_cargo_toml_json,
302351 rel_path = patch_paths_by_name .get (pkg ["name" ]) or dep_paths_by_name .get (pkg ["name" ])
303352 local_path = rel_path
304353 if rel_path and not rel_path .startswith ("/" ):
305- local_path = paths .join (workspace_root , rel_path )
354+ local_path = paths .join (repo_root , rel_path )
306355
307356 if not local_path :
308357 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" ]))
309358
310359 pkg ["source" ] = "path+" + hub_name + "/" + rel_path
311360 pkg ["local_path" ] = local_path
361+ pkg ["package_dir" ] = rel_path
312362 packages .append (pkg )
313363
314364 return struct (
@@ -317,7 +367,7 @@ def split_lockfile_packages(hub_name, cargo_metadata, workspace_cargo_toml_json,
317367 workspace_member_keys = workspace_member_keys ,
318368 )
319369
320- def resolve_package_facts (packages , facts_by_fq_crate , platform_triples ):
370+ def resolve_package_facts (packages , facts_by_fq_crate , platform_triples , skip_internal_rustc_placeholder_crates = True ):
321371 feature_resolutions_by_fq_crate = {}
322372 versions_by_name = {}
323373
@@ -330,7 +380,10 @@ def resolve_package_facts(packages, facts_by_fq_crate, platform_triples):
330380
331381 fact = facts_by_fq_crate [fq_crate (name , version )]
332382 possible_features = fact ["features" ]
333- possible_deps = prepare_possible_deps (fact ["dependencies" ])
383+ possible_deps = prepare_possible_deps (
384+ fact ["dependencies" ],
385+ skip_internal_rustc_placeholder_crates = skip_internal_rustc_placeholder_crates ,
386+ )
334387 feature_resolutions = new_feature_resolutions (package_index , possible_deps , possible_features , platform_triples )
335388 package ["feature_resolutions" ] = feature_resolutions
336389 feature_resolutions_by_fq_crate [fq_crate (name , version )] = feature_resolutions
@@ -418,6 +471,7 @@ def resolve_cargo_workspace_members(
418471 debug ,
419472 dep_label_prefix = None ,
420473 allow_missing_resolved_deps = False ,
474+ skip_internal_rustc_placeholder_crates = True ,
421475 watch_manifests = False ,
422476 use_legacy_rules_rust_platforms = False ):
423477 platform_cfg_attrs = [triple_to_cfg_attrs (triple ) for triple in platform_triples ]
@@ -449,6 +503,7 @@ def resolve_cargo_workspace_members(
449503 possible_deps = prepare_possible_deps (
450504 package .get ("dependencies" , []),
451505 converter = cargo_metadata_dep_to_dep_dict ,
506+ skip_internal_rustc_placeholder_crates = skip_internal_rustc_placeholder_crates ,
452507 )
453508
454509 package_index = len (resolver_packages )
@@ -495,11 +550,12 @@ def resolve_cargo_workspace_members(
495550 for dep in package ["dependencies" ]:
496551 source = dep .get ("source" )
497552 dep_name = dep ["name" ]
498- dep_fq = fq_deps .get (dep_name )
553+ dep_package = dep_package_name (dep )
554+ dep_fq = select_package_fq_dep (dep , fq_deps )
499555 dep_version = None
500556 if dep_fq :
501- dep_version = dep_fq [len (dep_name ) + 1 :]
502- is_first_party_dep = not source and dep_version and (dep_name , dep_version ) in workspace_member_keys
557+ dep_version = dep_fq [len (dep_package ) + 1 :]
558+ is_first_party_dep = not source and dep_version and (dep_package , dep_version ) in workspace_member_keys
503559
504560 if dep_fq and dep_fq not in feature_resolutions_by_fq_crate and allow_missing_resolved_deps :
505561 continue
@@ -508,13 +564,13 @@ def resolve_cargo_workspace_members(
508564 req = dep ["req" ]
509565 fq = dep_fq
510566 if req and fq :
511- locked_version = fq [len (dep_name ) + 1 :]
567+ locked_version = fq [len (dep_package ) + 1 :]
512568 if not select_matching_version (req , [locked_version ]):
513569 fail (("ERROR: Cargo.lock out of sync: %s requires %s %s but Cargo.lock has %s.\n \n " +
514570 "If this is incorrect, please set `validate_lockfile = False` in `crate.from_cargo`\n " +
515571 "and file a bug at https://github.com/hermeticbuild/rules_rs/issues/new" ) % (
516572 package ["name" ],
517- dep_name ,
573+ dep_package ,
518574 req ,
519575 locked_version ,
520576 ))
0 commit comments