| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133 | 
							- #!/usr/bin/env python3
 
- # Copyright 2020 The gRPC Authors
 
- #
 
- # Licensed under the Apache License, Version 2.0 (the "License");
 
- # you may not use this file except in compliance with the License.
 
- # You may obtain a copy of the License at
 
- #
 
- #     http://www.apache.org/licenses/LICENSE-2.0
 
- #
 
- # Unless required by applicable law or agreed to in writing, software
 
- # distributed under the License is distributed on an "AS IS" BASIS,
 
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
- # See the License for the specific language governing permissions and
 
- # limitations under the License.
 
- # Script to extract build metadata from bazel BUILD.
 
- # To avoid having two sources of truth for the build metadata (build
 
- # targets, source files, header files etc.), this script analyzes the contents
 
- # of bazel BUILD files and generates a YAML file (currently called
 
- # build_autogenerated.yaml). The format and semantics of the generated YAML files
 
- # is chosen to match the format of a "build.yaml" file, which used
 
- # to be build the source of truth for gRPC build before bazel became
 
- # the primary build system.
 
- # A good basic overview of the "build.yaml" format is available here:
 
- # https://github.com/grpc/grpc/blob/master/templates/README.md. Note that
 
- # while useful as an overview, the doc does not act as formal spec
 
- # (formal spec does not exist in fact) and the doc can be incomplete,
 
- # inaccurate or slightly out of date.
 
- # TODO(jtattermusch): In the future we want to get rid of the legacy build.yaml
 
- # format entirely or simplify it to a point where it becomes self-explanatory
 
- # and doesn't need any detailed documentation.
 
- import subprocess
 
- import yaml
 
- import xml.etree.ElementTree as ET
 
- import os
 
- import collections
 
- import sys
 
- import re
 
- from typing import List, Any, Dict, Optional, Iterable
 
- import build_cleaner
 
- BuildMetadata = Dict[str, Any]
 
- BuildDict = Dict[str, BuildMetadata]
 
- BuildYaml = Dict[str, Any]
 
- def _bazel_query_xml_tree(query: str) -> ET.Element:
 
-     """Get xml output of bazel query invocation, parsed as XML tree"""
 
-     output = subprocess.check_output(
 
-         ['tools/bazel', 'query', '--noimplicit_deps', '--output', 'xml', query])
 
-     return ET.fromstring(output)
 
- def _rule_dict_from_xml_node(rule_xml_node):
 
-     """Converts XML node representing a rule (obtained from "bazel query --output xml") to a dictionary that contains all the metadata we will need."""
 
-     result = {
 
-         'class': rule_xml_node.attrib.get('class'),
 
-         'name': rule_xml_node.attrib.get('name'),
 
-         'srcs': [],
 
-         'hdrs': [],
 
-         'deps': [],
 
-         'data': [],
 
-         'tags': [],
 
-         'args': [],
 
-         'generator_function': None,
 
-         'size': None,
 
-         'flaky': False,
 
-     }
 
-     for child in rule_xml_node:
 
-         # all the metadata we want is stored under "list" tags
 
-         if child.tag == 'list':
 
-             list_name = child.attrib['name']
 
-             if list_name in ['srcs', 'hdrs', 'deps', 'data', 'tags', 'args']:
 
-                 result[list_name] += [item.attrib['value'] for item in child]
 
-         if child.tag == 'string':
 
-             string_name = child.attrib['name']
 
-             if string_name in ['generator_function', 'size']:
 
-                 result[string_name] = child.attrib['value']
 
-         if child.tag == 'boolean':
 
-             bool_name = child.attrib['name']
 
-             if bool_name in ['flaky']:
 
-                 result[bool_name] = child.attrib['value'] == 'true'
 
-     return result
 
- def _extract_rules_from_bazel_xml(xml_tree):
 
-     """Extract bazel rules from an XML tree node obtained from "bazel query --output xml" command."""
 
-     result = {}
 
-     for child in xml_tree:
 
-         if child.tag == 'rule':
 
-             rule_dict = _rule_dict_from_xml_node(child)
 
-             rule_clazz = rule_dict['class']
 
-             rule_name = rule_dict['name']
 
-             if rule_clazz in [
 
-                     'cc_library', 'cc_binary', 'cc_test', 'cc_proto_library',
 
-                     'proto_library'
 
-             ]:
 
-                 if rule_name in result:
 
-                     raise Exception('Rule %s already present' % rule_name)
 
-                 result[rule_name] = rule_dict
 
-     return result
 
- def _get_bazel_label(target_name: str) -> str:
 
-     if ':' in target_name:
 
-         return '//%s' % target_name
 
-     else:
 
-         return '//:%s' % target_name
 
- def _extract_source_file_path(label: str) -> str:
 
-     """Gets relative path to source file from bazel deps listing"""
 
-     if label.startswith('//'):
 
-         label = label[len('//'):]
 
-     # labels in form //:src/core/lib/surface/call_test_only.h
 
-     if label.startswith(':'):
 
-         label = label[len(':'):]
 
-     # labels in form //test/core/util:port.cc
 
-     label = label.replace(':', '/')
 
-     return label
 
- def _extract_public_headers(bazel_rule: BuildMetadata) -> List[str]:
 
-     """Gets list of public headers from a bazel rule"""
 
-     result = []
 
-     for dep in bazel_rule['hdrs']:
 
-         if dep.startswith('//:include/') and dep.endswith('.h'):
 
-             result.append(_extract_source_file_path(dep))
 
-     return list(sorted(result))
 
- def _extract_nonpublic_headers(bazel_rule: BuildMetadata) -> List[str]:
 
-     """Gets list of non-public headers from a bazel rule"""
 
-     result = []
 
-     for dep in bazel_rule['hdrs']:
 
-         if dep.startswith('//') and not dep.startswith(
 
-                 '//:include/') and dep.endswith('.h'):
 
-             result.append(_extract_source_file_path(dep))
 
-     return list(sorted(result))
 
- def _extract_sources(bazel_rule: BuildMetadata) -> List[str]:
 
-     """Gets list of source files from a bazel rule"""
 
-     result = []
 
-     for dep in bazel_rule['srcs']:
 
-         if dep.startswith('//') and (dep.endswith('.cc') or dep.endswith('.c')
 
-                                      or dep.endswith('.proto')):
 
