diff --git a/extensions/prost/private/prost.bzl b/extensions/prost/private/prost.bzl index 9f903dd001..f06719db95 100644 --- a/extensions/prost/private/prost.bzl +++ b/extensions/prost/private/prost.bzl @@ -299,15 +299,12 @@ def _rust_prost_aspect_impl(target, ctx): # https://github.com/rust-analyzer/rust-analyzer/blob/2021-11-15/crates/project_model/src/workspace.rs#L529-L531 cfgs = ["test", "debug_assertions"] - crate_id = "prost-" + dep_variant_info.crate_info.root.path - rust_analyzer_info = write_rust_analyzer_spec_file(ctx, ctx.rule.attr, ctx.label, RustAnalyzerInfo( - id = crate_id, aliases = {}, crate = dep_variant_info.crate_info, cfgs = cfgs, env = dep_variant_info.crate_info.rustc_env, - deps = depset([dep.id for dep in rust_analyzer_deps]).to_list(), + deps = rust_analyzer_deps, crate_specs = depset(transitive = [dep.crate_specs for dep in rust_analyzer_deps]), proc_macro_dylib_path = None, build_info = dep_variant_info.build_info, @@ -390,10 +387,7 @@ def _rust_prost_library_impl(ctx): rust_generated_srcs = rust_generated_srcs, proto_descriptor_set = proto_descriptor_set, ), - RustAnalyzerGroupInfo( - crate_specs = proto_dep[RustAnalyzerInfo].crate_specs, - deps = proto_dep[RustAnalyzerInfo].deps, - ), + RustAnalyzerGroupInfo(deps = [proto_dep[RustAnalyzerInfo]]), ] rust_prost_library = rule( diff --git a/rust/private/providers.bzl b/rust/private/providers.bzl index 0482cab7e8..97c4500b3b 100644 --- a/rust/private/providers.bzl +++ b/rust/private/providers.bzl @@ -157,14 +157,13 @@ TestCrateInfo = provider( RustAnalyzerInfo = provider( doc = "RustAnalyzerInfo holds rust crate metadata for targets", fields = { - "aliases": "Dict[String, String]: Maps crate IDs to Replacement names these targets should be known as in Rust code", + "aliases": "Dict[RustAnalyzerInfo, String]: Replacement names these targets should be known as in Rust code", "build_info": "BuildInfo: build info for this crate if present", "cfgs": "List[String]: features or other compilation `--cfg` settings", "crate": "CrateInfo: Crate information.", "crate_specs": "Depset[File]: transitive closure of OutputGroupInfo files", - "deps": "List[String]: IDs of direct dependency crates", + "deps": "List[RustAnalyzerInfo]: direct dependencies", "env": "Dict[String: String]: Environment variables, used for the `env!` macro", - "id": "String: Arbitrary unique ID for this crate", "proc_macro_dylib_path": "File: compiled shared library output of proc-macro rule", }, ) @@ -172,7 +171,6 @@ RustAnalyzerInfo = provider( RustAnalyzerGroupInfo = provider( doc = "RustAnalyzerGroupInfo holds multiple RustAnalyzerInfos", fields = { - "crate_specs": "Depset[File]: transitive closure of OutputGroupInfo files", - "deps": "List[String]: crate IDs of direct dependencies", + "deps": "List[RustAnalyzerInfo]: direct dependencies", }, ) diff --git a/rust/private/rust_analyzer.bzl b/rust/private/rust_analyzer.bzl index 6673a454e5..bc12306a82 100644 --- a/rust/private/rust_analyzer.bzl +++ b/rust/private/rust_analyzer.bzl @@ -53,7 +53,6 @@ def write_rust_analyzer_spec_file(ctx, attrs, owner, base_info): cfgs = base_info.cfgs, env = base_info.env, deps = base_info.deps, - id = base_info.id, crate_specs = depset(direct = [crate_spec], transitive = [base_info.crate_specs]), proc_macro_dylib_path = base_info.proc_macro_dylib_path, build_info = base_info.build_info, @@ -73,6 +72,21 @@ def write_rust_analyzer_spec_file(ctx, attrs, owner, base_info): return rust_analyzer_info +def _accumulate_rust_analyzer_info(dep_infos_to_accumulate, label_index_to_accumulate, dep): + if dep == None: + return + if RustAnalyzerInfo in dep: + label_index_to_accumulate[dep.label] = dep[RustAnalyzerInfo] + dep_infos_to_accumulate.append(dep[RustAnalyzerInfo]) + if RustAnalyzerGroupInfo in dep: + for expanded_dep in dep[RustAnalyzerGroupInfo].deps: + label_index_to_accumulate[expanded_dep.crate.owner] = expanded_dep + dep_infos_to_accumulate.append(expanded_dep) + +def _accumulate_rust_analyzer_infos(dep_infos_to_accumulate, label_index_to_accumulate, deps_attr): + for dep in deps_attr: + _accumulate_rust_analyzer_info(dep_infos_to_accumulate, label_index_to_accumulate, dep) + def _rust_analyzer_aspect_impl(target, ctx): if (rust_common.crate_info not in target and rust_common.test_crate_info not in target and @@ -93,31 +107,22 @@ def _rust_analyzer_aspect_impl(target, ctx): cfgs += [f[6:] for f in ctx.rule.attr.rustc_flags if f.startswith("--cfg ") or f.startswith("--cfg=")] build_info = None + dep_infos = [] + labels_to_rais = {} + for dep in getattr(ctx.rule.attr, "deps", []): # Save BuildInfo if we find any (for build script output) if BuildInfo in dep: build_info = dep[BuildInfo] - # Gather required info from dependencies. - label_to_id = {} # {Label of dependency => crate_id} - crate_specs = [] # [depset of File - transitive crate_spec.json files] - attrs = ctx.rule.attr - all_deps = getattr(attrs, "deps", []) + getattr(attrs, "proc_macro_deps", []) + \ - [dep for dep in [getattr(attrs, "crate", None), getattr(attrs, "actual", None)] if dep != None] - for dep in all_deps: - if RustAnalyzerInfo in dep: - label_to_id[dep.label] = dep[RustAnalyzerInfo].id - crate_specs.append(dep[RustAnalyzerInfo].crate_specs) - if RustAnalyzerGroupInfo in dep: - for expanded_dep in dep[RustAnalyzerGroupInfo].deps: - label_to_id[expanded_dep] = expanded_dep - crate_specs.append(dep[RustAnalyzerGroupInfo].crate_specs) - - deps = label_to_id.values() - crate_specs = depset(transitive = crate_specs) + _accumulate_rust_analyzer_infos(dep_infos, labels_to_rais, getattr(ctx.rule.attr, "deps", [])) + _accumulate_rust_analyzer_infos(dep_infos, labels_to_rais, getattr(ctx.rule.attr, "proc_macro_deps", [])) + + _accumulate_rust_analyzer_info(dep_infos, labels_to_rais, getattr(ctx.rule.attr, "crate", None)) + _accumulate_rust_analyzer_info(dep_infos, labels_to_rais, getattr(ctx.rule.attr, "actual", None)) if rust_common.crate_group_info in target: - return [RustAnalyzerGroupInfo(deps = deps, crate_specs = crate_specs)] + return [RustAnalyzerGroupInfo(deps = dep_infos)] elif rust_common.crate_info in target: crate_info = target[rust_common.crate_info] elif rust_common.test_crate_info in target: @@ -125,23 +130,18 @@ def _rust_analyzer_aspect_impl(target, ctx): else: fail("Unexpected target type: {}".format(target)) - aliases = { - label_to_id[target.label]: name - for (target, name) in getattr(attrs, "aliases", {}).items() - if target.label in label_to_id - } - - # An arbitrary unique and stable identifier. - crate_id = "ID-" + crate_info.root.path + aliases = {} + for aliased_target, aliased_name in getattr(ctx.rule.attr, "aliases", {}).items(): + if aliased_target.label in labels_to_rais: + aliases[labels_to_rais[aliased_target.label]] = aliased_name rust_analyzer_info = write_rust_analyzer_spec_file(ctx, ctx.rule.attr, ctx.label, RustAnalyzerInfo( - id = crate_id, aliases = aliases, crate = crate_info, cfgs = cfgs, env = crate_info.rustc_env, - deps = deps, - crate_specs = crate_specs, + deps = dep_infos, + crate_specs = depset(transitive = [dep.crate_specs for dep in dep_infos]), proc_macro_dylib_path = find_proc_macro_dylib_path(toolchain, target), build_info = build_info, )) @@ -193,6 +193,14 @@ _WORKSPACE_TEMPLATE = "__WORKSPACE__/" _EXEC_ROOT_TEMPLATE = "__EXEC_ROOT__/" _OUTPUT_BASE_TEMPLATE = "__OUTPUT_BASE__/" +def _crate_id(crate_info): + """Returns a unique stable identifier for a crate + + Returns: + (string): This crate's unique stable id. + """ + return "ID-" + crate_info.root.path + def _create_single_crate(ctx, attrs, info): """Creates a crate in the rust-project.json format. @@ -206,7 +214,8 @@ def _create_single_crate(ctx, attrs, info): """ crate_name = info.crate.name crate = dict() - crate["crate_id"] = info.id + crate_id = _crate_id(info.crate) + crate["crate_id"] = crate_id crate["display_name"] = crate_name crate["edition"] = info.crate.edition crate["env"] = {} @@ -254,8 +263,8 @@ def _create_single_crate(ctx, attrs, info): # There's one exception - if the dependency is the same crate name as the # the crate being processed, we don't add it as a dependency to itself. This is # common and expected - `rust_test.crate` pointing to the `rust_library`. - crate["deps"] = [id for id in info.deps if id != info.id] - crate["aliases"] = info.aliases + crate["deps"] = [_crate_id(dep.crate) for dep in info.deps if _crate_id(dep.crate) != crate_id] + crate["aliases"] = {_crate_id(alias_target.crate): alias_name for alias_target, alias_name in info.aliases.items()} crate["cfg"] = info.cfgs toolchain = find_toolchain(ctx) crate["target"] = (_EXEC_ROOT_TEMPLATE + toolchain.target_json.path) if toolchain.target_json else toolchain.target_flag_value