diff options
| -rwxr-xr-x | tools/whichgit | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/tools/whichgit b/tools/whichgit new file mode 100755 index 0000000000..24d6d87d36 --- /dev/null +++ b/tools/whichgit @@ -0,0 +1,109 @@ +#!/usr/bin/env python3 + +import argparse +import os +import subprocess +import sys + +def get_build_var(var): + return subprocess.run(["build/soong/soong_ui.bash","--dumpvar-mode", var], + check=True, capture_output=True, text=True).stdout.strip() + + +def get_sources(modules): + result = subprocess.run(["./prebuilts/build-tools/linux-x86/bin/ninja", "-f", + "out/combined-" + os.environ["TARGET_PRODUCT"] + ".ninja", + "-t", "inputs", "-d", ] + modules, + stderr=subprocess.STDOUT, stdout=subprocess.PIPE, check=False, text=True) + if result.returncode != 0: + sys.stderr.write(result.stdout) + sys.exit(1) + return set([f for f in result.stdout.split("\n") if not f.startswith("out/")]) + + +def m_nothing(): + result = subprocess.run(["build/soong/soong_ui.bash", "--build-mode", "--all-modules", + "--dir=" + os.getcwd(), "nothing"], + check=False, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, text=True) + if result.returncode != 0: + sys.stderr.write(result.stdout) + sys.exit(1) + + +def get_git_dirs(): + text = subprocess.run(["repo","list"], check=True, capture_output=True, text=True).stdout + return [line.split(" : ")[0] + "/" for line in text.split("\n")] + + +def get_referenced_projects(git_dirs, files): + # files must be sorted + referenced_dirs = set() + prev_dir = None + for f in files: + # Optimization is ~5x speedup for large sets of files + if prev_dir: + if f.startswith(prev_dir): + referenced_dirs.add(d) + continue + for d in git_dirs: + if f.startswith(d): + referenced_dirs.add(d) + prev_dir = d + break + return [d[0:-1] for d in referenced_dirs] + + +def main(argv): + # Argument parsing + ap = argparse.ArgumentParser(description="List the required git projects for the given modules") + ap.add_argument("--products", nargs="*", + help="The TARGET_PRODUCT to check. If not provided just uses whatever has" + + " already been built") + ap.add_argument("--variants", nargs="*", + help="The TARGET_BUILD_VARIANTS to check. If not provided just uses whatever has" + + " already been built, or eng if --products is supplied") + ap.add_argument("--modules", nargs="*", + help="The build modules to check, or droid it not supplied") + ap.add_argument("--why", nargs="*", + help="Also print the input files used in these projects, or \"*\" for all") + args = ap.parse_args(argv[1:]) + + modules = args.modules if args.modules else ["droid"] + + # Get the list of sources for all of the requested build combos + if not args.products and not args.variants: + sources = get_sources(modules) + else: + if not args.products: + sys.stderr.write("Error: --products must be supplied if --variants is supplied") + sys.exit(1) + sources = set() + build_num = 1 + for product in args.products: + os.environ["TARGET_PRODUCT"] = product + variants = args.variants if args.variants else ["user", "userdebug", "eng"] + for variant in variants: + sys.stderr.write(f"Analyzing build {build_num} of {len(args.products)*len(variants)}\r") + os.environ["TARGET_BUILD_VARIANT"] = variant + m_nothing() + sources.update(get_sources(modules)) + build_num += 1 + sys.stderr.write("\n\n") + + sources = sorted(sources) + + # Print the list of git directories that has one or more of the sources in it + for project in sorted(get_referenced_projects(get_git_dirs(), sources)): + print(project) + if "*" in args.why or project in args.why: + prefix = project + "/" + for f in sources: + if f.startswith(prefix): + print(" " + f) + + +if __name__ == "__main__": + sys.exit(main(sys.argv)) + + +# vim: set ts=2 sw=2 sts=2 expandtab nocindent tw=100: |