Refactor the mongo main() into a class in mk2bp_catalog.py
Test: m out/target/product/$(get_build_var TARGET_DEVICE)/mk2bp_remaining.html
Change-Id: I7200f5f9a6735bb0da3928aa5dc74723d69752d3
diff --git a/tools/mk2bp_catalog.py b/tools/mk2bp_catalog.py
index e85ae18..e41f3ea 100755
--- a/tools/mk2bp_catalog.py
+++ b/tools/mk2bp_catalog.py
@@ -177,16 +177,6 @@
return True
return False
-def make_annotation_link(annotations, analysis, modules):
- if analysis:
- return "<a href='javascript:update_details(%d)'>%s</a>" % (
- annotations.Add(analysis, modules),
- len(analysis)
- )
- else:
- return "";
-
-
def is_clean(makefile):
for analysis in makefile.analyses.values():
if analysis:
@@ -242,6 +232,18 @@
traverse(module)
return results
+ def contains_unblocked_modules(self, filename):
+ for m in self.reverse_makefiles[filename]:
+ if len(self.deps[m]) == 0:
+ return True
+ return False
+
+ def contains_blocked_modules(self, filename):
+ for m in self.reverse_makefiles[filename]:
+ if len(self.deps[m]) > 0:
+ return True
+ return False
+
def count_deps(depsdb, module, seen):
"""Based on the depsdb, count the number of transitive dependencies.
@@ -256,18 +258,6 @@
count += 1 + count_deps(depsdb, dep, seen)
return count
-def contains_unblocked_modules(soong, modules):
- for m in modules:
- if len(soong.deps[m]) == 0:
- return True
- return False
-
-def contains_blocked_modules(soong, modules):
- for m in modules:
- if len(soong.deps[m]) > 0:
- return True
- return False
-
OTHER_PARTITON = "_other"
HOST_PARTITON = "_host"
@@ -292,21 +282,6 @@
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>
@@ -328,48 +303,6 @@
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,
@@ -394,14 +327,11 @@
args.out_dir = args.out_dir[:-1]
TARGET_DEVICE = args.device
+ global HOST_OUT_ROOT
HOST_OUT_ROOT = args.out_dir + "/host"
+ global PRODUCT_OUT
PRODUCT_OUT = args.out_dir + "/target/product/%s" % TARGET_DEVICE
- if args.title:
- page_title = args.title
- else:
- page_title = "Remaining Android.mk files"
-
# Read target information
# TODO: Pull from configurable location. This is also slightly different because it's
# only a single build, where as the tree scanning we do below is all Android.mk files.
@@ -409,564 +339,650 @@
% PRODUCT_OUT, "r", errors="ignore") as csvfile:
soong = SoongData(csv.reader(csvfile))
- # Which modules are installed where
- modules_by_partition = dict()
- partitions = set()
- for installed, module in soong.installed.items():
- partition = get_partition_from_installed(HOST_OUT_ROOT, PRODUCT_OUT, installed)
- modules_by_partition.setdefault(partition, []).append(module)
- partitions.add(partition)
+ # Read the makefiles
+ all_makefiles = dict()
+ for filename, modules in soong.reverse_makefiles.items():
+ if filename.startswith(args.out_dir + "/"):
+ continue
+ all_makefiles[filename] = Makefile(filename)
- print("""
- <html>
- <head>
- <title>%(page_title)s</title>
- <style type="text/css">
- body, table {
- font-family: Roboto, sans-serif;
- font-size: 9pt;
- }
- body {
- margin: 0;
- padding: 0;
- display: flex;
- flex-direction: column;
- height: 100vh;
- }
- #container {
- flex: 1;
- display: flex;
- flex-direction: row;
- overflow: hidden;
- }
- #tables {
- padding: 0 20px 40px 20px;
- overflow: scroll;
- flex: 2 2 600px;
- }
- #details {
- display: none;
- overflow: scroll;
- flex: 1 1 650px;
- padding: 0 20px 0 20px;
- }
- h1 {
- margin: 16px 0 16px 20px;
- }
- h2 {
- margin: 12px 0 4px 0;
- }
- .RowTitle {
- text-align: left;
- width: 200px;
- min-width: 200px;
- }
- .Count {
- text-align: center;
- width: 60px;
- min-width: 60px;
- max-width: 60px;
- }
- th.Clean,
- th.Unblocked {
- background-color: #1e8e3e;
- }
- th.Blocked {
- background-color: #d93025;
- }
- th.Warning {
- background-color: #e8710a;
- }
- th {
- background-color: #1a73e8;
- color: white;
- font-weight: bold;
- }
- td.Unblocked {
- background-color: #81c995;
- }
- td.Blocked {
- background-color: #f28b82;
- }
- td, th {
- 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;
- }
- tr.GoogleDir td {
- background-color: #e8f0fe;
- border-right-color: #e8f0fe;
- }
- tr.PartnerDir td {
- background-color: #fce8e6;
- border-right-color: #fce8e6;
- }
- table {
- border-spacing: 0;
- border-collapse: collapse;
- }
- div.Makefile {
- margin: 12px 0 0 0;
- }
- div.Makefile:first {
- margin-top: 0;
- }
- div.FileModules {
- padding: 4px 0 0 20px;
- }
- td.LineNo {
- vertical-align: baseline;
- padding: 6px 0 0 20px;
- width: 50px;
- vertical-align: baseline;
- }
- td.LineText {
- vertical-align: baseline;
- font-family: monospace;
- padding: 6px 0 0 0;
- }
- a.CsLink {
- font-family: monospace;
- }
- div.Help {
- width: 550px;
- }
- table.HelpColumns tr {
- border-bottom: 2px solid white;
- }
- .ModuleName {
- vertical-align: baseline;
- padding: 6px 0 0 20px;
- width: 275px;
- }
- .ModuleDeps {
- vertical-align: baseline;
- padding: 6px 0 0 0;
- }
- table#Modules td {
- vertical-align: baseline;
- }
- tr.Alt {
- background-color: #ececec;
- }
- tr.Alt td {
- border-right-color: #ececec;
- }
- .AnalysisCol {
- width: 300px;
- padding: 2px;
- line-height: 21px;
- }
- .Analysis {
- color: white;
- font-weight: bold;
- background-color: #e8710a;
- border-radius: 6px;
- margin: 4px;
- padding: 2px 6px;
- white-space: nowrap;
- }
- .Nav {
- margin: 4px 0 16px 20px;
- }
- .NavSpacer {
- display: inline-block;
- width: 6px;
- }
- .ModuleDetails {
- margin-top: 20px;
- }
- .ModuleDetails td {
- vertical-align: baseline;
- }
- </style>
- </head>
- <body>
- <h1>%(page_title)s</h1>
- <div class="Nav">
- <a href='#help'>Help</a>
- <span class='NavSpacer'></span><span class='NavSpacer'> </span>
- Partitions:
- """ % {
- "page_title": page_title,
- })
- for partition in sorted(partitions):
- print("<a href='#partition_%s'>%s</a><span class='NavSpacer'></span>" % (partition, partition))
+ HtmlProcessor(args=args, soong=soong, all_makefiles=all_makefiles).execute()
- print("""
- <span class='NavSpacer'></span><span class='NavSpacer'> </span>
- <a href='#summary'>Overall Summary</a>
- </div>
- <div id="container">
- <div id="tables">
- <a name="help"></a>
- <div class="Help">
- <p>
- This page analyzes the remaining Android.mk files in the Android Source tree.
- <p>
- The modules are first broken down by which of the device filesystem partitions
- they are installed to. This also includes host tools and testcases which don't
- actually reside in their own partition but convenitely group together.
- <p>
- The makefiles for each partition are further are grouped into a set of directories
- aritrarily picked to break down the problem size by owners.
- <ul style="width: 300px">
- <li style="background-color: #e6f4ea">AOSP directories are colored green.</li>
- <li style="background-color: #e8f0fe">Google directories are colored blue.</li>
- <li style="background-color: #fce8e6">Other partner directories are colored red.</li>
- </ul>
- Each of the makefiles are scanned for issues that are likely to come up during
- conversion to soong. Clicking the number in each cell shows additional information,
- including the line that triggered the warning.
- <p>
- <table class="HelpColumns">
- <tr>
- <th>Total</th>
- <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>
+class HtmlProcessor(object):
+ def __init__(self, args, soong, all_makefiles):
+ self.args = args
+ self.soong = soong
+ self.all_makefiles = all_makefiles
+ self.annotations = Annotations()
- <tr>
- <th class="Unblocked">Unblocked</th>
- <td>Makefiles containing one or more modules that don't have any
- additional dependencies pending before conversion.</td>
- </tr>
- <tr>
- <th class="Blocked">Blocked</th>
- <td>Makefiles containiong one or more modules which <i>do</i> have
- additional prerequesite depenedencies that are not yet converted.</td>
- </tr>
- <tr>
- <th class="Clean">Clean</th>
- <td>The number of makefiles that have none of the following warnings.</td>
- </tr>
- <tr>
- <th class="Warning">ifeq / ifneq</th>
- <td>Makefiles that use <code>ifeq</code> or <code>ifneq</code>. i.e.
- conditionals.</td>
- </tr>
- <tr>
- <th class="Warning">Wacky Includes</th>
- <td>Makefiles that <code>include</code> files other than the standard build-system
- defined template and macros.</td>
- </tr>
- <tr>
- <th class="Warning">Calls base_rules</th>
- <td>Makefiles that include base_rules.mk directly.</td>
- </tr>
- <tr>
- <th class="Warning">Calls define</th>
- <td>Makefiles that define their own macros. Some of these are easy to convert
- to soong <code>defaults</code>, but others are complex.</td>
- </tr>
- <tr>
- <th class="Warning">Has ../</th>
- <td>Makefiles containing the string "../" outside of a comment. These likely
- access files outside their directories.</td>
- </tr>
- <tr>
- <th class="Warning">dist-for-goals</th>
- <td>Makefiles that call <code>dist-for-goals</code> directly.</td>
- </tr>
- <tr>
- <th class="Warning">.PHONY</th>
- <td>Makefiles that declare .PHONY targets.</td>
- </tr>
- <tr>
- <th class="Warning">renderscript</th>
- <td>Makefiles defining targets that depend on <code>.rscript</code> source files.</td>
- </tr>
- <tr>
- <th class="Warning">vts src</th>
- <td>Makefiles defining targets that depend on <code>.vts</code> source files.</td>
- </tr>
- <tr>
- <th class="Warning">COPY_HEADERS</th>
- <td>Makefiles using LOCAL_COPY_HEADERS.</td>
- </tr>
- </table>
- <p>
- Following the list of directories is a list of the modules that are installed on
- each partition. Potential issues from their makefiles are listed, as well as the
- total number of dependencies (both blocking that module and blocked by that module)
- and the list of direct dependencies. Note: The number is the number of all transitive
- dependencies and the list of modules is only the direct dependencies.
- </div>
- """)
+ def execute(self):
+ if self.args.title:
+ page_title = self.args.title
+ else:
+ page_title = "Remaining Android.mk files"
- annotations = Annotations()
- overall_summary = Summary()
+ # Which modules are installed where
+ modules_by_partition = dict()
+ partitions = set()
+ for installed, module in self.soong.installed.items():
+ partition = get_partition_from_installed(HOST_OUT_ROOT, PRODUCT_OUT, installed)
+ modules_by_partition.setdefault(partition, []).append(module)
+ partitions.add(partition)
- # For each partition
- makefiles_for_partitions = dict()
- for partition in sorted(partitions):
- modules = modules_by_partition[partition]
-
- makefiles = set(itertools.chain.from_iterable(
- [soong.makefiles[module] for module in modules]))
-
- # Read makefiles
- summary = Summary()
- 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 = []
- google_dirs = []
- partner_dirs = []
- for dirname in sorted(summary.directories.keys()):
- if is_aosp(dirname):
- aosp_dirs.append(dirname)
- elif is_google(dirname):
- google_dirs.append(dirname)
- else:
- partner_dirs.append(dirname)
-
- print_analysis_header("partition_" + partition, partition)
-
- for dirgroup, rowclass in [(aosp_dirs, "AospDir"),
- (google_dirs, "GoogleDir"),
- (partner_dirs, "PartnerDir"),]:
- for dirname in dirgroup:
- print_analysis_row(soong, summary, annotations, modules,
- dirname, rowclass, summary.directories[dirname])
-
- print_analysis_row(soong, summary, annotations, modules,
- "Total", "TotalRow",
- set(itertools.chain.from_iterable(summary.directories.values())))
print("""
- </table>
+ <html>
+ <head>
+ <title>%(page_title)s</title>
+ <style type="text/css">
+ body, table {
+ font-family: Roboto, sans-serif;
+ font-size: 9pt;
+ }
+ body {
+ margin: 0;
+ padding: 0;
+ display: flex;
+ flex-direction: column;
+ height: 100vh;
+ }
+ #container {
+ flex: 1;
+ display: flex;
+ flex-direction: row;
+ overflow: hidden;
+ }
+ #tables {
+ padding: 0 20px 40px 20px;
+ overflow: scroll;
+ flex: 2 2 600px;
+ }
+ #details {
+ display: none;
+ overflow: scroll;
+ flex: 1 1 650px;
+ padding: 0 20px 0 20px;
+ }
+ h1 {
+ margin: 16px 0 16px 20px;
+ }
+ h2 {
+ margin: 12px 0 4px 0;
+ }
+ .RowTitle {
+ text-align: left;
+ width: 200px;
+ min-width: 200px;
+ }
+ .Count {
+ text-align: center;
+ width: 60px;
+ min-width: 60px;
+ max-width: 60px;
+ }
+ th.Clean,
+ th.Unblocked {
+ background-color: #1e8e3e;
+ }
+ th.Blocked {
+ background-color: #d93025;
+ }
+ th.Warning {
+ background-color: #e8710a;
+ }
+ th {
+ background-color: #1a73e8;
+ color: white;
+ font-weight: bold;
+ }
+ td.Unblocked {
+ background-color: #81c995;
+ }
+ td.Blocked {
+ background-color: #f28b82;
+ }
+ td, th {
+ 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;
+ }
+ tr.GoogleDir td {
+ background-color: #e8f0fe;
+ border-right-color: #e8f0fe;
+ }
+ tr.PartnerDir td {
+ background-color: #fce8e6;
+ border-right-color: #fce8e6;
+ }
+ table {
+ border-spacing: 0;
+ border-collapse: collapse;
+ }
+ div.Makefile {
+ margin: 12px 0 0 0;
+ }
+ div.Makefile:first {
+ margin-top: 0;
+ }
+ div.FileModules {
+ padding: 4px 0 0 20px;
+ }
+ td.LineNo {
+ vertical-align: baseline;
+ padding: 6px 0 0 20px;
+ width: 50px;
+ vertical-align: baseline;
+ }
+ td.LineText {
+ vertical-align: baseline;
+ font-family: monospace;
+ padding: 6px 0 0 0;
+ }
+ a.CsLink {
+ font-family: monospace;
+ }
+ div.Help {
+ width: 550px;
+ }
+ table.HelpColumns tr {
+ border-bottom: 2px solid white;
+ }
+ .ModuleName {
+ vertical-align: baseline;
+ padding: 6px 0 0 20px;
+ width: 275px;
+ }
+ .ModuleDeps {
+ vertical-align: baseline;
+ padding: 6px 0 0 0;
+ }
+ table#Modules td {
+ vertical-align: baseline;
+ }
+ tr.Alt {
+ background-color: #ececec;
+ }
+ tr.Alt td {
+ border-right-color: #ececec;
+ }
+ .AnalysisCol {
+ width: 300px;
+ padding: 2px;
+ line-height: 21px;
+ }
+ .Analysis {
+ color: white;
+ font-weight: bold;
+ background-color: #e8710a;
+ border-radius: 6px;
+ margin: 4px;
+ padding: 2px 6px;
+ white-space: nowrap;
+ }
+ .Nav {
+ margin: 4px 0 16px 20px;
+ }
+ .NavSpacer {
+ display: inline-block;
+ width: 6px;
+ }
+ .ModuleDetails {
+ margin-top: 20px;
+ }
+ .ModuleDetails td {
+ vertical-align: baseline;
+ }
+ </style>
+ </head>
+ <body>
+ <h1>%(page_title)s</h1>
+ <div class="Nav">
+ <a href='#help'>Help</a>
+ <span class='NavSpacer'></span><span class='NavSpacer'> </span>
+ Partitions:
+ """ % {
+ "page_title": page_title,
+ })
+ for partition in sorted(partitions):
+ print("<a href='#partition_%s'>%s</a><span class='NavSpacer'></span>" % (partition, partition))
+
+ print("""
+ <span class='NavSpacer'></span><span class='NavSpacer'> </span>
+ <a href='#summary'>Overall Summary</a>
+ </div>
+ <div id="container">
+ <div id="tables">
+ <a name="help"></a>
+ <div class="Help">
+ <p>
+ This page analyzes the remaining Android.mk files in the Android Source tree.
+ <p>
+ The modules are first broken down by which of the device filesystem partitions
+ they are installed to. This also includes host tools and testcases which don't
+ actually reside in their own partition but convenitely group together.
+ <p>
+ The makefiles for each partition are further are grouped into a set of directories
+ aritrarily picked to break down the problem size by owners.
+ <ul style="width: 300px">
+ <li style="background-color: #e6f4ea">AOSP directories are colored green.</li>
+ <li style="background-color: #e8f0fe">Google directories are colored blue.</li>
+ <li style="background-color: #fce8e6">Other partner directories are colored red.</li>
+ </ul>
+ Each of the makefiles are scanned for issues that are likely to come up during
+ conversion to soong. Clicking the number in each cell shows additional information,
+ including the line that triggered the warning.
+ <p>
+ <table class="HelpColumns">
+ <tr>
+ <th>Total</th>
+ <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>
+ </tr>
+ <tr>
+ <th class="Blocked">Blocked</th>
+ <td>Makefiles containiong one or more modules which <i>do</i> have
+ additional prerequesite depenedencies that are not yet converted.</td>
+ </tr>
+ <tr>
+ <th class="Clean">Clean</th>
+ <td>The number of makefiles that have none of the following warnings.</td>
+ </tr>
+ <tr>
+ <th class="Warning">ifeq / ifneq</th>
+ <td>Makefiles that use <code>ifeq</code> or <code>ifneq</code>. i.e.
+ conditionals.</td>
+ </tr>
+ <tr>
+ <th class="Warning">Wacky Includes</th>
+ <td>Makefiles that <code>include</code> files other than the standard build-system
+ defined template and macros.</td>
+ </tr>
+ <tr>
+ <th class="Warning">Calls base_rules</th>
+ <td>Makefiles that include base_rules.mk directly.</td>
+ </tr>
+ <tr>
+ <th class="Warning">Calls define</th>
+ <td>Makefiles that define their own macros. Some of these are easy to convert
+ to soong <code>defaults</code>, but others are complex.</td>
+ </tr>
+ <tr>
+ <th class="Warning">Has ../</th>
+ <td>Makefiles containing the string "../" outside of a comment. These likely
+ access files outside their directories.</td>
+ </tr>
+ <tr>
+ <th class="Warning">dist-for-goals</th>
+ <td>Makefiles that call <code>dist-for-goals</code> directly.</td>
+ </tr>
+ <tr>
+ <th class="Warning">.PHONY</th>
+ <td>Makefiles that declare .PHONY targets.</td>
+ </tr>
+ <tr>
+ <th class="Warning">renderscript</th>
+ <td>Makefiles defining targets that depend on <code>.rscript</code> source files.</td>
+ </tr>
+ <tr>
+ <th class="Warning">vts src</th>
+ <td>Makefiles defining targets that depend on <code>.vts</code> source files.</td>
+ </tr>
+ <tr>
+ <th class="Warning">COPY_HEADERS</th>
+ <td>Makefiles using LOCAL_COPY_HEADERS.</td>
+ </tr>
+ </table>
+ <p>
+ Following the list of directories is a list of the modules that are installed on
+ each partition. Potential issues from their makefiles are listed, as well as the
+ total number of dependencies (both blocking that module and blocked by that module)
+ and the list of direct dependencies. Note: The number is the number of all transitive
+ dependencies and the list of modules is only the direct dependencies.
+ </div>
""")
- module_details = [(count_deps(soong.deps, m, []), -count_deps(soong.reverse_deps, m, []), m)
- for m in modules]
- module_details.sort()
- module_details = [m[2] for m in module_details]
- print("""
- <table class="ModuleDetails">""")
- print("<tr>")
- print(" <th>Module Name</th>")
- print(" <th>Issues</th>")
- print(" <th colspan='2'>Blocked By</th>")
- print(" <th colspan='2'>Blocking</th>")
- print("</tr>")
- altRow = True
- for module in module_details:
- analyses = set()
- for filename in soong.makefiles[module]:
- makefile = summary.makefiles.get(filename)
+ overall_summary = Summary()
+
+ # For each partition
+ for partition in sorted(partitions):
+ modules = modules_by_partition[partition]
+
+ makefiles = set(itertools.chain.from_iterable(
+ [self.soong.makefiles[module] for module in modules]))
+
+ # Read makefiles
+ summary = Summary()
+ for filename in makefiles:
+ makefile = self.all_makefiles.get(filename)
if makefile:
- for analyzer, analysis in makefile.analyses.items():
- if analysis:
- analyses.add(analyzer.title)
+ summary.Add(makefile)
+ overall_summary.Add(makefile)
- altRow = not altRow
- print("<tr class='%s'>" % ("Alt" if altRow else "",))
- print(" <td><a name='module_%s'></a>%s</td>" % (module, module))
- print(" <td class='AnalysisCol'>%s</td>" % " ".join(["<span class='Analysis'>%s</span>" % title
- for title in analyses]))
- print(" <td>%s</td>" % count_deps(soong.deps, module, []))
- print(" <td>%s</td>" % format_module_list(soong.deps.get(module, [])))
- print(" <td>%s</td>" % count_deps(soong.reverse_deps, module, []))
- print(" <td>%s</td>" % format_module_list(soong.reverse_deps.get(module, [])))
+ # Categorize directories by who is responsible
+ aosp_dirs = []
+ google_dirs = []
+ partner_dirs = []
+ for dirname in sorted(summary.directories.keys()):
+ if is_aosp(dirname):
+ aosp_dirs.append(dirname)
+ elif is_google(dirname):
+ google_dirs.append(dirname)
+ else:
+ partner_dirs.append(dirname)
+
+ print_analysis_header("partition_" + partition, partition)
+
+ for dirgroup, rowclass in [(aosp_dirs, "AospDir"),
+ (google_dirs, "GoogleDir"),
+ (partner_dirs, "PartnerDir"),]:
+ for dirname in dirgroup:
+ self.print_analysis_row(summary, modules,
+ dirname, rowclass, summary.directories[dirname])
+
+ self.print_analysis_row(summary, modules,
+ "Total", "TotalRow",
+ set(itertools.chain.from_iterable(summary.directories.values())))
+ print("""
+ </table>
+ """)
+
+ module_details = [(count_deps(self.soong.deps, m, []),
+ -count_deps(self.soong.reverse_deps, m, []), m)
+ for m in modules]
+ module_details.sort()
+ module_details = [m[2] for m in module_details]
+ print("""
+ <table class="ModuleDetails">""")
+ print("<tr>")
+ print(" <th>Module Name</th>")
+ print(" <th>Issues</th>")
+ print(" <th colspan='2'>Blocked By</th>")
+ print(" <th colspan='2'>Blocking</th>")
print("</tr>")
- print("""</table>""")
+ altRow = True
+ for module in module_details:
+ analyses = set()
+ for filename in self.soong.makefiles[module]:
+ makefile = summary.makefiles.get(filename)
+ if makefile:
+ for analyzer, analysis in makefile.analyses.items():
+ if analysis:
+ analyses.add(analyzer.title)
- print_analysis_header("summary", "Overall Summary")
+ altRow = not altRow
+ print("<tr class='%s'>" % ("Alt" if altRow else "",))
+ print(" <td><a name='module_%s'></a>%s</td>" % (module, module))
+ print(" <td class='AnalysisCol'>%s</td>" % " ".join(["<span class='Analysis'>%s</span>" % title
+ for title in analyses]))
+ print(" <td>%s</td>" % count_deps(self.soong.deps, module, []))
+ print(" <td>%s</td>" % format_module_list(self.soong.deps.get(module, [])))
+ print(" <td>%s</td>" % count_deps(self.soong.reverse_deps, module, []))
+ print(" <td>%s</td>" % format_module_list(self.soong.reverse_deps.get(module, [])))
+ print("</tr>")
+ print("""</table>""")
- 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_analysis_header("summary", "Overall Summary")
- print("""
- <script type="text/javascript">
- function close_details() {
- document.getElementById('details').style.display = 'none';
- }
+ modules = [module for installed, module in self.soong.installed.items()]
+ self.print_analysis_row(overall_summary, modules,
+ "All Makefiles", "TotalRow",
+ set(itertools.chain.from_iterable(overall_summary.directories.values())))
+ print("""
+ </table>
+ """)
- class LineMatch {
- constructor(lineno, text) {
- this.lineno = lineno;
- this.text = text;
- }
- }
-
- class Analysis {
- constructor(filename, modules, line_matches) {
- this.filename = filename;
- this.modules = modules;
- this.line_matches = line_matches;
- }
- }
-
- class Module {
- constructor(deps) {
- this.deps = deps;
- }
- }
-
- function make_module_link(module) {
- var a = document.createElement('a');
- a.className = 'ModuleLink';
- a.innerText = module;
- a.href = '#module_' + module;
- return a;
- }
-
- function update_details(id) {
- document.getElementById('details').style.display = 'block';
-
- var analyses = ANALYSIS[id];
-
- var details = document.getElementById("details_data");
- while (details.firstChild) {
- details.removeChild(details.firstChild);
+ print("""
+ <script type="text/javascript">
+ function close_details() {
+ document.getElementById('details').style.display = 'none';
}
- for (var i=0; i<analyses.length; i++) {
- var analysis = analyses[i];
+ class LineMatch {
+ constructor(lineno, text) {
+ this.lineno = lineno;
+ this.text = text;
+ }
+ }
- var makefileDiv = document.createElement('div');
- makefileDiv.className = 'Makefile';
- details.appendChild(makefileDiv);
+ class Analysis {
+ constructor(filename, modules, line_matches) {
+ this.filename = filename;
+ this.modules = modules;
+ this.line_matches = line_matches;
+ }
+ }
- var fileA = document.createElement('a');
- makefileDiv.appendChild(fileA);
- fileA.className = 'CsLink';
- fileA.href = '%(codesearch)s' + analysis.filename;
- fileA.innerText = analysis.filename;
- fileA.target = "_blank";
+ class Module {
+ constructor(deps) {
+ this.deps = deps;
+ }
+ }
- if (analysis.modules.length > 0) {
- var moduleTable = document.createElement('table');
- details.appendChild(moduleTable);
+ function make_module_link(module) {
+ var a = document.createElement('a');
+ a.className = 'ModuleLink';
+ a.innerText = module;
+ a.href = '#module_' + module;
+ return a;
+ }
- for (var j=0; j<analysis.modules.length; j++) {
- var moduleRow = document.createElement('tr');
- moduleTable.appendChild(moduleRow);
+ function update_details(id) {
+ document.getElementById('details').style.display = 'block';
- var moduleNameCell = document.createElement('td');
- moduleRow.appendChild(moduleNameCell);
- moduleNameCell.className = 'ModuleName';
- moduleNameCell.appendChild(make_module_link(analysis.modules[j]));
+ var analyses = ANALYSIS[id];
- var moduleData = MODULE_DATA[analysis.modules[j]];
- console.log(moduleData);
+ var details = document.getElementById("details_data");
+ while (details.firstChild) {
+ details.removeChild(details.firstChild);
+ }
- var depCell = document.createElement('td');
- moduleRow.appendChild(depCell);
+ for (var i=0; i<analyses.length; i++) {
+ var analysis = analyses[i];
- if (moduleData.deps.length == 0) {
- depCell.className = 'ModuleDeps Unblocked';
- depCell.innerText = 'UNBLOCKED';
- } else {
- depCell.className = 'ModuleDeps Blocked';
+ var makefileDiv = document.createElement('div');
+ makefileDiv.className = 'Makefile';
+ details.appendChild(makefileDiv);
- for (var k=0; k<moduleData.deps.length; k++) {
- depCell.appendChild(make_module_link(moduleData.deps[k]));
- depCell.appendChild(document.createElement('br'));
+ var fileA = document.createElement('a');
+ makefileDiv.appendChild(fileA);
+ fileA.className = 'CsLink';
+ fileA.href = '%(codesearch)s' + analysis.filename;
+ fileA.innerText = analysis.filename;
+ fileA.target = "_blank";
+
+ if (analysis.modules.length > 0) {
+ var moduleTable = document.createElement('table');
+ details.appendChild(moduleTable);
+
+ for (var j=0; j<analysis.modules.length; j++) {
+ var moduleRow = document.createElement('tr');
+ moduleTable.appendChild(moduleRow);
+
+ var moduleNameCell = document.createElement('td');
+ moduleRow.appendChild(moduleNameCell);
+ moduleNameCell.className = 'ModuleName';
+ moduleNameCell.appendChild(make_module_link(analysis.modules[j]));
+
+ var moduleData = MODULE_DATA[analysis.modules[j]];
+ console.log(moduleData);
+
+ var depCell = document.createElement('td');
+ moduleRow.appendChild(depCell);
+
+ if (moduleData.deps.length == 0) {
+ depCell.className = 'ModuleDeps Unblocked';
+ depCell.innerText = 'UNBLOCKED';
+ } else {
+ depCell.className = 'ModuleDeps Blocked';
+
+ for (var k=0; k<moduleData.deps.length; k++) {
+ depCell.appendChild(make_module_link(moduleData.deps[k]));
+ depCell.appendChild(document.createElement('br'));
+ }
}
}
}
- }
- if (analysis.line_matches.length > 0) {
- var lineTable = document.createElement('table');
- details.appendChild(lineTable);
+ if (analysis.line_matches.length > 0) {
+ var lineTable = document.createElement('table');
+ details.appendChild(lineTable);
- for (var j=0; j<analysis.line_matches.length; j++) {
- var line_match = analysis.line_matches[j];
+ for (var j=0; j<analysis.line_matches.length; j++) {
+ var line_match = analysis.line_matches[j];
- var lineRow = document.createElement('tr');
- lineTable.appendChild(lineRow);
+ var lineRow = document.createElement('tr');
+ lineTable.appendChild(lineRow);
- var linenoCell = document.createElement('td');
- lineRow.appendChild(linenoCell);
- linenoCell.className = 'LineNo';
+ var linenoCell = document.createElement('td');
+ lineRow.appendChild(linenoCell);
+ linenoCell.className = 'LineNo';
- var linenoA = document.createElement('a');
- linenoCell.appendChild(linenoA);
- linenoA.className = 'CsLink';
- linenoA.href = '%(codesearch)s' + analysis.filename
- + ';l=' + line_match.lineno;
- linenoA.innerText = line_match.lineno;
- linenoA.target = "_blank";
+ var linenoA = document.createElement('a');
+ linenoCell.appendChild(linenoA);
+ linenoA.className = 'CsLink';
+ linenoA.href = '%(codesearch)s' + analysis.filename
+ + ';l=' + line_match.lineno;
+ linenoA.innerText = line_match.lineno;
+ linenoA.target = "_blank";
- var textCell = document.createElement('td');
- lineRow.appendChild(textCell);
- textCell.className = 'LineText';
- textCell.innerText = line_match.text;
+ var textCell = document.createElement('td');
+ lineRow.appendChild(textCell);
+ textCell.className = 'LineText';
+ textCell.innerText = line_match.text;
+ }
}
}
}
- }
- var ANALYSIS = [
- """ % {
- "codesearch": args.codesearch,
- })
- for entry, mods in annotations.entries:
- print(" [")
- for analysis in entry:
- print(" new Analysis('%(filename)s', %(modules)s, [%(line_matches)s])," % {
- "filename": analysis.filename,
- #"modules": json.dumps([m for m in mods if m in filename in soong.makefiles[m]]),
- "modules": json.dumps(
- [m for m in soong.reverse_makefiles[analysis.filename] if m in mods]),
- "line_matches": ", ".join([
- "new LineMatch(%d, %s)" % (lineno, json.dumps(text))
- for lineno, text in analysis.line_matches]),
+ var ANALYSIS = [
+ """ % {
+ "codesearch": self.args.codesearch,
})
- print(" ],")
- print("""
- ];
- var MODULE_DATA = {
- """)
- for module in soong.modules:
- print(" '%(name)s': new Module(%(deps)s)," % {
- "name": module,
- "deps": json.dumps(soong.deps[module]),
- })
- print("""
- };
- </script>
+ for entry, mods in self.annotations.entries:
+ print(" [")
+ for analysis in entry:
+ print(" new Analysis('%(filename)s', %(modules)s, [%(line_matches)s])," % {
+ "filename": analysis.filename,
+ #"modules": json.dumps([m for m in mods if m in filename in self.soong.makefiles[m]]),
+ "modules": json.dumps(
+ [m for m in self.soong.reverse_makefiles[analysis.filename] if m in mods]),
+ "line_matches": ", ".join([
+ "new LineMatch(%d, %s)" % (lineno, json.dumps(text))
+ for lineno, text in analysis.line_matches]),
+ })
+ print(" ],")
+ print("""
+ ];
+ var MODULE_DATA = {
+ """)
+ for module in self.soong.modules:
+ print(" '%(name)s': new Module(%(deps)s)," % {
+ "name": module,
+ "deps": json.dumps(self.soong.deps[module]),
+ })
+ print("""
+ };
+ </script>
- """)
+ """)
- print("""
- </div> <!-- id=tables -->
- <div id="details">
- <div style="text-align: right;">
- <a href="javascript:close_details();">
- <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
- </a>
+ print("""
+ </div> <!-- id=tables -->
+ <div id="details">
+ <div style="text-align: right;">
+ <a href="javascript:close_details();">
+ <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
+ </a>
+ </div>
+ <div id="details_data"></div>
</div>
- <div id="details_data"></div>
- </div>
- </body>
- </html>
- """)
+ </body>
+ </html>
+ """)
+
+ def traverse_ready_makefiles(self, summary, makefiles):
+ def clean_and_only_blocked_by_clean(makefile):
+ if not is_clean(makefile):
+ return False
+ modules = self.soong.reverse_makefiles[makefile.filename]
+ for module in modules:
+ for dep in self.soong.transitive_deps(module):
+ for m in self.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_row(self, summary, 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 = self.traverse_ready_makefiles(summary, makefiles)
+ unblocked_clean_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles
+ if (self.soong.contains_unblocked_modules(makefile.filename)
+ and is_clean(makefile))]
+ unblocked_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles
+ if self.soong.contains_unblocked_modules(makefile.filename)]
+ blocked_makefiles = [Analysis(makefile.filename, []) for makefile in makefiles
+ if self.soong.contains_blocked_modules(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": self.make_annotation_link(all_makefiles, modules),
+ "unblocked": self.make_annotation_link(unblocked_makefiles, modules),
+ "blocked": self.make_annotation_link(blocked_makefiles, modules),
+ "clean": self.make_annotation_link(clean_makefiles, modules),
+ "unblocked_clean": self.make_annotation_link(unblocked_clean_makefiles, modules),
+ "easy": self.make_annotation_link(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>"""
+ % self.make_annotation_link(analyses, modules))
+
+ print(" </tr>")
+
+ def make_annotation_link(self, analysis, modules):
+ if analysis:
+ return "<a href='javascript:update_details(%d)'>%s</a>" % (
+ self.annotations.Add(analysis, modules),
+ len(analysis)
+ )
+ else:
+ return "";
if __name__ == "__main__":
main()