summaryrefslogtreecommitdiff
path: root/build/util/action_remote.py
blob: 1e9517ddfd0d3ab440261b1db52a8a7a1d510cbc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#!/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


class CustomProcessor(Enum):
  mojom_parser = 'mojom_parser'

  def __str__(self):
    return self.value


def _process_build_metadata_json(bm_file, exec_root, working_dir, output_root,
                                 re_outputs, processed_inputs):
  """Recursively find mojom_parser inputs from a build_metadata file."""
  if bm_file in processed_inputs:
    return

  processed_inputs.add(bm_file)

  bm_dir = os.path.dirname(bm_file)
  wd_rel = os.path.relpath(working_dir, exec_root)

  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.normpath(
        os.path.join(output_root, os.path.join(wd_rel, src + "-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, exec_root, working_dir, 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)
  mojom_parser_args, _ = argparser.parse_known_args(args=extra_args)

  processed_inputs = set()
  _process_build_metadata_json(mojom_parser_args.check_imports, exec_root,
                               os.getcwd(), mojom_parser_args.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())