| #!/usr/bin/env python3 |
| # Copyright 2022 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| """Wrapper script to run action remotely through rewrapper with gn. |
| |
| Also includes Chromium-specific input processors which don't make sense to |
| be reclient inbuilt input processors.""" |
| |
| import argparse |
| import json |
| import os |
| import subprocess |
| import sys |
| from enum import Enum |
| |
| _THIS_DIR = os.path.realpath(os.path.dirname(__file__)) |
| _SRC_DIR = os.path.dirname(os.path.dirname(_THIS_DIR)) |
| _MOJOM_DIR = os.path.join(_SRC_DIR, 'mojo', 'public', 'tools', 'mojom') |
| |
| |
| class CustomProcessor(Enum): |
| mojom_parser = 'mojom_parser' |
| |
| def __str__(self): |
| return self.value |
| |
| |
| def _process_build_metadata_json(bm_file, input_roots, output_root, re_outputs, |
| processed_inputs): |
| """Recursively find mojom_parser inputs from a build_metadata file.""" |
| # Import Mojo-specific dep here so non-Mojo remote actions don't need it. |
| if _MOJOM_DIR not in sys.path: |
| sys.path.insert(0, _MOJOM_DIR) |
| from mojom_parser import RebaseAbsolutePath |
| |
| if bm_file in processed_inputs: |
| return |
| |
| processed_inputs.add(bm_file) |
| |
| bm_dir = os.path.dirname(bm_file) |
| |
| with open(bm_file) as f: |
| bm = json.load(f) |
| |
| # All sources and corresponding module files are inputs. |
| for s in bm["sources"]: |
| src = os.path.normpath(os.path.join(bm_dir, s)) |
| if src not in processed_inputs and os.path.exists(src): |
| processed_inputs.add(src) |
| src_module = os.path.join( |
| output_root, |
| RebaseAbsolutePath(os.path.abspath(src), input_roots) + "-module") |
| if src_module in re_outputs: |
| continue |
| if src_module not in processed_inputs and os.path.exists(src_module): |
| processed_inputs.add(src_module) |
| |
| # Recurse into build_metadata deps. |
| for d in bm["deps"]: |
| dep = os.path.normpath(os.path.join(bm_dir, d)) |
| _process_build_metadata_json(dep, input_roots, output_root, re_outputs, |
| processed_inputs) |
| |
| |
| def _get_mojom_parser_inputs(exec_root, output_files, extra_args): |
| """Get mojom inputs by walking generated build_metadata files. |
| |
| This is less complexity and disk I/O compared to parsing mojom files for |
| imports and finding all imports. |
| |
| Start from the root build_metadata file passed to mojom_parser's |
| --check-imports flag. |
| """ |
| argparser = argparse.ArgumentParser() |
| argparser.add_argument('--check-imports', dest='check_imports', required=True) |
| argparser.add_argument('--output-root', dest='output_root', required=True) |
| argparser.add_argument('--input-root', |
| default=[], |
| action='append', |
| dest='input_root_paths') |
| mojom_parser_args, _ = argparser.parse_known_args(args=extra_args) |
| |
| input_roots = list(map(os.path.abspath, mojom_parser_args.input_root_paths)) |
| output_root = os.path.abspath(mojom_parser_args.output_root) |
| processed_inputs = set() |
| _process_build_metadata_json(mojom_parser_args.check_imports, input_roots, |
| output_root, output_files, processed_inputs) |
| |
| # Rebase paths onto rewrapper exec root. |
| return map(lambda dep: os.path.normpath(os.path.relpath(dep, exec_root)), |
| processed_inputs) |
| |
| |
| def main(): |
| # Set up argparser with some rewrapper flags. |
| argparser = argparse.ArgumentParser(description='rewrapper executor for gn', |
| allow_abbrev=False) |
| argparser.add_argument('--custom_processor', |
| type=CustomProcessor, |
| choices=list(CustomProcessor)) |
| argparser.add_argument('rewrapper_path') |
| argparser.add_argument('--input_list_paths') |
| argparser.add_argument('--output_list_paths') |
| argparser.add_argument('--exec_root') |
| parsed_args, extra_args = argparser.parse_known_args() |
| |
| # This script expects to be calling rewrapper. |
| args = [parsed_args.rewrapper_path] |
| |
| # Get the output files list. |
| output_files = set() |
| with open(parsed_args.output_list_paths, 'r') as file: |
| for line in file: |
| output_files.add(line.rstrip('\n')) |
| |
| # Scan for and add explicit inputs for rewrapper if necessary. |
| # These should be in a new input list paths file, as using --inputs can fail |
| # if the list is extremely large. |
| if parsed_args.custom_processor == CustomProcessor.mojom_parser: |
| root, ext = os.path.splitext(parsed_args.input_list_paths) |
| extra_inputs = _get_mojom_parser_inputs(parsed_args.exec_root, output_files, |
| extra_args) |
| extra_input_list_path = '%s__extra%s' % (root, ext) |
| with open(extra_input_list_path, 'w') as file: |
| with open(parsed_args.input_list_paths, 'r') as inputs: |
| file.write(inputs.read()) |
| file.write("\n".join(extra_inputs)) |
| args += ["--input_list_paths=%s" % extra_input_list_path] |
| else: |
| args += ["--input_list_paths=%s" % parsed_args.input_list_paths] |
| |
| # Filter out --custom_processor= which is a flag for this script, |
| # and filter out --input_list_paths= because we replace it above. |
| # Pass on the rest of the args to rewrapper. |
| args_rest = filter(lambda arg: '--custom_processor=' not in arg, sys.argv[2:]) |
| args += filter(lambda arg: '--input_list_paths=' not in arg, args_rest) |
| |
| # Run rewrapper. |
| proc = subprocess.run(args) |
| return proc.returncode |
| |
| |
| if __name__ == '__main__': |
| sys.exit(main()) |