-             result.append(_extract_source_file_path(dep))
 
-     return list(sorted(result))
 
- def _extract_deps(bazel_rule: BuildMetadata,
 
-                   bazel_rules: BuildDict) -> List[str]:
 
-     """Gets list of deps from from a bazel rule"""
 
-     return list(sorted(bazel_rule['deps']))
 
- def _create_target_from_bazel_rule(target_name: str,
 
-                                    bazel_rules: BuildDict) -> BuildMetadata:
 
-     """Create build.yaml-like target definition from bazel metadata"""
 
-     bazel_rule = bazel_rules[_get_bazel_label(target_name)]
 
-     # Create a template for our target from the bazel rule. Initially we only
 
-     # populate some "private" fields with the original info we got from bazel
 
-     # and only later we will populate the public fields (once we do some extra
 
-     # postprocessing).
 
-     result = {
 
-         'name': target_name,
 
-         '_PUBLIC_HEADERS_BAZEL': _extract_public_headers(bazel_rule),
 
-         '_HEADERS_BAZEL': _extract_nonpublic_headers(bazel_rule),
 
-         '_SRC_BAZEL': _extract_sources(bazel_rule),
 
-         '_DEPS_BAZEL': _extract_deps(bazel_rule, bazel_rules),
 
-         'public_headers': bazel_rule['_COLLAPSED_PUBLIC_HEADERS'],
 
-         'headers': bazel_rule['_COLLAPSED_HEADERS'],
 
-         'src': bazel_rule['_COLLAPSED_SRCS'],
 
-         'deps': bazel_rule['_COLLAPSED_DEPS'],
 
-     }
 
-     return result
 
- def _external_dep_name_from_bazel_dependency(bazel_dep: str) -> Optional[str]:
 
-     """Returns name of dependency if external bazel dependency is provided or None"""
 
-     if bazel_dep.startswith('@com_google_absl//'):
 
-         # special case for add dependency on one of the absl libraries (there is not just one absl library)
 
-         prefixlen = len('@com_google_absl//')
 
-         return bazel_dep[prefixlen:]
 
-     elif bazel_dep == '//external:upb_lib':
 
-         return 'upb'
 
-     elif bazel_dep == '//external:benchmark':
 
-         return 'benchmark'
 
-     elif bazel_dep == '//external:libssl':
 
-         return 'libssl'
 
-     else:
 
-         # all the other external deps such as protobuf, cares, zlib
 
-         # don't need to be listed explicitly, they are handled automatically
 
-         # by the build system (make, cmake)
 
-         return None
 
- def _compute_transitive_metadata(
 
-         rule_name: str, bazel_rules: Any,
 
-         bazel_label_to_dep_name: Dict[str, str]) -> None:
 
-     """Computes the final build metadata for Bazel target with rule_name.
 
-     The dependencies that will appear on the deps list are:
 
-     * Public build targets including binaries and tests;
 
-     * External targets, like absl, re2.
 
-     All other intermediate dependencies will be merged, which means their
 
-     source file, headers, etc. will be collected into one build target. This
 
-     step of processing will greatly reduce the complexity of the generated
 
-     build specifications for other build systems, like CMake, Make, setuptools.
 
-     The final build metadata are:
 
-     * _TRANSITIVE_DEPS: all the transitive dependencies including intermediate
 
-                         targets;
 
-     * _COLLAPSED_DEPS:  dependencies that fits our requirement above, and it
 
-                         will remove duplicated items and produce the shortest
 
-                         possible dependency list in alphabetical order;
 
-     * _COLLAPSED_SRCS:  the merged source files;
 
-     * _COLLAPSED_PUBLIC_HEADERS: the merged public headers;
 
-     * _COLLAPSED_HEADERS: the merged non-public headers;
 
-     * _EXCLUDE_DEPS: intermediate targets to exclude when performing collapsing
 
-       of sources and dependencies. 
 
-     For the collapsed_deps, the algorithm improved cases like:
 
-     The result in the past:
 
-         end2end_tests -> [grpc_test_util, grpc, gpr, address_sorting, upb]
 
-         grpc_test_util -> [grpc, gpr, address_sorting, upb, ...]
 
-         grpc -> [gpr, address_sorting, upb, ...]
 
-     
 
-     The result of the algorithm:
 
-         end2end_tests -> [grpc_test_util]
 
-         grpc_test_util -> [grpc]
 
-         grpc -> [gpr, address_sorting, upb, ...]
 
-     """
 
-     bazel_rule = bazel_rules[rule_name]
 
-     direct_deps = _extract_deps(bazel_rule, bazel_rules)
 
-     transitive_deps = set()
 
-     collapsed_deps = set()
 
-     exclude_deps = set()
 
-     collapsed_srcs = set(_extract_sources(bazel_rule))
 
-     collapsed_public_headers = set(_extract_public_headers(bazel_rule))
 
-     collapsed_headers = set(_extract_nonpublic_headers(bazel_rule))
 
-     for dep in direct_deps:
 
-         external_dep_name_maybe = _external_dep_name_from_bazel_dependency(dep)
 
-         if dep in bazel_rules:
 
-             # Descend recursively, but no need to do that for external deps
 
-             if external_dep_name_maybe is None:
 
-                 if "_PROCESSING_DONE" not in bazel_rules[dep]:
 
-                     # This item is not processed before, compute now
 
-                     _compute_transitive_metadata(dep, bazel_rules,
 
-                                                  bazel_label_to_dep_name)
 
-                 transitive_deps.update(bazel_rules[dep].get(
 
-                     '_TRANSITIVE_DEPS', []))
 
-                 collapsed_deps.update(
 
-                     collapsed_deps, bazel_rules[dep].get('_COLLAPSED_DEPS', []))
 
-                 exclude_deps.update(bazel_rules[dep].get('_EXCLUDE_DEPS', []))
 
-         # This dep is a public target, add it as a dependency
 
-         if dep in bazel_label_to_dep_name:
 
-             transitive_deps.update([bazel_label_to_dep_name[dep]])
 
-             collapsed_deps.update(collapsed_deps,
 
-                                   [bazel_label_to_dep_name[dep]])
 
-             # Add all the transitive deps of our every public dep to exclude
 
-             # list since we want to avoid building sources that are already
 
-             # built by our dependencies
 
-             exclude_deps.update(bazel_rules[dep]['_TRANSITIVE_DEPS'])
 
