"Fossies" - the Fresh Open Source Software Archive 
Member "abseil-cpp-20230802.1/absl/abseil.podspec.gen.py" (18 Sep 2023, 7377 Bytes) of package /linux/misc/abseil-cpp-20230802.1.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style:
standard) with prefixed line numbers.
Alternatively you can here
view or
download the uninterpreted source code file.
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 """This script generates abseil.podspec from all BUILD.bazel files.
4
5 This is expected to run on abseil git repository with Bazel 1.0 on Linux.
6 It recursively analyzes BUILD.bazel files using query command of Bazel to
7 dump its build rules in XML format. From these rules, it constructs podspec
8 structure.
9 """
10
11 import argparse
12 import collections
13 import os
14 import re
15 import subprocess
16 import xml.etree.ElementTree
17
18 # Template of root podspec.
19 SPEC_TEMPLATE = """
20 # This file has been automatically generated from a script.
21 # Please make modifications to `abseil.podspec.gen.py` instead.
22 Pod::Spec.new do |s|
23 s.name = 'abseil'
24 s.version = '${version}'
25 s.summary = 'Abseil Common Libraries (C++) from Google'
26 s.homepage = 'https://abseil.io'
27 s.license = 'Apache License, Version 2.0'
28 s.authors = { 'Abseil Team' => 'abseil-io@googlegroups.com' }
29 s.source = {
30 :git => 'https://github.com/abseil/abseil-cpp.git',
31 :tag => '${tag}',
32 }
33 s.module_name = 'absl'
34 s.header_mappings_dir = 'absl'
35 s.header_dir = 'absl'
36 s.libraries = 'c++'
37 s.compiler_flags = '-Wno-everything'
38 s.pod_target_xcconfig = {
39 'USER_HEADER_SEARCH_PATHS' => '$(inherited) "$(PODS_TARGET_SRCROOT)"',
40 'USE_HEADERMAP' => 'NO',
41 'ALWAYS_SEARCH_USER_PATHS' => 'NO',
42 }
43 s.ios.deployment_target = '9.0'
44 s.osx.deployment_target = '10.10'
45 s.tvos.deployment_target = '9.0'
46 s.watchos.deployment_target = '2.0'
47 """
48
49 # Rule object representing the rule of Bazel BUILD.
50 Rule = collections.namedtuple(
51 "Rule", "type name package srcs hdrs textual_hdrs deps visibility testonly")
52
53
54 def get_elem_value(elem, name):
55 """Returns the value of XML element with the given name."""
56 for child in elem:
57 if child.attrib.get("name") != name:
58 continue
59 if child.tag == "string":
60 return child.attrib.get("value")
61 if child.tag == "boolean":
62 return child.attrib.get("value") == "true"
63 if child.tag == "list":
64 return [nested_child.attrib.get("value") for nested_child in child]
65 raise "Cannot recognize tag: " + child.tag
66 return None
67
68
69 def normalize_paths(paths):
70 """Returns the list of normalized path."""
71 # e.g. ["//absl/strings:dir/header.h"] -> ["absl/strings/dir/header.h"]
72 return [path.lstrip("/").replace(":", "/") for path in paths]
73
74
75 def parse_rule(elem, package):
76 """Returns a rule from bazel XML rule."""
77 return Rule(
78 type=elem.attrib["class"],
79 name=get_elem_value(elem, "name"),
80 package=package,
81 srcs=normalize_paths(get_elem_value(elem, "srcs") or []),
82 hdrs=normalize_paths(get_elem_value(elem, "hdrs") or []),
83 textual_hdrs=normalize_paths(get_elem_value(elem, "textual_hdrs") or []),
84 deps=get_elem_value(elem, "deps") or [],
85 visibility=get_elem_value(elem, "visibility") or [],
86 testonly=get_elem_value(elem, "testonly") or False)
87
88
89 def read_build(package):
90 """Runs bazel query on given package file and returns all cc rules."""
91 result = subprocess.check_output(
92 ["bazel", "query", package + ":all", "--output", "xml"])
93 root = xml.etree.ElementTree.fromstring(result)
94 return [
95 parse_rule(elem, package)
96 for elem in root
97 if elem.tag == "rule" and elem.attrib["class"].startswith("cc_")
98 ]
99
100
101 def collect_rules(root_path):
102 """Collects and returns all rules from root path recursively."""
103 rules = []
104 for cur, _, _ in os.walk(root_path):
105 build_path = os.path.join(cur, "BUILD.bazel")
106 if os.path.exists(build_path):
107 rules.extend(read_build("//" + cur))
108 return rules
109
110
111 def relevant_rule(rule):
112 """Returns true if a given rule is relevant when generating a podspec."""
113 return (
114 # cc_library only (ignore cc_test, cc_binary)
115 rule.type == "cc_library" and
116 # ignore empty rule
117 (rule.hdrs + rule.textual_hdrs + rule.srcs) and
118 # ignore test-only rule
119 not rule.testonly)
120
121
122 def get_spec_var(depth):
123 """Returns the name of variable for spec with given depth."""
124 return "s" if depth == 0 else "s{}".format(depth)
125
126
127 def get_spec_name(label):
128 """Converts the label of bazel rule to the name of podspec."""
129 assert label.startswith("//absl/"), "{} doesn't start with //absl/".format(
130 label)
131 # e.g. //absl/apple/banana -> abseil/apple/banana
132 return "abseil/" + label[7:]
133
134
135 def write_podspec(f, rules, args):
136 """Writes a podspec from given rules and args."""
137 rule_dir = build_rule_directory(rules)["abseil"]
138 # Write root part with given arguments
139 spec = re.sub(r"\$\{(\w+)\}", lambda x: args[x.group(1)],
140 SPEC_TEMPLATE).lstrip()
141 f.write(spec)
142 # Write all target rules
143 write_podspec_map(f, rule_dir, 0)
144 f.write("end\n")
145
146
147 def build_rule_directory(rules):
148 """Builds a tree-style rule directory from given rules."""
149 rule_dir = {}
150 for rule in rules:
151 cur = rule_dir
152 for frag in get_spec_name(rule.package).split("/"):
153 cur = cur.setdefault(frag, {})
154 cur[rule.name] = rule
155 return rule_dir
156
157
158 def write_podspec_map(f, cur_map, depth):
159 """Writes podspec from rule map recursively."""
160 for key, value in sorted(cur_map.items()):
161 indent = " " * (depth + 1)
162 f.write("{indent}{var0}.subspec '{key}' do |{var1}|\n".format(
163 indent=indent,
164 key=key,
165 var0=get_spec_var(depth),
166 var1=get_spec_var(depth + 1)))
167 if isinstance(value, dict):
168 write_podspec_map(f, value, depth + 1)
169 else:
170 write_podspec_rule(f, value, depth + 1)
171 f.write("{indent}end\n".format(indent=indent))
172
173
174 def write_podspec_rule(f, rule, depth):
175 """Writes podspec from given rule."""
176 indent = " " * (depth + 1)
177 spec_var = get_spec_var(depth)
178 # Puts all files in hdrs, textual_hdrs, and srcs into source_files.
179 # Since CocoaPods treats header_files a bit differently from bazel,
180 # this won't generate a header_files field so that all source_files
181 # are considered as header files.
182 srcs = sorted(set(rule.hdrs + rule.textual_hdrs + rule.srcs))
183 write_indented_list(
184 f, "{indent}{var}.source_files = ".format(indent=indent, var=spec_var),
185 srcs)
186 # Writes dependencies of this rule.
187 for dep in sorted(rule.deps):
188 name = get_spec_name(dep.replace(":", "/"))
189 f.write("{indent}{var}.dependency '{dep}'\n".format(
190 indent=indent, var=spec_var, dep=name))
191
192
193 def write_indented_list(f, leading, values):
194 """Writes leading values in an indented style."""
195 f.write(leading)
196 f.write((",\n" + " " * len(leading)).join("'{}'".format(v) for v in values))
197 f.write("\n")
198
199
200 def generate(args):
201 """Generates a podspec file from all BUILD files under absl directory."""
202 rules = filter(relevant_rule, collect_rules("absl"))
203 with open(args.output, "wt") as f:
204 write_podspec(f, rules, vars(args))
205
206
207 def main():
208 parser = argparse.ArgumentParser(
209 description="Generates abseil.podspec from BUILD.bazel")
210 parser.add_argument(
211 "-v", "--version", help="The version of podspec", required=True)
212 parser.add_argument(
213 "-t",
214 "--tag",
215 default=None,
216 help="The name of git tag (default: version)")
217 parser.add_argument(
218 "-o",
219 "--output",
220 default="abseil.podspec",
221 help="The name of output file (default: abseil.podspec)")
222 args = parser.parse_args()
223 if args.tag is None:
224 args.tag = args.version
225 generate(args)
226
227
228 if __name__ == "__main__":
229 main()