xref: /aosp_15_r20/external/cronet/build/util/ide_query (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*6777b538SAndroid Build Coastguard Worker# Copyright 2024 The Chromium Authors. All rights reserved.
3*6777b538SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be
4*6777b538SAndroid Build Coastguard Worker# found in the LICENSE file.
5*6777b538SAndroid Build Coastguard Worker"""A script gets the information needed by lDE language services.
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard WorkerExpected to run it at repository root,  where top DEP, .gn etc exists.
8*6777b538SAndroid Build Coastguard WorkerNot intended to run by user.
9*6777b538SAndroid Build Coastguard WorkerSee go/reqs-for-peep
10*6777b538SAndroid Build Coastguard Worker"""
11*6777b538SAndroid Build Coastguard Worker
12*6777b538SAndroid Build Coastguard Workerimport argparse
13*6777b538SAndroid Build Coastguard Workerimport os
14*6777b538SAndroid Build Coastguard Workerimport re
15*6777b538SAndroid Build Coastguard Workerimport subprocess
16*6777b538SAndroid Build Coastguard Workerimport sys
17*6777b538SAndroid Build Coastguard Worker
18*6777b538SAndroid Build Coastguard Workerdef _gn_lines(output_dir, path):
19*6777b538SAndroid Build Coastguard Worker    """
20*6777b538SAndroid Build Coastguard Worker    Generator function that returns args.gn lines one at a time, following
21*6777b538SAndroid Build Coastguard Worker    import directives as needed.
22*6777b538SAndroid Build Coastguard Worker    """
23*6777b538SAndroid Build Coastguard Worker    import_re = re.compile(r'\s*import\("(.*)"\)')
24*6777b538SAndroid Build Coastguard Worker    with open(path, encoding="utf-8") as f:
25*6777b538SAndroid Build Coastguard Worker        for line in f:
26*6777b538SAndroid Build Coastguard Worker            match = import_re.match(line)
27*6777b538SAndroid Build Coastguard Worker            if match:
28*6777b538SAndroid Build Coastguard Worker                raw_import_path = match.groups()[0]
29*6777b538SAndroid Build Coastguard Worker                if raw_import_path[:2] == "//":
30*6777b538SAndroid Build Coastguard Worker                    import_path = os.path.normpath(
31*6777b538SAndroid Build Coastguard Worker                        os.path.join(output_dir, "..", "..",
32*6777b538SAndroid Build Coastguard Worker                                     raw_import_path[2:]))
33*6777b538SAndroid Build Coastguard Worker                else:
34*6777b538SAndroid Build Coastguard Worker                    import_path = os.path.normpath(
35*6777b538SAndroid Build Coastguard Worker                        os.path.join(os.path.dirname(path), raw_import_path))
36*6777b538SAndroid Build Coastguard Worker                for import_line in _gn_lines(output_dir, import_path):
37*6777b538SAndroid Build Coastguard Worker                    yield import_line
38*6777b538SAndroid Build Coastguard Worker            else:
39*6777b538SAndroid Build Coastguard Worker                yield line
40*6777b538SAndroid Build Coastguard Worker
41*6777b538SAndroid Build Coastguard Workerdef _use_reclient(outdir):
42*6777b538SAndroid Build Coastguard Worker  args_gn = os.path.join(outdir, 'args.gn')
43*6777b538SAndroid Build Coastguard Worker  if not os.path.exists(args_gn):
44*6777b538SAndroid Build Coastguard Worker    return False
45*6777b538SAndroid Build Coastguard Worker  for line in _gn_lines(outdir, args_gn):
46*6777b538SAndroid Build Coastguard Worker    line_without_comment = line.split('#')[0]
47*6777b538SAndroid Build Coastguard Worker    if re.search(r"(^|\s)(use_remoteexec)\s*=\s*true($|\s)",
48*6777b538SAndroid Build Coastguard Worker                 line_without_comment):
49*6777b538SAndroid Build Coastguard Worker      return True
50*6777b538SAndroid Build Coastguard Worker  return False
51*6777b538SAndroid Build Coastguard Worker
52*6777b538SAndroid Build Coastguard Workerdef main():
53*6777b538SAndroid Build Coastguard Worker  parser = argparse.ArgumentParser()
54*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--source', action='append',
55*6777b538SAndroid Build Coastguard Worker    help=('The source file being analyzed.'
56*6777b538SAndroid Build Coastguard Worker          'Multiple --source arguments can be passed in order to batch '
57*6777b538SAndroid Build Coastguard Worker          'process is desired. '))
58*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--perform-build', action='store_true',
59*6777b538SAndroid Build Coastguard Worker    help=('If specified, actually build the target, including any generated '
60*6777b538SAndroid Build Coastguard Worker          'prerequisite files. '
61*6777b538SAndroid Build Coastguard Worker          'If --perform-build is not passed, the contents of '
62*6777b538SAndroid Build Coastguard Worker          'the GeneratedFile results will only be returned if a build has '
63*6777b538SAndroid Build Coastguard Worker          'been previously completed, and may be stale.'))
64*6777b538SAndroid Build Coastguard Worker  parser.add_argument('--out-dir',
65*6777b538SAndroid Build Coastguard Worker    help=('Output directory, containing  args.gn, which specifies the build '
66*6777b538SAndroid Build Coastguard Worker          'configuration.'))
67*6777b538SAndroid Build Coastguard Worker  options = parser.parse_args()
68*6777b538SAndroid Build Coastguard Worker
69*6777b538SAndroid Build Coastguard Worker  this_dir = os.path.dirname(__file__)
70*6777b538SAndroid Build Coastguard Worker  repo_root = os.path.join(this_dir, '..', '..')
71*6777b538SAndroid Build Coastguard Worker
72*6777b538SAndroid Build Coastguard Worker  targets = []
73*6777b538SAndroid Build Coastguard Worker  for source in options.source:
74*6777b538SAndroid Build Coastguard Worker    # source is repo root (cwd) relative,
75*6777b538SAndroid Build Coastguard Worker    # but siso uses out dir relative target.
76*6777b538SAndroid Build Coastguard Worker    target = os.path.relpath(source, start=options.out_dir) + "^"
77*6777b538SAndroid Build Coastguard Worker    targets.append(target)
78*6777b538SAndroid Build Coastguard Worker
79*6777b538SAndroid Build Coastguard Worker  if options.perform_build:
80*6777b538SAndroid Build Coastguard Worker    if _use_reclient(options.out_dir):
81*6777b538SAndroid Build Coastguard Worker      args = ['autoninja', '-C', options.out_dir]
82*6777b538SAndroid Build Coastguard Worker    else:
83*6777b538SAndroid Build Coastguard Worker      args = ['siso', 'ninja', '-C', options.out_dir]
84*6777b538SAndroid Build Coastguard Worker    args.extend(targets)
85*6777b538SAndroid Build Coastguard Worker    p = subprocess.run(args, cwd=repo_root, capture_output=True)
86*6777b538SAndroid Build Coastguard Worker    if p.returncode != 0:
87*6777b538SAndroid Build Coastguard Worker      # TODO: report error in IdeAnalysis.Status?
88*6777b538SAndroid Build Coastguard Worker      sys.stderr.write('build failed with %d\n%s\n%s' % (
89*6777b538SAndroid Build Coastguard Worker          p.returncode, p.stdout, p.stderr))
90*6777b538SAndroid Build Coastguard Worker      return 1
91*6777b538SAndroid Build Coastguard Worker
92*6777b538SAndroid Build Coastguard Worker  args = ['siso', 'query', 'ideanalysis', '-C', options.out_dir]
93*6777b538SAndroid Build Coastguard Worker  args.extend(targets)
94*6777b538SAndroid Build Coastguard Worker  subprocess.run(args, cwd=repo_root, check=True)
95*6777b538SAndroid Build Coastguard Worker
96*6777b538SAndroid Build Coastguard Workerif __name__ == '__main__':
97*6777b538SAndroid Build Coastguard Worker  sys.exit(main())
98