1#!/usr/bin/env python3 2 3import argparse 4import itertools 5import os 6import posixpath 7import re 8 9try: 10 import cPickle as pickle # Python 2 11except ImportError: 12 import pickle # Python 3 13 14import ninja 15 16 17def _parse_args(): 18 parser = argparse.ArgumentParser() 19 20 # Ninja input file options 21 parser.add_argument('input_file', help='input ninja file') 22 parser.add_argument('--ninja-deps', help='.ninja_deps file') 23 parser.add_argument('--cwd', help='working directory for ninja') 24 parser.add_argument('--encoding', default='utf-8', 25 help='ninja file encoding') 26 27 # Options 28 parser.add_argument( 29 '--out-dir', default='out', help='path to output directory') 30 parser.add_argument( 31 '--installed-filter', default='system', 32 help='path filter for installed files (w.r.t. device root)') 33 parser.add_argument( 34 '--source-filter', default='vendor:device', 35 help='path filter for source files (w.r.t. source root)') 36 37 return parser.parse_args() 38 39 40def main(): 41 args = _parse_args() 42 43 out_dir = posixpath.normpath(args.out_dir) 44 45 out_pattern = re.compile(re.escape(out_dir) + '/') 46 47 installed_dirs = '|'.join('(?:' + re.escape(posixpath.normpath(path)) + ')' 48 for path in args.installed_filter.split(':')) 49 50 installed_filter = re.compile( 51 re.escape(out_dir) + '/target/product/[^/]+/' + 52 '(?:' + installed_dirs + ')') 53 54 source_filter = re.compile( 55 '|'.join('(?:' + re.escape(posixpath.normpath(path)) + ')' 56 for path in args.source_filter.split(':'))) 57 58 manifest = ninja.load_manifest_from_args(args) 59 60 # Build lookup map 61 outs = {} 62 for build in manifest.builds: 63 for path in build.explicit_outs: 64 outs[path] = build 65 for path in build.implicit_outs: 66 outs[path] = build 67 68 # Compute transitive input files 69 outs_from_vendor_cache = {} 70 71 def _are_inputs_from_vendor(build): 72 # Check whether the input files are matched by source_filter first. 73 gen_paths = [] 74 paths = itertools.chain( 75 build.explicit_ins, build.implicit_ins, build.depfile_implicit_ins) 76 for path in paths: 77 if source_filter.match(path): 78 return True 79 if out_pattern.match(path): 80 gen_paths.append(path) 81 82 # Check whether the input files transitively depend on source_filter. 83 for path in gen_paths: 84 if is_from_vendor(path): 85 return True 86 87 return False 88 89 def is_from_vendor(out_path): 90 matched = outs_from_vendor_cache.get(out_path, None) 91 if matched is not None: 92 return matched 93 94 build = outs.get(out_path) 95 if build: 96 matched = _are_inputs_from_vendor(build) 97 else: 98 matched = bool(source_filter.match(path)) 99 outs_from_vendor_cache[out_path] = matched 100 return matched 101 102 matched_paths = [ 103 path for path in outs 104 if installed_filter.match(path) and is_from_vendor(path)] 105 106 matched_paths.sort() 107 108 for path in matched_paths: 109 print(path) 110 111 112if __name__ == '__main__': 113 main() 114