Joe Onorato | cccf2ca | 2022-09-28 22:52:56 -0700 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | |
| 3 | import argparse |
| 4 | import os |
| 5 | import subprocess |
| 6 | import sys |
| 7 | |
| 8 | def 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 | |
| 13 | def 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 | |
| 24 | def 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 | |
| 33 | def 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 | |
| 38 | def 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 | |
| 56 | def 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) |
Joe Onorato | 8e908b2 | 2022-10-24 08:03:20 -0700 | [diff] [blame] | 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) |
Joe Onorato | cccf2ca | 2022-09-28 22:52:56 -0700 | [diff] [blame] | 104 | |
| 105 | |
| 106 | if __name__ == "__main__": |
| 107 | sys.exit(main(sys.argv)) |
| 108 | |
| 109 | |
| 110 | # vim: set ts=2 sw=2 sts=2 expandtab nocindent tw=100: |