Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8ade9b2e authored by Joe Onorato's avatar Joe Onorato
Browse files

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
parent 934bd8dc
Loading
Loading
Loading
Loading
+613 −597
Original line number Diff line number Diff line
@@ -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:
@@ -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.

@@ -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"

@@ -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>
@@ -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,
@@ -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.
@@ -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)
@@ -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 = []
@@ -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]
@@ -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():
@@ -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("""
@@ -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]),
@@ -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("""
      };
@@ -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()