-             continue
 
-         # This dep is an external target, add it as a dependency
 
-         if external_dep_name_maybe is not None:
 
-             transitive_deps.update([external_dep_name_maybe])
 
-             collapsed_deps.update(collapsed_deps, [external_dep_name_maybe])
 
-             continue
 
-     # Direct dependencies are part of transitive dependencies
 
-     transitive_deps.update(direct_deps)
 
-     # Calculate transitive public deps (needed for collapsing sources)
 
-     transitive_public_deps = set(
 
-         filter(lambda x: x in bazel_label_to_dep_name, transitive_deps))
 
-     # Remove intermediate targets that our public dependencies already depend
 
-     # on. This is the step that further shorten the deps list.
 
-     collapsed_deps = set(filter(lambda x: x not in exclude_deps,
 
-                                 collapsed_deps))
 
-     # Compute the final source files and headers for this build target whose
 
-     # name is `rule_name` (input argument of this function).
 
-     #
 
-     # Imaging a public target PX has transitive deps [IA, IB, PY, IC, PZ]. PX,
 
-     # PY and PZ are public build targets. And IA, IB, IC are intermediate
 
-     # targets. In addition, PY depends on IC.
 
-     #
 
-     # Translate the condition into dependency graph:
 
-     #   PX -> [IA, IB, PY, IC, PZ]
 
-     #   PY -> [IC]
 
-     #   Public targets: [PX, PY, PZ]
 
-     #
 
-     # The collapsed dependencies of PX: [PY, PZ].
 
-     # The excluded dependencies of X: [PY, IC, PZ].
 
-     # (IC is excluded as a dependency of PX. It is already included in PY, hence
 
-     # it would be redundant to include it again.)
 
-     #
 
-     # Target PX should include source files and headers of [PX, IA, IB] as final
 
-     # build metadata.
 
-     for dep in transitive_deps:
 
-         if dep not in exclude_deps and dep not in transitive_public_deps:
 
-             if dep in bazel_rules:
 
-                 collapsed_srcs.update(_extract_sources(bazel_rules[dep]))
 
-                 collapsed_public_headers.update(
 
-                     _extract_public_headers(bazel_rules[dep]))
 
-                 collapsed_headers.update(
 
-                     _extract_nonpublic_headers(bazel_rules[dep]))
 
-     # This item is a "visited" flag
 
-     bazel_rule['_PROCESSING_DONE'] = True
 
-     # Following items are described in the docstinrg.
 
-     bazel_rule['_TRANSITIVE_DEPS'] = list(sorted(transitive_deps))
 
-     bazel_rule['_COLLAPSED_DEPS'] = list(sorted(collapsed_deps))
 
-     bazel_rule['_COLLAPSED_SRCS'] = list(sorted(collapsed_srcs))
 
-     bazel_rule['_COLLAPSED_PUBLIC_HEADERS'] = list(
 
-         sorted(collapsed_public_headers))
 
-     bazel_rule['_COLLAPSED_HEADERS'] = list(sorted(collapsed_headers))
 
-     bazel_rule['_EXCLUDE_DEPS'] = list(sorted(exclude_deps))
 
- # TODO(jtattermusch): deduplicate with transitive_dependencies.py (which has a slightly different logic)
 
- # TODO(jtattermusch): This is done to avoid introducing too many intermediate
 
- # libraries into the build.yaml-based builds (which might in cause issues
 
- # building language-specific artifacts) and also because the libraries
 
- # in build.yaml-based build are generally considered units of distributions
 
- # (= public libraries that are visible to the user and are installable),
 
- # while in bazel builds it is customary to define larger number of smaller
 
- # "sublibraries". The need for elision (and expansion)
 
- # of intermediate libraries can be re-evaluated in the future.
 
- def _populate_transitive_metadata(bazel_rules: Any,
 
-                                   public_dep_names: Iterable[str]) -> None:
 
-     """Add 'transitive_deps' field for each of the rules"""
 
-     # Create the map between Bazel label and public dependency name
 
-     bazel_label_to_dep_name = {}
 
-     for dep_name in public_dep_names:
 
-         bazel_label_to_dep_name[_get_bazel_label(dep_name)] = dep_name
 
-     # Make sure we reached all the Bazel rules
 
-     # TODO(lidiz) potentially we could only update a subset of rules
 
-     for rule_name in bazel_rules:
 
-         if '_PROCESSING_DONE' not in bazel_rules[rule_name]:
 
-             _compute_transitive_metadata(rule_name, bazel_rules,
 
-                                          bazel_label_to_dep_name)
 
- def update_test_metadata_with_transitive_metadata(
 
-         all_extra_metadata: BuildDict, bazel_rules: BuildDict) -> None:
 
-     """Patches test build metadata with transitive metadata."""
 
-     for lib_name, lib_dict in all_extra_metadata.items():
 
-         # Skip if it isn't not an test
 
-         if lib_dict.get('build') != 'test' or lib_dict.get('_TYPE') != 'target':
 
-             continue
 
-         bazel_rule = bazel_rules[_get_bazel_label(lib_name)]
 
-         if '//external:benchmark' in bazel_rule['_TRANSITIVE_DEPS']:
 
-             lib_dict['benchmark'] = True
 
-             lib_dict['defaults'] = 'benchmark'
 
-         if '//external:gtest' in bazel_rule['_TRANSITIVE_DEPS']:
 
-             lib_dict['gtest'] = True
 
-             lib_dict['language'] = 'c++'
 
- def _generate_build_metadata(build_extra_metadata: BuildDict,
 
-                              bazel_rules: BuildDict) -> BuildDict:
 
-     """Generate build metadata in build.yaml-like format bazel build metadata and build.yaml-specific "extra metadata"."""
 
-     lib_names = list(build_extra_metadata.keys())
 
-     result = {}
 
-     for lib_name in lib_names:
 
-         lib_dict = _create_target_from_bazel_rule(lib_name, bazel_rules)
 
-         # populate extra properties from the build.yaml-specific "extra metadata"
 
-         lib_dict.update(build_extra_metadata.get(lib_name, {}))
 
-         # store to results
 
-         result[lib_name] = lib_dict
 
-     # Rename targets marked with "_RENAME" extra metadata.
 
-     # This is mostly a cosmetic change to ensure that we end up with build.yaml target
 
