1*635a8641SAndroid Build Coastguard Worker#!/usr/bin/env vpython 2*635a8641SAndroid Build Coastguard Worker# Copyright 2016 The Chromium Authors. All rights reserved. 3*635a8641SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*635a8641SAndroid Build Coastguard Worker# found in the LICENSE file. 5*635a8641SAndroid Build Coastguard Worker 6*635a8641SAndroid Build Coastguard Worker"""Prints all non-system dependencies for the given module. 7*635a8641SAndroid Build Coastguard Worker 8*635a8641SAndroid Build Coastguard WorkerThe primary use-case for this script is to genererate the list of python modules 9*635a8641SAndroid Build Coastguard Workerrequired for .isolate files. 10*635a8641SAndroid Build Coastguard Worker""" 11*635a8641SAndroid Build Coastguard Worker 12*635a8641SAndroid Build Coastguard Workerimport argparse 13*635a8641SAndroid Build Coastguard Workerimport imp 14*635a8641SAndroid Build Coastguard Workerimport os 15*635a8641SAndroid Build Coastguard Workerimport pipes 16*635a8641SAndroid Build Coastguard Workerimport sys 17*635a8641SAndroid Build Coastguard Worker 18*635a8641SAndroid Build Coastguard Worker# Don't use any helper modules, or else they will end up in the results. 19*635a8641SAndroid Build Coastguard Worker 20*635a8641SAndroid Build Coastguard Worker 21*635a8641SAndroid Build Coastguard Worker_SRC_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) 22*635a8641SAndroid Build Coastguard Worker 23*635a8641SAndroid Build Coastguard Worker 24*635a8641SAndroid Build Coastguard Workerdef _ComputePythonDependencies(): 25*635a8641SAndroid Build Coastguard Worker """Gets the paths of imported non-system python modules. 26*635a8641SAndroid Build Coastguard Worker 27*635a8641SAndroid Build Coastguard Worker A path is assumed to be a "system" import if it is outside of chromium's 28*635a8641SAndroid Build Coastguard Worker src/. The paths will be relative to the current directory. 29*635a8641SAndroid Build Coastguard Worker """ 30*635a8641SAndroid Build Coastguard Worker module_paths = (m.__file__ for m in sys.modules.values() 31*635a8641SAndroid Build Coastguard Worker if m and hasattr(m, '__file__')) 32*635a8641SAndroid Build Coastguard Worker 33*635a8641SAndroid Build Coastguard Worker src_paths = set() 34*635a8641SAndroid Build Coastguard Worker for path in module_paths: 35*635a8641SAndroid Build Coastguard Worker if path == __file__: 36*635a8641SAndroid Build Coastguard Worker continue 37*635a8641SAndroid Build Coastguard Worker path = os.path.abspath(path) 38*635a8641SAndroid Build Coastguard Worker if not path.startswith(_SRC_ROOT): 39*635a8641SAndroid Build Coastguard Worker continue 40*635a8641SAndroid Build Coastguard Worker 41*635a8641SAndroid Build Coastguard Worker if (path.endswith('.pyc') 42*635a8641SAndroid Build Coastguard Worker or (path.endswith('c') and not os.path.splitext(path)[1])): 43*635a8641SAndroid Build Coastguard Worker path = path[:-1] 44*635a8641SAndroid Build Coastguard Worker src_paths.add(path) 45*635a8641SAndroid Build Coastguard Worker 46*635a8641SAndroid Build Coastguard Worker return src_paths 47*635a8641SAndroid Build Coastguard Worker 48*635a8641SAndroid Build Coastguard Worker 49*635a8641SAndroid Build Coastguard Workerdef _NormalizeCommandLine(options): 50*635a8641SAndroid Build Coastguard Worker """Returns a string that when run from SRC_ROOT replicates the command.""" 51*635a8641SAndroid Build Coastguard Worker args = ['build/print_python_deps.py'] 52*635a8641SAndroid Build Coastguard Worker root = os.path.relpath(options.root, _SRC_ROOT) 53*635a8641SAndroid Build Coastguard Worker if root != '.': 54*635a8641SAndroid Build Coastguard Worker args.extend(('--root', root)) 55*635a8641SAndroid Build Coastguard Worker if options.output: 56*635a8641SAndroid Build Coastguard Worker args.extend(('--output', os.path.relpath(options.output, _SRC_ROOT))) 57*635a8641SAndroid Build Coastguard Worker for whitelist in sorted(options.whitelists): 58*635a8641SAndroid Build Coastguard Worker args.extend(('--whitelist', os.path.relpath(whitelist, _SRC_ROOT))) 59*635a8641SAndroid Build Coastguard Worker args.append(os.path.relpath(options.module, _SRC_ROOT)) 60*635a8641SAndroid Build Coastguard Worker return ' '.join(pipes.quote(x) for x in args) 61*635a8641SAndroid Build Coastguard Worker 62*635a8641SAndroid Build Coastguard Worker 63*635a8641SAndroid Build Coastguard Workerdef _FindPythonInDirectory(directory): 64*635a8641SAndroid Build Coastguard Worker """Returns an iterable of all non-test python files in the given directory.""" 65*635a8641SAndroid Build Coastguard Worker files = [] 66*635a8641SAndroid Build Coastguard Worker for root, _dirnames, filenames in os.walk(directory): 67*635a8641SAndroid Build Coastguard Worker for filename in filenames: 68*635a8641SAndroid Build Coastguard Worker if filename.endswith('.py') and not filename.endswith('_test.py'): 69*635a8641SAndroid Build Coastguard Worker yield os.path.join(root, filename) 70*635a8641SAndroid Build Coastguard Worker 71*635a8641SAndroid Build Coastguard Worker 72*635a8641SAndroid Build Coastguard Workerdef main(): 73*635a8641SAndroid Build Coastguard Worker parser = argparse.ArgumentParser( 74*635a8641SAndroid Build Coastguard Worker description='Prints all non-system dependencies for the given module.') 75*635a8641SAndroid Build Coastguard Worker parser.add_argument('module', 76*635a8641SAndroid Build Coastguard Worker help='The python module to analyze.') 77*635a8641SAndroid Build Coastguard Worker parser.add_argument('--root', default='.', 78*635a8641SAndroid Build Coastguard Worker help='Directory to make paths relative to.') 79*635a8641SAndroid Build Coastguard Worker parser.add_argument('--output', 80*635a8641SAndroid Build Coastguard Worker help='Write output to a file rather than stdout.') 81*635a8641SAndroid Build Coastguard Worker parser.add_argument('--no-header', action='store_true', 82*635a8641SAndroid Build Coastguard Worker help='Do not write the "# Generated by" header.') 83*635a8641SAndroid Build Coastguard Worker parser.add_argument('--gn-paths', action='store_true', 84*635a8641SAndroid Build Coastguard Worker help='Write paths as //foo/bar/baz.py') 85*635a8641SAndroid Build Coastguard Worker parser.add_argument('--whitelist', default=[], action='append', 86*635a8641SAndroid Build Coastguard Worker dest='whitelists', 87*635a8641SAndroid Build Coastguard Worker help='Recursively include all non-test python files ' 88*635a8641SAndroid Build Coastguard Worker 'within this directory. May be specified multiple times.') 89*635a8641SAndroid Build Coastguard Worker options = parser.parse_args() 90*635a8641SAndroid Build Coastguard Worker # Replace the path entry for print_python_deps.py with the one for the given 91*635a8641SAndroid Build Coastguard Worker # module. 92*635a8641SAndroid Build Coastguard Worker sys.path[0] = os.path.dirname(options.module) 93*635a8641SAndroid Build Coastguard Worker imp.load_source('NAME', options.module) 94*635a8641SAndroid Build Coastguard Worker 95*635a8641SAndroid Build Coastguard Worker paths_set = _ComputePythonDependencies() 96*635a8641SAndroid Build Coastguard Worker for path in options.whitelists: 97*635a8641SAndroid Build Coastguard Worker paths_set.update(os.path.abspath(p) for p in _FindPythonInDirectory(path)) 98*635a8641SAndroid Build Coastguard Worker 99*635a8641SAndroid Build Coastguard Worker paths = [os.path.relpath(p, options.root) for p in paths_set] 100*635a8641SAndroid Build Coastguard Worker 101*635a8641SAndroid Build Coastguard Worker normalized_cmdline = _NormalizeCommandLine(options) 102*635a8641SAndroid Build Coastguard Worker out = open(options.output, 'w') if options.output else sys.stdout 103*635a8641SAndroid Build Coastguard Worker with out: 104*635a8641SAndroid Build Coastguard Worker if not options.no_header: 105*635a8641SAndroid Build Coastguard Worker out.write('# Generated by running:\n') 106*635a8641SAndroid Build Coastguard Worker out.write('# %s\n' % normalized_cmdline) 107*635a8641SAndroid Build Coastguard Worker prefix = '//' if options.gn_paths else '' 108*635a8641SAndroid Build Coastguard Worker for path in sorted(paths): 109*635a8641SAndroid Build Coastguard Worker out.write(prefix + path + '\n') 110*635a8641SAndroid Build Coastguard Worker 111*635a8641SAndroid Build Coastguard Worker 112*635a8641SAndroid Build Coastguard Workerif __name__ == '__main__': 113*635a8641SAndroid Build Coastguard Worker sys.exit(main()) 114