• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2
3import argparse
4import os
5import subprocess
6import sys
7
8def get_build_var(var):
9  return subprocess.run(["build/soong/soong_ui.bash","--dumpvar-mode", var],
10                        check=True, capture_output=True, text=True).stdout.strip()
11
12
13def get_sources(modules):
14  result = subprocess.run(["./prebuilts/build-tools/linux-x86/bin/ninja", "-f",
15                           "out/combined-" + os.environ["TARGET_PRODUCT"] + ".ninja",
16                           "-t", "inputs", "-d", ] + modules,
17                          stderr=subprocess.STDOUT, stdout=subprocess.PIPE, check=False, text=True)
18  if result.returncode != 0:
19    sys.stderr.write(result.stdout)
20    sys.exit(1)
21  return set([f for f in result.stdout.split("\n") if not f.startswith("out/")])
22
23
24def m_nothing():
25  result = subprocess.run(["build/soong/soong_ui.bash", "--build-mode", "--all-modules",
26                           "--dir=" + os.getcwd(), "nothing"],
27                           check=False, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, text=True)
28  if result.returncode != 0:
29    sys.stderr.write(result.stdout)
30    sys.exit(1)
31
32
33def get_git_dirs():
34  text = subprocess.run(["repo","list"], check=True, capture_output=True, text=True).stdout
35  return [line.split(" : ")[0] + "/" for line in text.split("\n")]
36
37
38def get_referenced_projects(git_dirs, files):
39  # files must be sorted
40  referenced_dirs = set()
41  prev_dir = None
42  for f in files:
43    # Optimization is ~5x speedup for large sets of files
44    if prev_dir:
45      if f.startswith(prev_dir):
46        referenced_dirs.add(d)
47        continue
48    for d in git_dirs:
49      if f.startswith(d):
50        referenced_dirs.add(d)
51        prev_dir = d
52        break
53  return [d[0:-1] for d in referenced_dirs]
54
55
56def main(argv):
57  # Argument parsing
58  ap = argparse.ArgumentParser(description="List the required git projects for the given modules")
59  ap.add_argument("--products", nargs="*",
60                  help="The TARGET_PRODUCT to check. If not provided just uses whatever has"
61                        + " already been built")
62  ap.add_argument("--variants", nargs="*",
63                  help="The TARGET_BUILD_VARIANTS to check. If not provided just uses whatever has"
64                        + " already been built, or eng if --products is supplied")
65  ap.add_argument("--modules", nargs="*",
66                  help="The build modules to check, or droid it not supplied")
67  ap.add_argument("--why", nargs="*",
68                  help="Also print the input files used in these projects, or \"*\" for all")
69  args = ap.parse_args(argv[1:])
70
71  modules = args.modules if args.modules else ["droid"]
72
73  # Get the list of sources for all of the requested build combos
74  if not args.products and not args.variants:
75    sources = get_sources(modules)
76  else:
77    if not args.products:
78      sys.stderr.write("Error: --products must be supplied if --variants is supplied")
79      sys.exit(1)
80    sources = set()
81    build_num = 1
82    for product in args.products:
83      os.environ["TARGET_PRODUCT"] = product
84      variants = args.variants if args.variants else ["user", "userdebug", "eng"]
85      for variant in variants:
86        sys.stderr.write(f"Analyzing build {build_num} of {len(args.products)*len(variants)}\r")
87        os.environ["TARGET_BUILD_VARIANT"] = variant
88        m_nothing()
89        sources.update(get_sources(modules))
90        build_num += 1
91    sys.stderr.write("\n\n")
92
93  sources = sorted(sources)
94
95  # Print the list of git directories that has one or more of the sources in it
96  for project in sorted(get_referenced_projects(get_git_dirs(), sources)):
97    print(project)
98    if args.why:
99      if "*" in args.why or project in args.why:
100        prefix = project + "/"
101        for f in sources:
102          if f.startswith(prefix):
103            print("  " + f)
104
105
106if __name__ == "__main__":
107  sys.exit(main(sys.argv))
108
109
110# vim: set ts=2 sw=2 sts=2 expandtab nocindent tw=100:
111