-     # names we're used to from the past (and also to avoid too long target names).
 
-     # The rename step needs to be made after we're done with most of processing logic
 
-     # otherwise the already-renamed libraries will have different names than expected
 
-     for lib_name in lib_names:
 
-         to_name = build_extra_metadata.get(lib_name, {}).get('_RENAME', None)
 
-         if to_name:
 
-             # store lib under the new name and also change its 'name' property
 
-             if to_name in result:
 
-                 raise Exception('Cannot rename target ' + str(lib_name) + ', ' +
 
-                                 str(to_name) + ' already exists.')
 
-             lib_dict = result.pop(lib_name)
 
-             lib_dict['name'] = to_name
 
-             result[to_name] = lib_dict
 
-             # dep names need to be updated as well
 
-             for lib_dict_to_update in result.values():
 
-                 lib_dict_to_update['deps'] = list([
 
-                     to_name if dep == lib_name else dep
 
-                     for dep in lib_dict_to_update['deps']
 
-                 ])
 
-     return result
 
- def _convert_to_build_yaml_like(lib_dict: BuildMetadata) -> BuildYaml:
 
-     lib_names = [
 
-         lib_name for lib_name in list(lib_dict.keys())
 
-         if lib_dict[lib_name].get('_TYPE', 'library') == 'library'
 
-     ]
 
-     target_names = [
 
-         lib_name for lib_name in list(lib_dict.keys())
 
-         if lib_dict[lib_name].get('_TYPE', 'library') == 'target'
 
-     ]
 
-     test_names = [
 
-         lib_name for lib_name in list(lib_dict.keys())
 
-         if lib_dict[lib_name].get('_TYPE', 'library') == 'test'
 
-     ]
 
-     # list libraries and targets in predefined order
 
-     lib_list = [lib_dict[lib_name] for lib_name in lib_names]
 
-     target_list = [lib_dict[lib_name] for lib_name in target_names]
 
-     test_list = [lib_dict[lib_name] for lib_name in test_names]
 
-     # get rid of temporary private fields prefixed with "_" and some other useless fields
 
-     for lib in lib_list:
 
-         for field_to_remove in [k for k in lib.keys() if k.startswith('_')]:
 
-             lib.pop(field_to_remove, None)
 
-     for target in target_list:
 
-         for field_to_remove in [k for k in target.keys() if k.startswith('_')]:
 
-             target.pop(field_to_remove, None)
 
-         target.pop('public_headers',
 
-                    None)  # public headers make no sense for targets
 
-     for test in test_list:
 
-         for field_to_remove in [k for k in test.keys() if k.startswith('_')]:
 
-             test.pop(field_to_remove, None)
 
-         test.pop('public_headers',
 
-                  None)  # public headers make no sense for tests
 
-     build_yaml_like = {
 
-         'libs': lib_list,
 
-         'filegroups': [],
 
-         'targets': target_list,
 
-         'tests': test_list,
 
-     }
 
-     return build_yaml_like
 
- def _extract_cc_tests(bazel_rules: BuildDict) -> List[str]:
 
-     """Gets list of cc_test tests from bazel rules"""
 
-     result = []
 
-     for bazel_rule in bazel_rules.values():
 
-         if bazel_rule['class'] == 'cc_test':
 
-             test_name = bazel_rule['name']
 
-             if test_name.startswith('//'):
 
-                 prefixlen = len('//')
 
-                 result.append(test_name[prefixlen:])
 
-     return list(sorted(result))
 
- def _exclude_unwanted_cc_tests(tests: List[str]) -> List[str]:
 
-     """Filters out bazel tests that we don't want to run with other build systems or we cannot build them reasonably"""
 
-     # most qps tests are autogenerated, we are fine without them
 
-     tests = [test for test in tests if not test.startswith('test/cpp/qps:')]
 
-     # we have trouble with census dependency outside of bazel
 
-     tests = [
 
-         test for test in tests
 
-         if not test.startswith('test/cpp/ext/filters/census:')
 
-     ]
 
-     tests = [
 
-         test for test in tests
 
-         if not test.startswith('test/cpp/microbenchmarks:bm_opencensus_plugin')
 
-     ]
 
-     # missing opencensus/stats/stats.h
 
-     tests = [
 
-         test for test in tests if not test.startswith(
 
-             'test/cpp/end2end:server_load_reporting_end2end_test')
 
-     ]
 
-     tests = [
 
-         test for test in tests if not test.startswith(
 
-             'test/cpp/server/load_reporter:lb_load_reporter_test')
 
-     ]
 
-     # The test uses --running_under_bazel cmdline argument
 
-     # To avoid the trouble needing to adjust it, we just skip the test
 
-     tests = [
 
-         test for test in tests if not test.startswith(
 
-             'test/cpp/naming:resolver_component_tests_runner_invoker')
 
-     ]
 
-     # the test requires 'client_crash_test_server' to be built
 
-     tests = [
 
-         test for test in tests
 
-         if not test.startswith('test/cpp/end2end:time_change_test')
 
-     ]
 
-     # the test requires 'client_crash_test_server' to be built
 
-     tests = [
 
-         test for test in tests
 
-         if not test.startswith('test/cpp/end2end:client_crash_test')
 
-     ]
 
-     # the test requires 'server_crash_test_client' to be built
 
-     tests = [
 
-         test for test in tests
 
-         if not test.startswith('test/cpp/end2end:server_crash_test')
 
-     ]
 
-     # test never existed under build.yaml and it fails -> skip it
 
-     tests = [
 
-         test for test in tests
 
-         if not test.startswith('test/core/tsi:ssl_session_cache_test')
 
-     ]
 
-     # the binary of this test does not get built with cmake
 
-     tests = [
 
-         test for test in tests
 
-         if not test.startswith('test/cpp/util:channelz_sampler_test')
 
-     ]
 
-     return tests
 
- def _generate_build_extra_metadata_for_tests(
 
-         tests: List[str], bazel_rules: BuildDict) -> BuildDict:
 
-     """For given tests, generate the "extra metadata" that we need for our "build.yaml"-like output. The extra metadata is generated from the bazel rule metadata by using a bunch of heuristics."""
 
-     test_metadata = {}
 
-     for test in tests:
 
-         test_dict = {'build': 'test', '_TYPE': 'target'}
 
-         bazel_rule = bazel_rules[_get_bazel_label(test)]
 
