#!/usr/bin/env python3 """List all source file of a installed module.""" import argparse import itertools import posixpath import re try: import cPickle as pickle # Python 2 except ImportError: import pickle # Python 3 import ninja def _parse_args(): """Parse the command line arguments.""" parser = argparse.ArgumentParser() # Ninja input file options parser.add_argument('input_file', help='input ninja file') parser.add_argument('--ninja-deps', help='.ninja_deps file') parser.add_argument('--cwd', help='working directory for ninja') parser.add_argument('--encoding', default='utf-8', help='ninja file encoding') # Options parser.add_argument( 'installed_filter', nargs='+', help='path filter for installed files (w.r.t. device root)') parser.add_argument( '--out-dir', default='out', help='path to output directory') return parser.parse_args() def collect_source_files(graph, start, out_dir_pattern, out_host_dir_pattern): """Collect the transitive dependencies of a target.""" source_files = [] # Extract the file name of the target file. We need this file name to # allow the strip/copy build rules while leaving other shared libraries # alone. start_basename = posixpath.basename(start) # Collect all source files visited = {start} stack = [start] while stack: cur = stack.pop() if not out_dir_pattern.match(cur): source_files.append(cur) build = graph.get(cur) if build: for dep in itertools.chain(build.explicit_ins, build.implicit_ins, build.depfile_implicit_ins): # Skip the binaries for build process if dep.startswith('prebuilts/'): continue if out_host_dir_pattern.match(dep): continue # Skip the shared libraries if dep.endswith('.toc'): continue if dep.endswith('.so'): if posixpath.basename(dep) != start_basename: continue if dep not in visited: visited.add(dep) stack.append(dep) return sorted(source_files) def main(): args = _parse_args() out_dir = posixpath.normpath(args.out_dir) out_dir_pattern = re.compile(re.escape(out_dir) + '/') out_host_dir_pattern = re.compile(re.escape(out_dir) + '/host/') out_product_dir = out_dir + '/target/product/[^/]+' def _normalize_path(path): if path.startswith(out_dir + '/target'): return path return posixpath.join(out_product_dir, path) installed_filter = [_normalize_path(path) for path in args.installed_filter] installed_filter = re.compile( '|'.join('(?:' + p + ')' for p in installed_filter)) manifest = ninja.load_manifest_from_args(args) # Build lookup map graph = {} for build in manifest.builds: for path in build.explicit_outs: graph[path] = build for path in build.implicit_outs: graph[path] = build # Collect all matching outputs matched_files = [path for path in graph if installed_filter.match(path)] matched_files.sort() for path in matched_files: source_files = collect_source_files( graph, path, out_dir_pattern, out_host_dir_pattern) print(path) for dep in source_files: print('\t' + dep) print() if __name__ == '__main__': main()