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