-         bazel_tags = bazel_rule['tags']
 
-         if 'manual' in bazel_tags:
 
-             # don't run the tests marked as "manual"
 
-             test_dict['run'] = False
 
-         if bazel_rule['flaky']:
 
-             # don't run tests that are marked as "flaky" under bazel
 
-             # because that would only add noise for the run_tests.py tests
 
-             # and seeing more failures for tests that we already know are flaky
 
-             # doesn't really help anything
 
-             test_dict['run'] = False
 
-         if 'no_uses_polling' in bazel_tags:
 
-             test_dict['uses_polling'] = False
 
-         if 'grpc_fuzzer' == bazel_rule['generator_function']:
 
-             # currently we hand-list fuzzers instead of generating them automatically
 
-             # because there's no way to obtain maxlen property from bazel BUILD file.
 
-             print('skipping fuzzer ' + test)
 
-             continue
 
-         # if any tags that restrict platform compatibility are present,
 
-         # generate the "platforms" field accordingly
 
-         # TODO(jtattermusch): there is also a "no_linux" tag, but we cannot take
 
-         # it into account as it is applied by grpc_cc_test when poller expansion
 
-         # is made (for tests where uses_polling=True). So for now, we just
 
-         # assume all tests are compatible with linux and ignore the "no_linux" tag
 
-         # completely.
 
-         known_platform_tags = set(['no_windows', 'no_mac'])
 
-         if set(bazel_tags).intersection(known_platform_tags):
 
-             platforms = []
 
-             # assume all tests are compatible with linux and posix
 
-             platforms.append('linux')
 
-             platforms.append(
 
-                 'posix')  # there is no posix-specific tag in bazel BUILD
 
-             if not 'no_mac' in bazel_tags:
 
-                 platforms.append('mac')
 
-             if not 'no_windows' in bazel_tags:
 
-                 platforms.append('windows')
 
-             test_dict['platforms'] = platforms
 
-         cmdline_args = bazel_rule['args']
 
-         if cmdline_args:
 
-             test_dict['args'] = list(cmdline_args)
 
-         if test.startswith('test/cpp'):
 
-             test_dict['language'] = 'c++'
 
-         elif test.startswith('test/core'):
 
-             test_dict['language'] = 'c'
 
-         else:
 
-             raise Exception('wrong test' + test)
 
-         # short test name without the path.
 
-         # There can be name collisions, but we will resolve them later
 
-         simple_test_name = os.path.basename(_extract_source_file_path(test))
 
-         test_dict['_RENAME'] = simple_test_name
 
-         test_metadata[test] = test_dict
 
-     # detect duplicate test names
 
-     tests_by_simple_name = {}
 
-     for test_name, test_dict in test_metadata.items():
 
-         simple_test_name = test_dict['_RENAME']
 
-         if not simple_test_name in tests_by_simple_name:
 
-             tests_by_simple_name[simple_test_name] = []
 
-         tests_by_simple_name[simple_test_name].append(test_name)
 
-     # choose alternative names for tests with a name collision
 
-     for collision_list in tests_by_simple_name.values():
 
-         if len(collision_list) > 1:
 
-             for test_name in collision_list:
 
-                 long_name = test_name.replace('/', '_').replace(':', '_')
 
-                 print(
 
-                     'short name of "%s" collides with another test, renaming to %s'
 
-                     % (test_name, long_name))
 
-                 test_metadata[test_name]['_RENAME'] = long_name
 
-     return test_metadata
 
- def _detect_and_print_issues(build_yaml_like: BuildYaml) -> None:
 
-     """Try detecting some unusual situations and warn about them."""
 
-     for tgt in build_yaml_like['targets']:
 
-         if tgt['build'] == 'test':
 
-             for src in tgt['src']:
 
-                 if src.startswith('src/') and not src.endswith('.proto'):
 
-                     print('source file from under "src/" tree used in test ' +
 
-                           tgt['name'] + ': ' + src)
 
- # extra metadata that will be used to construct build.yaml
 
- # there are mostly extra properties that we weren't able to obtain from the bazel build
 
- # _TYPE: whether this is library, target or test
 
- # _RENAME: whether this target should be renamed to a different name (to match expectations of make and cmake builds)
 
