• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# Copyright 2022 The Chromium Authors
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5"""Wrapper script to run action remotely through rewrapper with gn.
6
7Also includes Chromium-specific input processors which don't make sense to
8be reclient inbuilt input processors."""
9
10import argparse
11import json
12import os
13import subprocess
14import sys
15from enum import Enum
16
17_THIS_DIR = os.path.realpath(os.path.dirname(__file__))
18_SRC_DIR = os.path.dirname(os.path.dirname(_THIS_DIR))
19_MOJOM_DIR = os.path.join(_SRC_DIR, 'mojo', 'public', 'tools', 'mojom')
20
21
22class CustomProcessor(Enum):
23  mojom_parser = 'mojom_parser'
24
25  def __str__(self):
26    return self.value
27
28
29def _process_build_metadata_json(bm_file, input_roots, output_root, re_outputs,
30                                 processed_inputs):
31  """Recursively find mojom_parser inputs from a build_metadata file."""
32  # Import Mojo-specific dep here so non-Mojo remote actions don't need it.
33  if _MOJOM_DIR not in sys.path:
34    sys.path.insert(0, _MOJOM_DIR)
35  from mojom_parser import RebaseAbsolutePath
36
37  if bm_file in processed_inputs:
38    return
39
40  processed_inputs.add(bm_file)
41
42  bm_dir = os.path.dirname(bm_file)
43
44  with open(bm_file) as f:
45    bm = json.load(f)
46
47  # All sources and corresponding module files are inputs.
48  for s in bm["sources"]:
49    src = os.path.normpath(os.path.join(bm_dir, s))
50    if src not in processed_inputs and os.path.exists(src):
51      processed_inputs.add(src)
52    src_module = os.path.join(
53        output_root,
54        RebaseAbsolutePath(os.path.abspath(src), input_roots) + "-module")
55    if src_module in re_outputs:
56      continue
57    if src_module not in processed_inputs and os.path.exists(src_module):
58      processed_inputs.add(src_module)
59
60  # Recurse into build_metadata deps.
61  for d in bm["deps"]:
62    dep = os.path.normpath(os.path.join(bm_dir, d))
63    _process_build_metadata_json(dep, input_roots, output_root, re_outputs,
64                                 processed_inputs)
65
66
67def _get_mojom_parser_inputs(exec_root, output_files, extra_args):
68  """Get mojom inputs by walking generated build_metadata files.
69
70  This is less complexity and disk I/O compared to parsing mojom files for
71  imports and finding all imports.
72
73  Start from the root build_metadata file passed to mojom_parser's
74  --check-imports flag.
75  """
76  argparser = argparse.ArgumentParser()
77  argparser.add_argument('--check-imports', dest='check_imports', required=True)
78  argparser.add_argument('--output-root', dest='output_root', required=True)
79  argparser.add_argument('--input-root',
80                         default=[],
81                         action='append',
82                         dest='input_root_paths')
83  mojom_parser_args, _ = argparser.parse_known_args(args=extra_args)
84
85  input_roots = list(map(os.path.abspath, mojom_parser_args.input_root_paths))
86  output_root = os.path.abspath(mojom_parser_args.output_root)
87  processed_inputs = set()
88  _process_build_metadata_json(mojom_parser_args.check_imports, input_roots,
89                               output_root, output_files, processed_inputs)
90
91  # Rebase paths onto rewrapper exec root.
92  return map(lambda dep: os.path.normpath(os.path.relpath(dep, exec_root)),
93             processed_inputs)
94
95
96def main():
97  # Set up argparser with some rewrapper flags.
98  argparser = argparse.ArgumentParser(description='rewrapper executor for gn',
99                                      allow_abbrev=False)
100  argparser.add_argument('--custom_processor',
101                         type=CustomProcessor,
102                         choices=list(CustomProcessor))
103  argparser.add_argument('rewrapper_path')
104  argparser.add_argument('--input_list_paths')
105  argparser.add_argument('--output_list_paths')
106  argparser.add_argument('--exec_root')
107  parsed_args, extra_args = argparser.parse_known_args()
108
109  # This script expects to be calling rewrapper.
110  args = [parsed_args.rewrapper_path]
111
112  # Get the output files list.
113  output_files = set()
114  with open(parsed_args.output_list_paths, 'r') as file:
115    for line in file:
116      output_files.add(line.rstrip('\n'))
117
118  # Scan for and add explicit inputs for rewrapper if necessary.
119  # These should be in a new input list paths file, as using --inputs can fail
120  # if the list is extremely large.
121  if parsed_args.custom_processor == CustomProcessor.mojom_parser:
122    root, ext = os.path.splitext(parsed_args.input_list_paths)
123    extra_inputs = _get_mojom_parser_inputs(parsed_args.exec_root, output_files,
124                                            extra_args)
125    extra_input_list_path = '%s__extra%s' % (root, ext)
126    with open(extra_input_list_path, 'w') as file:
127      with open(parsed_args.input_list_paths, 'r') as inputs:
128        file.write(inputs.read())
129      file.write("\n".join(extra_inputs))
130    args += ["--input_list_paths=%s" % extra_input_list_path]
131  else:
132    args += ["--input_list_paths=%s" % parsed_args.input_list_paths]
133
134  # Filter out --custom_processor= which is a flag for this script,
135  # and filter out --input_list_paths= because we replace it above.
136  # Pass on the rest of the args to rewrapper.
137  args_rest = filter(lambda arg: '--custom_processor=' not in arg, sys.argv[2:])
138  args += filter(lambda arg: '--input_list_paths=' not in arg, args_rest)
139
140  # Run rewrapper.
141  proc = subprocess.run(args)
142  return proc.returncode
143
144
145if __name__ == '__main__':
146  sys.exit(main())
147