Add per-partition summaries and "easy" transitions to mk2bp_catalog
"Easy" means makefiles that are both clean themselves and
only depend on clean targets themselves too.
Test: m out/target/product/$(get_build_var TARGET_DEVICE)/mk2bp_remaining.html
Change-Id: If3402a0ada5d9db5fb04c617d197ab28d695b03c
diff --git a/tools/mk2bp_catalog.py b/tools/mk2bp_catalog.py
index 83abd62..e85ae18 100755
--- a/tools/mk2bp_catalog.py
+++ b/tools/mk2bp_catalog.py
@@ -119,6 +119,15 @@
self.makefiles[makefile.filename] = makefile
self.directories.setdefault(directory_group(makefile.filename), []).append(makefile)
+ def IsClean(self, filename):
+ """Also returns true if filename isn't present, with the assumption that it's already
+ converted.
+ """
+ makefile = self.makefiles.get(filename)
+ if not makefile:
+ return True
+ return is_clean(makefile)
+
class Makefile(object):
def __init__(self, filename):
self.filename = filename
@@ -223,6 +232,16 @@
for f in installed.strip().split(' '):
self.installed[f] = module
+ def transitive_deps(self, module):
+ results = set()
+ def traverse(module):
+ for dep in self.deps.get(module, []):
+ if not dep in results:
+ results.add(dep)
+ traverse(module)
+ traverse(module)
+ return results
+
def count_deps(depsdb, module, seen):
"""Based on the depsdb, count the number of transitive dependencies.
@@ -273,6 +292,84 @@
def format_module_list(modules):
return "".join(["<div>%s</div>" % format_module_link(m) for m in modules])
+def traverse_ready_makefiles(soong, summary, makefiles):
+ def clean_and_only_blocked_by_clean(makefile):
+ if not is_clean(makefile):
+ return False
+ modules = soong.reverse_makefiles[makefile.filename]
+ for module in modules:
+ for dep in soong.transitive_deps(module):
+ for m in soong.makefiles.get(dep, []):
+ if not summary.IsClean(m):
+ return False
+ return True
+
+ return [Analysis(makefile.filename, []) for makefile in makefiles
+ if clean_and_only_blocked_by_clean(makefile)]
+
+def print_analysis_header(link, title):
+ print("""
+ <a name="%(link)s"></a>
+ <h2>%(title)s</h2>
+ <table>
+ <tr>
+ <th class="RowTitle">Directory</th>
+ <th class="Count">Total</th>
+ <th class="Count Clean">Easy</th>
+ <th class="Count Clean">Unblocked Clean</th>
+ <th class="Count Unblocked">Unblocked</th>
+ <th class="Count Blocked">Blocked</th>
+ <th class="Count Clean">Clean</th>
+ """ % {
+ "link": link,
+ "title": title
+ })
+ for analyzer in ANALYZERS:
+ print("""<th class="Count Warning">%s</th>""" % analyzer.title)
+ print(" </tr>")
+
+
+def print_analysis_row(soong, summary, annotations, modules, rowtitle, rowclass, makefiles):
+ all_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles]
+ clean_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles
+ if is_clean(makefile)]
+ easy_makefiles = traverse_ready_makefiles(soong, summary, makefiles)
+ unblocked_clean_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles
+ if (contains_unblocked_modules(soong, soong.reverse_makefiles[makefile.filename])
+ and is_clean(makefile))]
+ unblocked_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles
+ if contains_unblocked_modules(soong,
+ soong.reverse_makefiles[makefile.filename])]
+ blocked_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles
+ if contains_blocked_modules(soong, soong.reverse_makefiles[makefile.filename])]
+
+ print("""
+ <tr class="%(rowclass)s">
+ <td class="RowTitle">%(rowtitle)s</td>
+ <td class="Count">%(makefiles)s</td>
+ <td class="Count">%(easy)s</td>
+ <td class="Count">%(unblocked_clean)s</td>
+ <td class="Count">%(unblocked)s</td>
+ <td class="Count">%(blocked)s</td>
+ <td class="Count">%(clean)s</td>
+ """ % {
+ "rowclass": rowclass,
+ "rowtitle": rowtitle,
+ "makefiles": make_annotation_link(annotations, all_makefiles, modules),
+ "unblocked": make_annotation_link(annotations, unblocked_makefiles, modules),
+ "blocked": make_annotation_link(annotations, blocked_makefiles, modules),
+ "clean": make_annotation_link(annotations, clean_makefiles, modules),
+ "unblocked_clean": make_annotation_link(annotations, unblocked_clean_makefiles, modules),
+ "easy": make_annotation_link(annotations, easy_makefiles, modules),
+ })
+
+ for analyzer in ANALYZERS:
+ analyses = [m.analyses.get(analyzer) for m in makefiles if m.analyses.get(analyzer)]
+ print("""<td class="Count">%s</td>"""
+ % make_annotation_link(annotations, analyses, modules))
+
+ print(" </tr>")
+
def main():
parser = argparse.ArgumentParser(description="Info about remaining Android.mk files.")
parser.add_argument("--device", type=str, required=True,
@@ -297,7 +394,7 @@
args.out_dir = args.out_dir[:-1]
TARGET_DEVICE = args.device
- HOST_OUT_ROOT = args.out_dir + "host"
+ HOST_OUT_ROOT = args.out_dir + "/host"
PRODUCT_OUT = args.out_dir + "/target/product/%s" % TARGET_DEVICE
if args.title:
@@ -343,7 +440,7 @@
overflow: hidden;
}
#tables {
- padding: 0 20px 0 20px;
+ padding: 0 20px 40px 20px;
overflow: scroll;
flex: 2 2 600px;
}
@@ -359,7 +456,7 @@
h2 {
margin: 12px 0 4px 0;
}
- .DirName {
+ .RowTitle {
text-align: left;
width: 200px;
min-width: 200px;
@@ -395,6 +492,10 @@
padding: 2px 4px;
border-right: 2px solid white;
}
+ tr.TotalRow td {
+ background-color: white;
+ border-right-color: white;
+ }
tr.AospDir td {
background-color: #e6f4ea;
border-right-color: #e6f4ea;
@@ -501,6 +602,7 @@
print("""
<span class='NavSpacer'></span><span class='NavSpacer'> </span>
+ <a href='#summary'>Overall Summary</a>
</div>
<div id="container">
<div id="tables">
@@ -530,6 +632,16 @@
<td>The total number of makefiles in this each directory.</td>
</tr>
<tr>
+ <th class="Clean">Easy</th>
+ <td>The number of makefiles that have no warnings themselves, and also
+ none of their dependencies have warnings either.</td>
+ </tr>
+ <tr>
+ <th class="Clean">Unblocked Clean</th>
+ <td>The number of makefiles that are both Unblocked and Clean.</td>
+ </tr>
+
+ <tr>
<th class="Unblocked">Unblocked</th>
<td>Makefiles containing one or more modules that don't have any
additional dependencies pending before conversion.</td>
@@ -598,6 +710,7 @@
""")
annotations = Annotations()
+ overall_summary = Summary()
# For each partition
makefiles_for_partitions = dict()
@@ -612,6 +725,7 @@
for filename in makefiles:
if not filename.startswith(args.out_dir + "/"):
summary.Add(Makefile(filename))
+ overall_summary.Add(Makefile(filename))
# Categorize directories by who is responsible
aosp_dirs = []
@@ -625,61 +739,18 @@
else:
partner_dirs.append(dirname)
- print("""
- <a name="partition_%(partition)s"></a>
- <h2>%(partition)s</h2>
- <table>
- <tr>
- <th class="DirName">Directory</th>
- <th class="Count">Total</th>
- <th class="Count Unblocked">Unblocked</th>
- <th class="Count Blocked">Blocked</th>
- <th class="Count Clean">Clean</th>
- """ % {
- "partition": partition
- })
+ print_analysis_header("partition_" + partition, partition)
- for analyzer in ANALYZERS:
- print("""<th class="Count Warning">%s</th>""" % analyzer.title)
-
- print(" </tr>")
for dirgroup, rowclass in [(aosp_dirs, "AospDir"),
(google_dirs, "GoogleDir"),
(partner_dirs, "PartnerDir"),]:
for dirname in dirgroup:
- makefiles = summary.directories[dirname]
+ print_analysis_row(soong, summary, annotations, modules,
+ dirname, rowclass, summary.directories[dirname])
- all_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles]
- clean_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles
- if is_clean(makefile)]
- unblocked_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles
- if contains_unblocked_modules(soong,
- soong.reverse_makefiles[makefile.filename])]
- blocked_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles
- if contains_blocked_modules(soong,
- soong.reverse_makefiles[makefile.filename])]
-
- print("""
- <tr class="%(rowclass)s">
- <td class="DirName">%(dirname)s</td>
- <td class="Count">%(makefiles)s</td>
- <td class="Count">%(unblocked)s</td>
- <td class="Count">%(blocked)s</td>
- <td class="Count">%(clean)s</td>
- """ % {
- "rowclass": rowclass,
- "dirname": dirname,
- "makefiles": make_annotation_link(annotations, all_makefiles, modules),
- "unblocked": make_annotation_link(annotations, unblocked_makefiles, modules),
- "blocked": make_annotation_link(annotations, blocked_makefiles, modules),
- "clean": make_annotation_link(annotations, clean_makefiles, modules),
- })
- for analyzer in ANALYZERS:
- analyses = [m.analyses.get(analyzer) for m in makefiles if m.analyses.get(analyzer)]
- print("""<td class="Count">%s</td>"""
- % make_annotation_link(annotations, analyses, modules))
-
- print(" </tr>")
+ print_analysis_row(soong, summary, annotations, modules,
+ "Total", "TotalRow",
+ set(itertools.chain.from_iterable(summary.directories.values())))
print("""
</table>
""")
@@ -718,6 +789,16 @@
print("</tr>")
print("""</table>""")
+ print_analysis_header("summary", "Overall Summary")
+
+ modules = [module for installed, module in soong.installed.items()]
+ print_analysis_row(soong, overall_summary, annotations, modules,
+ "All Makefiles", "TotalRow",
+ set(itertools.chain.from_iterable(overall_summary.directories.values())))
+ print("""
+ </table>
+ """)
+
print("""
<script type="text/javascript">
function close_details() {