- _BUILD_EXTRA_METADATA = {
 
-     'third_party/address_sorting:address_sorting': {
 
-         'language': 'c',
 
-         'build': 'all',
 
-         '_RENAME': 'address_sorting'
 
-     },
 
-     'gpr': {
 
-         'language': 'c',
 
-         'build': 'all',
 
-     },
 
-     'grpc': {
 
-         'language': 'c',
 
-         'build': 'all',
 
-         'baselib': True,
 
-         'generate_plugin_registry': True
 
-     },
 
-     'grpc++': {
 
-         'language': 'c++',
 
-         'build': 'all',
 
-         'baselib': True,
 
-     },
 
-     'grpc++_alts': {
 
-         'language': 'c++',
 
-         'build': 'all',
 
-         'baselib': True
 
-     },
 
-     'grpc++_error_details': {
 
-         'language': 'c++',
 
-         'build': 'all'
 
-     },
 
-     'grpc++_reflection': {
 
-         'language': 'c++',
 
-         'build': 'all'
 
-     },
 
-     'grpc++_unsecure': {
 
-         'language': 'c++',
 
-         'build': 'all',
 
-         'baselib': True,
 
-     },
 
-     # TODO(jtattermusch): do we need to set grpc_csharp_ext's LDFLAGS for wrapping memcpy in the same way as in build.yaml?
 
-     'grpc_csharp_ext': {
 
-         'language': 'c',
 
-         'build': 'all',
 
-     },
 
-     'grpc_unsecure': {
 
-         'language': 'c',
 
-         'build': 'all',
 
-         'baselib': True,
 
-         'generate_plugin_registry': True
 
-     },
 
-     'grpcpp_channelz': {
 
-         'language': 'c++',
 
-         'build': 'all'
 
-     },
 
-     'grpc++_test': {
 
-         'language': 'c++',
 
-         'build': 'private',
 
-     },
 
-     'src/compiler:grpc_plugin_support': {
 
-         'language': 'c++',
 
-         'build': 'protoc',
 
-         '_RENAME': 'grpc_plugin_support'
 
-     },
 
-     'src/compiler:grpc_cpp_plugin': {
 
-         'language': 'c++',
 
-         'build': 'protoc',
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'grpc_cpp_plugin'
 
-     },
 
-     'src/compiler:grpc_csharp_plugin': {
 
-         'language': 'c++',
 
-         'build': 'protoc',
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'grpc_csharp_plugin'
 
-     },
 
-     'src/compiler:grpc_node_plugin': {
 
-         'language': 'c++',
 
-         'build': 'protoc',
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'grpc_node_plugin'
 
-     },
 
-     'src/compiler:grpc_objective_c_plugin': {
 
-         'language': 'c++',
 
-         'build': 'protoc',
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'grpc_objective_c_plugin'
 
-     },
 
-     'src/compiler:grpc_php_plugin': {
 
-         'language': 'c++',
 
-         'build': 'protoc',
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'grpc_php_plugin'
 
-     },
 
-     'src/compiler:grpc_python_plugin': {
 
-         'language': 'c++',
 
-         'build': 'protoc',
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'grpc_python_plugin'
 
-     },
 
-     'src/compiler:grpc_ruby_plugin': {
 
-         'language': 'c++',
 
-         'build': 'protoc',
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'grpc_ruby_plugin'
 
-     },
 
-     # TODO(jtattermusch): consider adding grpc++_core_stats
 
-     # test support libraries
 
-     'test/core/util:grpc_test_util': {
 
-         'language': 'c',
 
-         'build': 'private',
 
-         '_RENAME': 'grpc_test_util'
 
-     },
 
-     'test/core/util:grpc_test_util_unsecure': {
 
-         'language': 'c',
 
-         'build': 'private',
 
-         '_RENAME': 'grpc_test_util_unsecure'
 
-     },
 
-     # TODO(jtattermusch): consider adding grpc++_test_util_unsecure - it doesn't seem to be used by bazel build (don't forget to set secure: False)
 
-     'test/cpp/util:test_config': {
 
-         'language': 'c++',
 
-         'build': 'private',
 
-         '_RENAME': 'grpc++_test_config'
 
-     },
 
-     'test/cpp/util:test_util': {
 
-         'language': 'c++',
 
-         'build': 'private',
 
-         '_RENAME': 'grpc++_test_util'
 
-     },
 
-     # end2end test support libraries
 
-     'test/core/end2end:end2end_tests': {
 
-         'language': 'c',
 
-         'build': 'private',
 
-         '_RENAME': 'end2end_tests'
 
-     },
 
-     'test/core/end2end:end2end_nosec_tests': {
 
-         'language': 'c',
 
-         'build': 'private',
 
-         '_RENAME': 'end2end_nosec_tests'
 
-     },
 
-     # benchmark support libraries
 
-     'test/cpp/microbenchmarks:helpers': {
 
-         'language': 'c++',
 
-         'build': 'test',
 
-         'defaults': 'benchmark',
 
-         '_RENAME': 'benchmark_helpers'
 
-     },
 
-     'test/cpp/interop:interop_client': {
 
-         'language': 'c++',
 
-         'build': 'test',
 
-         'run': False,
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'interop_client'
 
-     },
 
-     'test/cpp/interop:interop_server': {
 
-         'language': 'c++',
 
-         'build': 'test',
 
-         'run': False,
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'interop_server'
 
-     },
 
-     'test/cpp/interop:xds_interop_client': {
 
-         'language': 'c++',
 
-         'build': 'test',
 
-         'run': False,
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'xds_interop_client'
 
-     },
 
-     'test/cpp/interop:xds_interop_server': {
 
-         'language': 'c++',
 
-         'build': 'test',
 
-         'run': False,
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'xds_interop_server'
 
-     },
 
-     'test/cpp/interop:http2_client': {
 
-         'language': 'c++',
 
-         'build': 'test',
 
-         'run': False,
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'http2_client'
 
-     },
 
-     'test/cpp/qps:qps_json_driver': {
 
-         'language': 'c++',
 
-         'build': 'test',
 
-         'run': False,
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'qps_json_driver'
 
-     },
 
-     'test/cpp/qps:qps_worker': {
 
-         'language': 'c++',
 
-         'build': 'test',
 
-         'run': False,
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'qps_worker'
 
-     },
 
-     'test/cpp/util:grpc_cli': {
 
-         'language': 'c++',
 
-         'build': 'test',
 
-         'run': False,
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'grpc_cli'
 
-     },
 
-     # TODO(jtattermusch): create_jwt and verify_jwt breaks distribtests because it depends on grpc_test_utils and thus requires tests to be built
 
-     # For now it's ok to disable them as these binaries aren't very useful anyway.
 
-     #'test/core/security:create_jwt': { 'language': 'c', 'build': 'tool', '_TYPE': 'target', '_RENAME': 'grpc_create_jwt' },
 
-     #'test/core/security:verify_jwt': { 'language': 'c', 'build': 'tool', '_TYPE': 'target', '_RENAME': 'grpc_verify_jwt' },
 
-     # TODO(jtattermusch): add remaining tools such as grpc_print_google_default_creds_token (they are not used by bazel build)
 
-     # Fuzzers
 
-     'test/core/security:alts_credentials_fuzzer': {
 
-         'language': 'c++',
 
-         'build': 'fuzzer',
 
-         'corpus_dirs': ['test/core/security/corpus/alts_credentials_corpus'],
 
-         'maxlen': 2048,
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'alts_credentials_fuzzer'
 
-     },
 
-     'test/core/end2end/fuzzers:client_fuzzer': {
 
-         'language': 'c++',
 
-         'build': 'fuzzer',
 
-         'corpus_dirs': ['test/core/end2end/fuzzers/client_fuzzer_corpus'],
 
-         'maxlen': 2048,
 
-         'dict': 'test/core/end2end/fuzzers/hpack.dictionary',
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'client_fuzzer'
 
-     },
 
-     'test/core/transport/chttp2:hpack_parser_fuzzer': {
 
-         'language': 'c++',
 
-         'build': 'fuzzer',
 
-         'corpus_dirs': ['test/core/transport/chttp2/hpack_parser_corpus'],
 
-         'maxlen': 512,
 
-         'dict': 'test/core/end2end/fuzzers/hpack.dictionary',
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'hpack_parser_fuzzer_test'
 
-     },
 
-     'test/core/http:request_fuzzer': {
 
-         'language': 'c++',
 
-         'build': 'fuzzer',
 
-         'corpus_dirs': ['test/core/http/request_corpus'],
 
-         'maxlen': 2048,
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'http_request_fuzzer_test'
 
-     },
 
-     'test/core/http:response_fuzzer': {
 
-         'language': 'c++',
 
-         'build': 'fuzzer',
 
-         'corpus_dirs': ['test/core/http/response_corpus'],
 
-         'maxlen': 2048,
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'http_response_fuzzer_test'
 
-     },
 
-     'test/core/json:json_fuzzer': {
 
-         'language': 'c++',
 
-         'build': 'fuzzer',
 
-         'corpus_dirs': ['test/core/json/corpus'],
 
-         'maxlen': 512,
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'json_fuzzer_test'
 
-     },
 
-     'test/core/nanopb:fuzzer_response': {
 
-         'language': 'c++',
 
-         'build': 'fuzzer',
 
-         'corpus_dirs': ['test/core/nanopb/corpus_response'],
 
-         'maxlen': 128,
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'nanopb_fuzzer_response_test'
 
-     },
 
-     'test/core/nanopb:fuzzer_serverlist': {
 
-         'language': 'c++',
 
-         'build': 'fuzzer',
 
-         'corpus_dirs': ['test/core/nanopb/corpus_serverlist'],
 
-         'maxlen': 128,
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'nanopb_fuzzer_serverlist_test'
 
-     },
 
-     'test/core/slice:percent_decode_fuzzer': {
 
-         'language': 'c++',
 
-         'build': 'fuzzer',
 
-         'corpus_dirs': ['test/core/slice/percent_decode_corpus'],
 
-         'maxlen': 32,
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'percent_decode_fuzzer'
 
-     },
 
-     'test/core/slice:percent_encode_fuzzer': {
 
-         'language': 'c++',
 
-         'build': 'fuzzer',
 
-         'corpus_dirs': ['test/core/slice/percent_encode_corpus'],
 
-         'maxlen': 32,
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'percent_encode_fuzzer'
 
-     },
 
-     'test/core/end2end/fuzzers:server_fuzzer': {
 
-         'language': 'c++',
 
-         'build': 'fuzzer',
 
-         'corpus_dirs': ['test/core/end2end/fuzzers/server_fuzzer_corpus'],
 
-         'maxlen': 2048,
 
-         'dict': 'test/core/end2end/fuzzers/hpack.dictionary',
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'server_fuzzer'
 
-     },
 
-     'test/core/security:ssl_server_fuzzer': {
 
-         'language': 'c++',
 
-         'build': 'fuzzer',
 
-         'corpus_dirs': ['test/core/security/corpus/ssl_server_corpus'],
 
-         'maxlen': 2048,
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'ssl_server_fuzzer'
 
-     },
 
-     'test/core/uri:uri_fuzzer_test': {
 
-         'language': 'c++',
 
-         'build': 'fuzzer',
 
-         'corpus_dirs': ['test/core/uri/uri_corpus'],
 
-         'maxlen': 128,
 
-         '_TYPE': 'target',
 
-         '_RENAME': 'uri_fuzzer_test'
 
-     },
 
-     # TODO(jtattermusch): these fuzzers had no build.yaml equivalent
 
-     # test/core/compression:message_compress_fuzzer
 
-     # test/core/compression:message_decompress_fuzzer
 
-     # test/core/compression:stream_compression_fuzzer
 
-     # test/core/compression:stream_decompression_fuzzer
 
-     # test/core/slice:b64_decode_fuzzer
 
-     # test/core/slice:b64_encode_fuzzer
 
- }
 
