xref: /aosp_15_r20/external/libchrome/build/print_python_deps.py (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
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