21 import xml.etree.ElementTree 
as ET
 
   24 ABSEIL_PATH = 
"third_party/abseil-cpp" 
   25 OUTPUT_PATH = 
"src/abseil-cpp/preprocessed_builds.yaml" 
   26 CAPITAL_WORD = re.compile(
"[A-Z]+")
 
   27 ABSEIL_CMAKE_RULE_BEGIN = re.compile(
"^absl_cc_.*\(", re.MULTILINE)
 
   28 ABSEIL_CMAKE_RULE_END = re.compile(
"^\)", re.MULTILINE)
 
   31 Rule = collections.namedtuple(
 
   32     "Rule", 
"type name package srcs hdrs textual_hdrs deps visibility testonly")
 
   36   """Returns the value of XML element with the given name.""" 
   38     if child.attrib.get(
"name") == name:
 
   39       if child.tag == 
"string":
 
   40         return child.attrib.get(
"value")
 
   41       elif child.tag == 
"boolean":
 
   42         return child.attrib.get(
"value") == 
"true" 
   43       elif child.tag == 
"list":
 
   44         return [nested_child.attrib.get(
"value") 
for nested_child 
in child]
 
   46         raise "Cannot recognize tag: " + child.tag
 
   51   """Returns the list of normalized path.""" 
   53   return [path.lstrip(
"/").replace(
":", 
"/") 
for path 
in paths]
 
   57   """Returns a rule from bazel XML rule.""" 
   59       type=elem.attrib[
"class"],
 
   71   """Runs bazel query on given package file and returns all cc rules.""" 
   74   BAZEL_BIN = 
"../../tools/bazel" 
   75   result = subprocess.check_output(
 
   76       [BAZEL_BIN, 
"query", package + 
":all", 
"--output", 
"xml"])
 
   77   root = ET.fromstring(result)
 
   81       if elem.tag == 
"rule" and elem.attrib[
"class"].startswith(
"cc_")
 
   86   """Collects and returns all bazel rules from root path recursively.""" 
   88   for cur, _, _ 
in os.walk(root_path):
 
   89     build_path = os.path.join(cur, 
"BUILD.bazel")
 
   90     if os.path.exists(build_path):
 
   96   """Returns a rule from absl cmake rule. 
   97      Reference: https://github.com/abseil/abseil-cpp/blob/master/CMake/AbseilHelpers.cmake 
  101   lines = rule.splitlines()
 
  102   for line 
in lines[1:-1]:
 
  103     if CAPITAL_WORD.match(line.strip()):
 
  104       bucket = kv.setdefault(line.strip(), [])
 
  106       if bucket 
is not None:
 
  107         bucket.append(line.strip())
 
  109         raise ValueError(
"Illegal syntax: {}".
format(rule))
 
  111       type=lines[0].rstrip(
"("),
 
  112       name=
"absl::" + kv[
"NAME"][0],
 
  114       srcs=[package + 
"/" + f.strip(
'"') 
for f 
in kv.get(
"SRCS", [])],
 
  115       hdrs=[package + 
"/" + f.strip(
'"') 
for f 
in kv.get(
"HDRS", [])],
 
  117       deps=kv.get(
"DEPS", []),
 
  118       visibility=
"PUBLIC" in kv,
 
  119       testonly=
"TESTONLY" in kv,
 
  124   """Parses given CMakeLists.txt file and returns all cc rules.""" 
  126   with open(build_path, 
"r") 
as f:
 
  128     for begin_mo 
in ABSEIL_CMAKE_RULE_BEGIN.finditer(src):
 
  129       end_mo = ABSEIL_CMAKE_RULE_END.search(src[begin_mo.start(0):])
 
  130       expr = src[begin_mo.start(0):begin_mo.start(0) + end_mo.start(0) + 1]
 
  136   """Collects and returns all cmake rules from root path recursively.""" 
  138   for cur, _, _ 
in os.walk(root_path):
 
  139     build_path = os.path.join(cur, 
"CMakeLists.txt")
 
  140     if os.path.exists(build_path):
 
  146   """Returns a pair map between bazel rules and cmake rules based on 
  147      the similarity of the file list in the rule. This is because 
  148      cmake build and bazel build of abseil are not identical. 
  151   for rule 
in bazel_rules:
 
  152     best_crule, best_similarity = 
None, 0
 
  153     for crule 
in cmake_rules:
 
  155           set(rule.srcs + rule.hdrs + rule.textual_hdrs).intersection(
 
  156               set(crule.srcs + crule.hdrs + crule.textual_hdrs)))
 
  157       if similarity > best_similarity:
 
  158         best_crule, best_similarity = crule, similarity
 
  160       pair_map[(rule.package, rule.name)] = best_crule.name
 
  165   return [ABSEIL_PATH + 
"/" + f 
for f 
in files 
if f.endswith((
".h", 
".inc"))]
 
  169   return [ABSEIL_PATH + 
"/" + f 
for f 
in files 
if f.endswith(
".cc")]
 
  173   return [(t[2:] 
if t.startswith(
"//") 
else t) 
for t 
in targets]
 
  177   """Generates builds from all BUILD files under absl directory.""" 
  179       filter(
lambda r: r.type == 
"cc_library" and not r.testonly,
 
  182       filter(
lambda r: r.type == 
"absl_cc_library" and not r.testonly,
 
  186   for rule 
in sorted(bazel_rules, key=
lambda r: r.package[2:] + 
":" + r.name):
 
  189             rule.package[2:] + 
":" + rule.name,
 
  191             pair_map.get((rule.package, rule.name)) 
or "",
 
  193             sorted(
resolve_hdrs(rule.srcs + rule.hdrs + rule.textual_hdrs)),
 
  195             sorted(
resolve_srcs(rule.srcs + rule.hdrs + rule.textual_hdrs)),
 
  204   previous_dir = os.getcwd()
 
  205   os.chdir(ABSEIL_PATH)
 
  207   os.chdir(previous_dir)
 
  208   with open(OUTPUT_PATH, 
'w') 
as outfile:
 
  209     outfile.write(yaml.dump(builds, indent=2))
 
  212 if __name__ == 
"__main__":