Loading tools/mk2bp_catalog.py +613 −597 Original line number Diff line number Diff line Loading @@ -177,16 +177,6 @@ def is_google(dirname): 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: Loading Loading @@ -242,6 +232,18 @@ class SoongData(object): 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. Loading @@ -256,18 +258,6 @@ def count_deps(depsdb, module, seen): 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" Loading @@ -292,21 +282,6 @@ def format_module_link(module): 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> Loading @@ -328,48 +303,6 @@ def print_analysis_header(link, title): 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, Loading @@ -394,14 +327,11 @@ def main(): 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. Loading @@ -409,10 +339,32 @@ def main(): % PRODUCT_OUT, "r", errors="ignore") as csvfile: soong = SoongData(csv.reader(csvfile)) # 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) HtmlProcessor(args=args, soong=soong, all_makefiles=all_makefiles).execute() class HtmlProcessor(object): def __init__(self, args, soong, all_makefiles): self.args = args self.soong = soong self.all_makefiles = all_makefiles self.annotations = Annotations() def execute(self): if self.args.title: page_title = self.args.title else: page_title = "Remaining Android.mk files" # Which modules are installed where modules_by_partition = dict() partitions = set() for installed, module in soong.installed.items(): 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) Loading Loading @@ -709,23 +661,22 @@ def main(): </div> """) annotations = Annotations() overall_summary = Summary() # 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])) [self.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)) makefile = self.all_makefiles.get(filename) if makefile: summary.Add(makefile) overall_summary.Add(makefile) # Categorize directories by who is responsible aosp_dirs = [] Loading @@ -745,17 +696,18 @@ def main(): (google_dirs, "GoogleDir"), (partner_dirs, "PartnerDir"),]: for dirname in dirgroup: print_analysis_row(soong, summary, annotations, modules, self.print_analysis_row(summary, modules, dirname, rowclass, summary.directories[dirname]) print_analysis_row(soong, summary, annotations, modules, self.print_analysis_row(summary, modules, "Total", "TotalRow", set(itertools.chain.from_iterable(summary.directories.values()))) print(""" </table> """) module_details = [(count_deps(soong.deps, m, []), -count_deps(soong.reverse_deps, m, []), m) 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] Loading @@ -770,7 +722,7 @@ def main(): altRow = True for module in module_details: analyses = set() for filename in soong.makefiles[module]: for filename in self.soong.makefiles[module]: makefile = summary.makefiles.get(filename) if makefile: for analyzer, analysis in makefile.analyses.items(): Loading @@ -782,17 +734,17 @@ def main(): 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, []))) 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>""") print_analysis_header("summary", "Overall Summary") modules = [module for installed, module in soong.installed.items()] print_analysis_row(soong, overall_summary, annotations, modules, 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(""" Loading Loading @@ -924,16 +876,16 @@ def main(): var ANALYSIS = [ """ % { "codesearch": args.codesearch, "codesearch": self.args.codesearch, }) for entry, mods in annotations.entries: 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 soong.makefiles[m]]), #"modules": json.dumps([m for m in mods if m in filename in self.soong.makefiles[m]]), "modules": json.dumps( [m for m in soong.reverse_makefiles[analysis.filename] if m in mods]), [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]), Loading @@ -943,10 +895,10 @@ def main(): ]; var MODULE_DATA = { """) for module in soong.modules: for module in self.soong.modules: print(" '%(name)s': new Module(%(deps)s)," % { "name": module, "deps": json.dumps(soong.deps[module]), "deps": json.dumps(self.soong.deps[module]), }) print(""" }; Loading @@ -968,6 +920,70 @@ def main(): </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() Loading
tools/mk2bp_catalog.py +613 −597 Original line number Diff line number Diff line Loading @@ -177,16 +177,6 @@ def is_google(dirname): 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: Loading Loading @@ -242,6 +232,18 @@ class SoongData(object): 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. Loading @@ -256,18 +258,6 @@ def count_deps(depsdb, module, seen): 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" Loading @@ -292,21 +282,6 @@ def format_module_link(module): 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> Loading @@ -328,48 +303,6 @@ def print_analysis_header(link, title): 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, Loading @@ -394,14 +327,11 @@ def main(): 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. Loading @@ -409,10 +339,32 @@ def main(): % PRODUCT_OUT, "r", errors="ignore") as csvfile: soong = SoongData(csv.reader(csvfile)) # 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) HtmlProcessor(args=args, soong=soong, all_makefiles=all_makefiles).execute() class HtmlProcessor(object): def __init__(self, args, soong, all_makefiles): self.args = args self.soong = soong self.all_makefiles = all_makefiles self.annotations = Annotations() def execute(self): if self.args.title: page_title = self.args.title else: page_title = "Remaining Android.mk files" # Which modules are installed where modules_by_partition = dict() partitions = set() for installed, module in soong.installed.items(): 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) Loading Loading @@ -709,23 +661,22 @@ def main(): </div> """) annotations = Annotations() overall_summary = Summary() # 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])) [self.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)) makefile = self.all_makefiles.get(filename) if makefile: summary.Add(makefile) overall_summary.Add(makefile) # Categorize directories by who is responsible aosp_dirs = [] Loading @@ -745,17 +696,18 @@ def main(): (google_dirs, "GoogleDir"), (partner_dirs, "PartnerDir"),]: for dirname in dirgroup: print_analysis_row(soong, summary, annotations, modules, self.print_analysis_row(summary, modules, dirname, rowclass, summary.directories[dirname]) print_analysis_row(soong, summary, annotations, modules, self.print_analysis_row(summary, modules, "Total", "TotalRow", set(itertools.chain.from_iterable(summary.directories.values()))) print(""" </table> """) module_details = [(count_deps(soong.deps, m, []), -count_deps(soong.reverse_deps, m, []), m) 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] Loading @@ -770,7 +722,7 @@ def main(): altRow = True for module in module_details: analyses = set() for filename in soong.makefiles[module]: for filename in self.soong.makefiles[module]: makefile = summary.makefiles.get(filename) if makefile: for analyzer, analysis in makefile.analyses.items(): Loading @@ -782,17 +734,17 @@ def main(): 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, []))) 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>""") print_analysis_header("summary", "Overall Summary") modules = [module for installed, module in soong.installed.items()] print_analysis_row(soong, overall_summary, annotations, modules, 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(""" Loading Loading @@ -924,16 +876,16 @@ def main(): var ANALYSIS = [ """ % { "codesearch": args.codesearch, "codesearch": self.args.codesearch, }) for entry, mods in annotations.entries: 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 soong.makefiles[m]]), #"modules": json.dumps([m for m in mods if m in filename in self.soong.makefiles[m]]), "modules": json.dumps( [m for m in soong.reverse_makefiles[analysis.filename] if m in mods]), [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]), Loading @@ -943,10 +895,10 @@ def main(): ]; var MODULE_DATA = { """) for module in soong.modules: for module in self.soong.modules: print(" '%(name)s': new Module(%(deps)s)," % { "name": module, "deps": json.dumps(soong.deps[module]), "deps": json.dumps(self.soong.deps[module]), }) print(""" }; Loading @@ -968,6 +920,70 @@ def main(): </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()