- # We need a complete picture of all the targets and dependencies we're interested in
 
- # so we run multiple bazel queries and merge the results.
 
- _BAZEL_DEPS_QUERIES = [
 
-     'deps("//test/...")',
 
-     'deps("//:all")',
 
-     'deps("//src/compiler/...")',
 
-     'deps("//src/proto/...")',
 
-     # The ^ is needed to differentiate proto_library from go_proto_library
 
-     'deps(kind("^proto_library", @envoy_api//envoy/...))',
 
- ]
 
- # Step 1: run a bunch of "bazel query --output xml" queries to collect
 
- # the raw build metadata from the bazel build.
 
- # At the end of this step we will have a dictionary of bazel rules
 
- # that are interesting to us (libraries, binaries, etc.) along
 
- # with their most important metadata (sources, headers, dependencies)
 
- #
 
- # Example of a single bazel rule after being populated:
 
- # '//:grpc' : { 'class': 'cc_library',
 
- #               'hdrs': ['//:include/grpc/byte_buffer.h', ... ],
 
- #               'srcs': ['//:src/core/lib/surface/init.cc', ... ],
 
- #               'deps': ['//:grpc_common', ...],
 
- #               ... }
 
- bazel_rules = {}
 
- for query in _BAZEL_DEPS_QUERIES:
 
-     bazel_rules.update(
 
-         _extract_rules_from_bazel_xml(_bazel_query_xml_tree(query)))
 
- # Step 2: Extract the known bazel cc_test tests. While most tests
 
- # will be buildable with other build systems just fine, some of these tests
 
- # would be too difficult to build and run with other build systems,
 
- # so we simply exclude the ones we don't want.
 
- # Note that while making tests buildable with other build systems
 
- # than just bazel is extra effort, we still need to do that for these
 
- # reasons:
 
- # - If our cmake build doesn't have any tests at all, it's hard to make
 
- #   sure that what it built actually works (we need at least some "smoke tests").
 
- #   This is quite important because the build flags between bazel / non-bazel flag might differ
 
- #   (sometimes it's for interesting reasons that are not easy to overcome)
 
- #   which makes it even more important to have at least some tests for cmake/make
 
- # - Our portability suite actually runs cmake tests and migration of portability
 
- #   suite fully towards bazel might be intricate (e.g. it's unclear whether it's
 
- #   possible to get a good enough coverage of different compilers / distros etc.
 
- #   with bazel)
 
- # - some things that are considered "tests" in build.yaml-based builds are actually binaries
 
- #   we'd want to be able to build anyway (qps_json_worker, interop_client, interop_server, grpc_cli)
 
- #   so it's unclear how much make/cmake simplification we would gain by removing just some (but not all) test
 
- # TODO(jtattermusch): Investigate feasibility of running portability suite with bazel.
 
- tests = _exclude_unwanted_cc_tests(_extract_cc_tests(bazel_rules))
 
- # Step 3: Generate the "extra metadata" for all our build targets.
 
- # While the bazel rules give us most of the information we need,
 
- # the legacy "build.yaml" format requires some additional fields that
 
- # we cannot get just from bazel alone (we call that "extra metadata").
 
- # In this step, we basically analyze the build metadata we have from bazel
 
- # and use heuristics to determine (and sometimes guess) the right
 
- # extra metadata to use for each target.
 
- #
 
- # - For some targets (such as the public libraries, helper libraries
 
- #   and executables) determining the right extra metadata is hard to do
 
- #   automatically. For these targets, the extra metadata is supplied "manually"
 
- #   in form of the _BUILD_EXTRA_METADATA dictionary. That allows us to match
 
- #   the semantics of the legacy "build.yaml" as closely as possible.
 
- #
 
- # - For test binaries, it is possible to generate the "extra metadata" mostly
 
- #   automatically using a rule-based heuristic approach because most tests
 
- #   look and behave alike from the build's perspective.
 
- #
 
- # TODO(jtattermusch): Of course neither "_BUILD_EXTRA_METADATA" or
 
- # the heuristic approach used for tests are ideal and they cannot be made
 
- # to cover all possible situations (and are tailored to work with the way
 
- # the grpc build currently works), but the idea was to start with something
 
- # reasonably simple that matches the "build.yaml"-like semantics as closely
 
- # as possible (to avoid changing too many things at once) and gradually get
 
- # rid of the legacy "build.yaml"-specific fields one by one. Once that is done,
 
- # only very little "extra metadata" would be needed and/or it would be trivial
 
- # to generate it automatically.
 
- all_extra_metadata = {}
 
- all_extra_metadata.update(_BUILD_EXTRA_METADATA)
 
- all_extra_metadata.update(
 
-     _generate_build_extra_metadata_for_tests(tests, bazel_rules))
 
- # Step 4: Compute the build metadata that will be used in the final build.yaml.
 
- # The final build metadata includes transitive dependencies, and sources/headers
 
- # expanded without intermediate dependencies.
 
- # Example:
 
- # '//:grpc' : { ...,
 
- #               '_TRANSITIVE_DEPS': ['//:gpr_base', ...],
 
- #               '_COLLAPSED_DEPS': ['gpr', ...],
 
- #               '_COLLAPSED_SRCS': [...],
 
- #               '_COLLAPSED_PUBLIC_HEADERS': [...],
 
- #               '_COLLAPSED_HEADERS': [...]
 
- #             }
 
- _populate_transitive_metadata(bazel_rules, all_extra_metadata.keys())
 
- # Step 4a: Update the existing test metadata with the updated build metadata.
 
- # Certain build metadata of certain test targets depend on the transitive
 
- # metadata that wasn't available earlier.
 
- update_test_metadata_with_transitive_metadata(all_extra_metadata, bazel_rules)
 
- # Step 5: Generate the final metadata for all the targets.
 
- # This is done by combining the bazel build metadata and the "extra metadata"
 
- # we obtained in the previous step.
 
- # In this step, we also perform some interesting massaging of the target metadata
 
- # to end up with a result that is as similar to the legacy build.yaml data
 
- # as possible.
 
- # - Some targets get renamed (to match the legacy build.yaml target names)
 
- # - Some intermediate libraries get elided ("expanded") to better match the set
 
- #   of targets provided by the legacy build.yaml build
 
- #
 
- # Originally the target renaming was introduced to address these concerns:
 
- # - avoid changing too many things at the same time and avoid people getting
 
- #   confused by some well know targets suddenly being missing
 
- # - Makefile/cmake and also language-specific generators rely on some build
 
- #   targets being called exactly the way they they are. Some of our testing
 
- #   scrips also invoke executables (e.g. "qps_json_driver") by their name.
 
- # - The autogenerated test name from bazel includes the package path
 
- #   (e.g. "test_cpp_TEST_NAME"). Without renaming, the target names would
 
- #   end up pretty ugly (e.g. test_cpp_qps_qps_json_driver).
 
- # TODO(jtattermusch): reevaluate the need for target renaming in the future.
 
- #
 
- # Example of a single generated target:
 
- # 'grpc' : { 'language': 'c',
 
- #            'public_headers': ['include/grpc/byte_buffer.h', ... ],
 
- #            'headers': ['src/core/ext/filters/client_channel/client_channel.h', ... ],
 
- #            'src': ['src/core/lib/surface/init.cc', ... ],
 
- #            'deps': ['gpr', 'address_sorting', ...],
 
- #            ... }
 
- all_targets_dict = _generate_build_metadata(all_extra_metadata, bazel_rules)
 
- # Step 6: convert the dictionary with all the targets to a dict that has
 
- # the desired "build.yaml"-like layout.
 
- # TODO(jtattermusch): We use the custom "build.yaml"-like layout because
 
- # currently all other build systems use that format as their source of truth.
 
- # In the future, we can get rid of this custom & legacy format entirely,
 
- # but we would need to update the generators for other build systems
 
- # at the same time.
 
- #
 
- # Layout of the result:
 
- # { 'libs': { TARGET_DICT_FOR_LIB_XYZ, ... },
 
- #   'targets': { TARGET_DICT_FOR_BIN_XYZ, ... },
 
- #   'tests': { TARGET_DICT_FOR_TEST_XYZ, ...} }
 
- build_yaml_like = _convert_to_build_yaml_like(all_targets_dict)
 
- # detect and report some suspicious situations we've seen before
 
- _detect_and_print_issues(build_yaml_like)
 
- # Step 7: Store the build_autogenerated.yaml in a deterministic (=sorted)
 
- # and cleaned-up form.
 
- # A basic overview of the resulting "build.yaml"-like format is here:
 
- # https://github.com/grpc/grpc/blob/master/templates/README.md
 
- # TODO(jtattermusch): The "cleanup" function is taken from the legacy
 
- # build system (which used build.yaml) and can be eventually removed.
 
- build_yaml_string = build_cleaner.cleaned_build_yaml_dict_as_string(
 
-     build_yaml_like)
 
- with open('build_autogenerated.yaml', 'w') as file:
 
-     file.write(build_yaml_string)
 
 
  |