Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
rewrapper_dart.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2# Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
3# for details. All rights reserved. Use of this source code is governed by a
4# BSD-style license that can be found in the LICENSE file.
5
6# This program executes Dart programs on RBE using rewrapper by parsing the
7# source code to locate the input files, and recognizes the command line options
8# of well known programs to determine the output files.
9
10# New executions during the Dart SDK build needs to be supported here in order
11# to speed up the build with RBE. See the argument parser below.
12
13import json
14import os
15import re
16import subprocess
17import sys
18
19
20# Run a command, swallowing the output unless there is an error.
21def run_command(command, strategy):
22 try:
23 subprocess.check_output(command, stderr=subprocess.STDOUT)
24 return 0
25 except subprocess.CalledProcessError as e:
26 print(e.output.decode("utf-8"))
27 if strategy == 'remote':
28 joined = ' '.join(command)
29 print(f'''Failed to run command remotely: {joined}
30
31If you're seeing this error on a bot and it doesn't happen locally, then you may
32need to teach the script build/rbe/rewrapper_dart.py what the appropriate input
33and outputs files of the command are. You can see the list of used inputs and
34outputs in the rewrapper invocation above. To reproduce this error locally, try
35forcing a remote build by setting the RBE_exec_strategy=remote environment
36variable.
37''')
38 sys.exit(1)
39 except OSError as e:
40 print(e.strerror)
41 sys.exit(1)
42
43
44# Loads the package config file.
45def load_package_config(exec_root):
46 path = os.path.join(exec_root, '.dart_tool', 'package_config.json')
47 with open(path, 'r') as file:
48 return json.load(file)
49
50
51# Resolves a Dart import URI using the package config.
52def resolve_uri(uri, exec_root, package_config, whole_dir=False):
53 if uri.startswith('package:'):
54 match = re.search(r'package:([^/]*)/(.*)', uri)
55 package_name = match.groups()[0]
56 relative = match.groups()[1]
57 package_data = next(pkg for pkg in package_config['packages']
58 if pkg['name'] == package_name)
59 package_root = package_data['rootUri']
60 package_root = package_root[3:] # Remove leading ../
61 package_uri = package_data['packageUri']
62 if whole_dir:
63 uri = package_root + '/' + package_uri
64 else:
65 uri = package_root + '/' + package_uri + relative
66 return uri
67
68
69# Lists the imports of a Dart file uri using the package config and a rough
70# parser that recognizes fairly traditional imports. This is designed to be much
71# faster than actually invoking the front end.
72def list_imports(uri, exec_root, package_config):
73 if uri.startswith('dart:'):
74 return set()
75 path = os.path.join(exec_root, resolve_uri(uri, exec_root, package_config))
76 file = open(path, 'r')
77 imports = set()
78 for line in file.readlines():
79 tokens = [token for token in re.split(r'\s+', line) if token != '']
80 if not tokens or tokens[0] in [
81 '//', '///', '/*', '*/', '#!', 'library', 'show'
82 ]:
83 continue
84 # Imports must happen before definitions.
85 if tokens[0] in ['const', 'class', 'enum']:
86 break
87 if 2 <= len(tokens
88 ) and tokens[0] == 'if' and tokens[1] == '(dart.library.io)':
89 tokens = ['import'] + tokens[2:]
90 if tokens[0] not in ['import', 'export', 'part']:
91 continue
92 if len(tokens) < 2:
93 raise Exception(f'Bad import statement: {path}: {line}')
94 if tokens[0] == 'part' and tokens[1] == 'of':
95 continue
96 token = tokens[1].replace('"', '').replace("'", '').replace(';', '')
97 if token.startswith('dart:'):
98 continue
99 if not ':' in token:
100 dirname = os.path.dirname(uri)
101 while token.startswith('..'):
102 token = token[3:]
103 dirname = os.path.dirname(dirname)
104 token = dirname + '/' + token
105 imports.add(token)
106 file.close()
107 return imports
108
109
110# Transitively compute the set of dart files needed to execute the specified
111# entry point using the package config.
112def find_inputs(uris, exec_root, package_config):
113 inputs = set(uris)
114 unexplored = set(uris)
115 while unexplored:
116 uri = unexplored.pop()
117 imports = list_imports(uri, exec_root, package_config)
118 for uri in imports:
119 if not uri in inputs:
120 inputs.add(uri)
121 unexplored.add(uri)
122 return inputs
123
124
125# Rewrite absolute paths in an argument to be relative.
126def rewrite_absolute(arg, exec_root, working_directory):
127 # The file:// schema does not work with relative paths as they are parsed as
128 # the authority by the dart Uri class.
129 arg = arg.replace('file:///' + exec_root, '../../')
130 arg = arg.replace('file://' + exec_root, '../../')
131 # Replace the absolute exec root by a relative path to the exec root.
132 arg = arg.replace(exec_root, '../../')
133 # Simplify paths going to the exec root and back into the out directory.
134 # Carefully ensure the whole path isn't optimized away.
135 if arg.endswith(f'../../{working_directory}/'):
136 arg = arg.replace(f'../../{working_directory}/', '.')
137 else:
138 arg = arg.replace(f'../../{working_directory}/', '')
139 return arg
140
141
142# Parse the command line execution to recognize well known programs during the
143# Dart SDK build, so the inputs and output files can be determined, and the
144# command can be offloaded to RBE.
145#
146# RBE needs a command to run, a list of input files, and a list of output files,
147# and it then executes the command remotely and caches the result. Absolute
148# paths must not occur in the command as the remote execution will happen in
149# another directory. However, since we currently rely on absolute paths, we work
150# around the issue and rewrite the absolute paths accordingly until the problem
151# is fixed on our end.
152#
153# This is a parser that handles nested commands executing each other, taking
154# care to know whose options it is currently parsing, and extracting the
155# appropriate information from each argument. Every invoked program and option
156# during the build needs to be supported here, otherwise the remote command may
157# be inaccurate and not have right inputs and outputs. Although maintaining this
158# parser takes some effort, it is being paid back in the builders being sped up
159# massively on cache hits, as well as speeding up any local developers that
160# build code already built by the bots.
161#
162# To add a new program, recognize the entry point and define its parser method.
163# To add a new option, parse the option in the appropriate method and either
164# ignore it or recognize any input and output files. All invoked options needs
165# be allowlisted here know we didn't accidentally misunderstand the invoked
166# command when running it remotely.
168
169 def __init__(self, argv):
170 self.dart_subdir = None
171 self.depfiles = None
172 self.entry_points = set()
173 self.exec_root = None
174 self.exec_strategy = 'remote'
176 self.extra_paths = set()
177 self.outputs = []
178 self.no_remote = None
179 self.argv = argv
180 self.optarg = None
181 self.optind = 0
182 self.parse()
183
184 @property
185 def has_next_arg(self):
186 return self.optind + 1 < len(self.argv)
187
188 def next_arg(self):
189 self.optind += 1
190 return self.argv[self.optind]
191
192 def get_option(self, options):
193 arg = self.argv[self.optind]
194 for option in options:
195 if arg == option:
196 self.optind += 1
197 self.optarg = self.argv[self.optind]
198 return True
199 elif option.startswith('--') and arg.startswith(f'{option}='):
200 self.optarg = arg[len(f'{option}='):]
201 return True
202 elif option[0] == '-' and option[1] != '-' and arg.startswith(
203 option):
204 self.optarg = arg[len(option):]
205 return True
206 return False
207
208 def unsupported(self, state, arg):
209 raise Exception(f'''Unsupported operand in state {state}: {arg}
210
211You need to recognize the argument/option in the build/rbe/rewrapper_dart.py
212script in order to execute this command remotely on RBE. Read the big comments
213in the file explaining what this script is and how it works. Follow this stack
214trace to find the place to insert the appropriate support.
215''')
216
217 def rebase(self, path):
218 if path.startswith('package:'):
219 return path
220 # Handle the use of paths starting with an extra slash.
221 if path.startswith('org-dartlang-kernel-service:///'):
222 path = os.path.join(self.exec_root,
223 path[len('org-dartlang-kernel-service:///'):])
224 if path.startswith('org-dartlang-kernel-service://'):
225 path = os.path.join(self.exec_root,
226 path[len('org-dartlang-kernel-service://'):])
227 # Handle the use of paths starting with an extra slash.
228 if path.startswith('file:////'):
229 path = path[len('file:///'):]
230 elif path.startswith('file://'):
231 path = path[len('file://'):]
232 path = os.path.abspath(path)
233 if not path.startswith(self.exec_root):
234 raise Exception(f"Path isn't inside exec_root: {path}")
235 return path[len(self.exec_root):]
236
237 def parse(self):
238 while self.has_next_arg:
239 arg = self.next_arg()
240 if arg == 'rewrapper' or arg.endswith('/rewrapper'):
241 return self.parse_rewrapper()
242 else:
243 self.unsupported('rewrapper_dart', arg)
244
246 while self.has_next_arg:
247 arg = self.next_arg()
248 if self.get_option(['--cfg']):
249 with open(self.optarg, 'r') as fp:
250 for line in fp.readlines():
251 key, value = fp.split('=')
252 if key == 'exec_root':
253 self.exec_root = value
254 elif key == 'exec_strategy':
255 self.exec_strategy = value
256 elif self.get_option(['--exec_root']):
257 self.exec_root = os.path.abspath(self.optarg)
258 if not self.exec_root.endswith('/'):
259 self.exec_root += '/'
260 elif self.get_option(['--exec_strategy']):
261 self.exec_strategy = self.optarg
262 self.exec_strategy_explicit = True
263 elif arg == '--':
264 env_exec_strategy = os.environ.get('RBE_exec_strategy')
265 if env_exec_strategy and not self.exec_strategy_explicit:
266 self.exec_strategy = env_exec_strategy
267 elif arg.startswith('-'):
268 pass # Ignore unknown rewrapper options.
269 elif arg.endswith('/dart'):
270 self.dart_subdir = os.path.dirname(arg)
271 return self.parse_dart()
272 elif arg.endswith('/gen_snapshot') or arg.endswith(
273 '/gen_snapshot_product'):
274 return self.parse_gen_snapshot()
275 else:
276 self.unsupported('rewrapper', arg)
277
278 def parse_dart(self):
279 while self.has_next_arg:
280 arg = self.next_arg()
281 if self.get_option(['--dfe']):
282 self.extra_paths.add(self.rebase(self.optarg))
283 elif self.get_option(['--snapshot']):
284 self.outputs.append(self.rebase(self.optarg))
285 elif self.get_option(['--depfile']):
286 self.depfiles = [self.rebase(self.optarg)]
287 elif self.get_option(['--snapshot-depfile']):
288 self.depfiles = [self.rebase(self.optarg)]
289 elif self.get_option([
290 '--packages', '-D', '--snapshot-kind',
291 '--depfile_output_filename'
292 ]):
293 pass
294 elif arg in ['--deterministic', '--sound-null-safety']:
295 pass
296 elif arg == 'compile':
297 self.extra_paths.add(
298 self.rebase(
299 os.path.join(self.dart_subdir,
300 'snapshots/dartdev.dart.snapshot')))
301 self.extra_paths.add(
302 self.rebase(os.path.join(self.dart_subdir, '../lib')))
303 return self.parse_compile()
304 elif arg == '../../pkg/compiler/lib/src/dart2js.dart':
305 self.entry_points.add(self.rebase(arg))
306 return self.parse_dart2js()
307 elif arg == 'gen/utils/compiler/dart2js.dart.dill':
308 self.extra_paths.add(self.rebase(arg))
309 return self.parse_dart2js()
310 elif arg == '../../pkg/dev_compiler/bin/dartdevc.dart':
311 self.entry_points.add(self.rebase(arg))
312 return self.parse_dartdevc()
313 elif arg == 'gen/utils/ddc/dartdevc.dart.dill':
314 self.extra_paths.add(self.rebase(arg))
315 return self.parse_dartdevc()
316 elif arg == 'gen/utils/dartanalyzer/dartanalyzer.dart.dill':
317 self.extra_paths.add(self.rebase(arg))
318 return self.parse_dartanalyzer()
319 elif arg == 'gen/utils/analysis_server/analysis_server.dart.dill':
320 self.extra_paths.add(self.rebase(arg))
321 return self.parse_analysis_server()
322 elif arg == '../../pkg/front_end/tool/_fasta/compile_platform.dart':
323 self.entry_points.add(self.rebase(arg))
324 return self.parse_compile_platform()
325 elif arg == '../../utils/compiler/create_snapshot_entry.dart':
326 self.entry_points.add(self.rebase(arg))
327 self.extra_paths.add('tools/make_version.py')
328 # This step is very cheap and python3 isn't in the docker image.
329 self.no_remote = True
330 return self.parse_create_snapshot_entry()
331 elif arg == '../../utils/bazel/kernel_worker.dart':
332 self.entry_points.add(self.rebase(arg))
334 elif arg == '../../pkg/vm/bin/gen_kernel.dart':
335 self.entry_points.add(self.rebase(arg))
336 return self.parse_gen_kernel()
337 elif arg == 'gen/utils/kernel-service/frontend_server.dart.dill':
338 self.extra_paths.add(self.rebase(arg))
339 return self.parse_frontend_server()
340 elif arg == 'gen/utils/dtd/generate_dtd_snapshot.dart.dill':
341 self.extra_paths.add(self.rebase(arg))
342 return self.parse_generate_dtd_snapshot()
343 elif arg == 'gen/utils/dds/generate_dds_snapshot.dart.dill':
344 self.extra_paths.add(self.rebase(arg))
345 return self.parse_generate_dds_snapshot()
346 elif arg == 'gen/utils/bazel/kernel_worker.dart.dill':
347 self.extra_paths.add(self.rebase(arg))
349 elif arg == 'gen/utils/dartdev/generate_dartdev_snapshot.dart.dill':
350 self.extra_paths.add(self.rebase(arg))
352 elif arg == 'gen/utils/gen_kernel/bootstrap_gen_kernel.dill':
353 self.extra_paths.add(self.rebase(arg))
354 return self.parse_bootstrap_gen_kernel()
355 elif arg == 'gen/utils/kernel-service/kernel-service_snapshot.dart.dill':
356 self.extra_paths.add(self.rebase(arg))
357 self.extra_paths.add(
358 self.rebase(
359 os.path.join(self.dart_subdir,
360 'vm_platform_strong.dill')))
362 else:
363 self.unsupported('dart', arg)
364
365 def parse_compile(self):
366 while self.has_next_arg:
367 arg = self.next_arg()
368 if arg == 'js':
369 self.extra_paths.add(
370 self.rebase(
371 os.path.join(self.dart_subdir,
372 'snapshots/dart2js.dart.snapshot')))
373 return self.parse_dart2js()
374 else:
375 self.unsupported('compile', arg)
376
377 def parse_dart2js(self):
378 while self.has_next_arg:
379 arg = self.next_arg()
380 if self.get_option(['-o', '--output']):
381 self.outputs.append(self.rebase(self.optarg))
382 self.outputs.append(
383 self.rebase(self.optarg.replace('.js', '.js.map')))
384 elif self.get_option(['--platform-binaries']):
385 self.extra_paths.add(
386 self.rebase(
387 os.path.join(self.optarg, 'dart2js_platform.dill')))
388 elif self.get_option([
389 '--invoker', '--packages', '--libraries-spec',
390 '--snapshot-kind', '--depfile_output_filename'
391 ]):
392 pass
393 elif arg in [
394 '--canary',
395 '--enable-asserts',
396 '-m',
397 '--minify',
398 '--no-source-maps',
399 ]:
400 pass
401 elif not arg.startswith('-'):
402 self.entry_points.add(self.rebase(arg))
403 else:
404 self.unsupported('dart2js', arg)
405
406 def parse_dartdevc(self):
407 while self.has_next_arg:
408 arg = self.next_arg()
409 if self.get_option(['-o', '--output']):
410 self.outputs.append(self.rebase(self.optarg))
411 self.outputs.append(
412 self.rebase(self.optarg.replace('.js', '.js.map')))
413 self.outputs.append(
414 self.rebase(self.optarg.replace('.js', '.dill')))
415 elif self.get_option(['--dart-sdk-summary']):
416 self.extra_paths.add(self.rebase(self.optarg))
417 elif self.get_option([
418 '--multi-root-scheme', '--multi-root-output-path',
419 '--modules'
420 ]):
421 pass
422 elif arg in [
423 '--canary', '--no-summarize', '--sound-null-safety',
424 '--no-sound-null-safety'
425 ]:
426 pass
427 elif not arg.startswith('-'):
428 if arg.endswith('.dart'):
429 self.entry_points.add(self.rebase(arg))
430 else:
431 self.extra_paths.add(self.rebase(arg))
432 else:
433 self.unsupported('dartdevc', arg)
434
436 while self.has_next_arg:
437 arg = self.next_arg()
438 if arg in ['--help']:
439 pass
440 else:
441 self.unsupported('dartanalyzer', arg)
442
444 while self.has_next_arg:
445 arg = self.next_arg()
446 if self.get_option(['--sdk']):
447 self.extra_paths.add(self.rebase(self.optarg))
448 elif self.get_option(['--train-using']):
449 self.extra_paths.add(self.rebase(self.optarg))
450 self.entry_points.add(
451 self.rebase(os.path.join(self.optarg, 'compiler_api.dart')))
452 # This file isn't referenced from compiler_api.dart.
453 self.entry_points.add(
454 self.rebase(
455 os.path.join(self.optarg, 'src/io/mapped_file.dart')))
456 else:
457 self.unsupported('analysis_server', arg)
458
460 compile_platform_args = []
461 single_root_scheme = None
462 single_root_base = None
463 while self.has_next_arg:
464 arg = self.next_arg()
465 if self.get_option(['--single-root-scheme']):
466 single_root_scheme = self.optarg
467 elif self.get_option(['--single-root-base']):
468 single_root_base = self.optarg
469 # Remove trailing slash to avoid duplicate slashes later.
470 if 1 < len(single_root_base) and single_root_base[-1] == '/':
471 single_root_base = single_root_base[:-1]
472 elif self.get_option(['-D', '--target']):
473 pass
474 elif arg in [
475 '--no-defines',
476 '--nnbd-strong',
477 '--nnbd-weak',
478 '--nnbd-agnostic',
479 '--exclude-source',
480 ]:
481 pass
482 elif not arg.startswith('-'):
483 if len(compile_platform_args) == 0:
484 pass # e.g. dart:core
485 elif len(compile_platform_args) == 1:
486 sdk = arg # sdk via libraries.json
487 if sdk.startswith(f'{single_root_scheme}:///'):
488 sdk = sdk[len(f'{single_root_scheme}:///'):]
489 sdk = os.path.join(single_root_base, sdk)
490 if sdk.endswith('libraries.json'):
491 sdk = os.path.dirname(sdk)
492 self.extra_paths.add(self.rebase(sdk))
493 elif len(compile_platform_args) == 2: # vm_outline_strong dill
494 arg = self.rebase(arg)
495 elif len(compile_platform_args) == 3: # platform dill
496 arg = self.rebase(arg)
497 self.outputs.append(arg)
498 elif len(compile_platform_args) == 4: # outline dill
499 arg = self.rebase(arg)
500 self.outputs.append(arg)
501 if arg != compile_platform_args[2]:
502 self.extra_paths.add(compile_platform_args[2])
503 else:
504 self.unsupported('compile_platform', arg)
505 compile_platform_args.append(arg)
506 else:
507 self.unsupported('compile_platform', arg)
508
510 while self.has_next_arg:
511 arg = self.next_arg()
512 if self.get_option(['--output_dir']):
513 self.outputs.append(self.rebase(self.optarg))
514 elif arg in ['--no-git-hash']:
515 pass
516 else:
517 self.unsupported('create_snapshot_entry', arg)
518
520 while self.has_next_arg:
521 arg = self.next_arg()
522 if self.get_option(['-o', '--output']):
523 self.outputs.append(self.rebase(self.optarg))
524 elif self.get_option(['--dart-sdk-summary']):
525 self.extra_paths.add(self.rebase(self.optarg))
526 elif self.get_option(['--source']):
527 self.entry_points.add(self.rebase(self.optarg))
528 elif self.get_option(
529 ['--packages-file', '--target', '--dart-sdk-summary']):
530 pass
531 elif arg in [
532 '--summary-only',
533 '--sound-null-safety',
534 '--no-sound-null-safety',
535 ]:
536 pass
537 else:
538 self.unsupported('kernel_worker', arg)
539
541 while self.has_next_arg:
542 arg = self.next_arg()
543 if self.get_option(['-o', '--output']):
544 self.outputs.append(self.rebase(self.optarg))
545 elif self.get_option(['--platform']):
546 self.extra_paths.add(self.rebase(self.optarg))
547 elif self.get_option([
548 '--packages', '-D', '--filesystem-root',
549 '--filesystem-scheme'
550 ]):
551 pass
552 elif arg in ['--no-aot', '--no-embed-sources']:
553 pass
554 elif not arg.startswith('-'):
555 self.entry_points.add(self.rebase(arg))
556 else:
557 self.unsupported('gen_kernel', arg)
558
560 while self.has_next_arg:
561 arg = self.next_arg()
562 if self.get_option(['-o', '--output']):
563 self.outputs.append(self.rebase(self.optarg))
564 elif self.get_option(['--platform']):
565 self.extra_paths.add(self.rebase(self.optarg))
566 elif self.get_option(['--packages', '-D']):
567 pass
568 elif arg in [
569 '--aot',
570 '--no-aot',
571 '--no-embed-sources',
572 '--no-link-platform',
573 '--enable-asserts',
574 ]:
575 pass
576 elif self.get_option(['--depfile']):
577 self.depfiles = [self.rebase(self.optarg)]
578 elif not arg.startswith('-'):
579 self.entry_points.add(self.rebase(arg))
580 else:
581 self.unsupported('bootstrap_gen_kernel', arg)
582
584 while self.has_next_arg:
585 arg = self.next_arg()
586 if self.get_option(['--train']):
587 self.entry_points.add(self.rebase(self.optarg))
588 else:
589 self.unsupported('kernel_service_snapshot', arg)
590
592 while self.has_next_arg:
593 arg = self.next_arg()
594 if self.get_option(['--platform']):
595 self.extra_paths.add(self.rebase(self.optarg))
596 elif self.get_option(['--sdk-root']):
597 pass
598 elif arg in ['--train']:
599 pass
600 elif not arg.startswith('-'):
601 self.entry_points.add(self.rebase(arg))
602 else:
603 self.unsupported('frontend_server', arg)
604
606 while self.has_next_arg:
607 arg = self.next_arg()
608 if arg in ['--train']:
609 pass
610 else:
611 self.unsupported('generate_dtd_snapshot', arg)
612
614 while self.has_next_arg:
615 arg = self.next_arg()
616 if arg in ['--help']:
617 pass
618 else:
619 self.unsupported('generate_dds_snapshot', arg)
620
622 while self.has_next_arg:
623 arg = self.next_arg()
624 if arg in ['--help']:
625 pass
626 elif self.get_option(['-o', '--output']):
627 self.outputs.append(self.rebase(self.optarg))
628 elif self.get_option(['--packages-file']):
629 self.extra_paths.add(self.rebase(self.optarg))
630 elif self.get_option(['--dart-sdk-summary']):
631 self.extra_paths.add(self.rebase(self.optarg))
632 elif self.get_option(['--source']):
633 self.entry_points.add(self.rebase(self.optarg))
634 elif self.get_option(['--target']):
635 pass
636 elif arg in [
637 '--sound-null-safety', '--no-sound-null-safety',
638 '--summary-only'
639 ]:
640 pass
641 else:
642 self.unsupported('kernel_worker', arg)
643
645 while self.has_next_arg:
646 arg = self.next_arg()
647 if arg in ['--help']:
648 pass
649 else:
650 self.unsupported('generate_dartdev_snapshot', arg)
651
653 while self.has_next_arg:
654 arg = self.next_arg()
655 if self.get_option(['-o', '--output']):
656 self.outputs.append(self.rebase(self.optarg))
657 elif self.get_option([
658 '--vm_snapshot_data',
659 '--vm_snapshot_instructions',
660 '--isolate_snapshot_data',
661 '--isolate_snapshot_instructions',
662 '--elf',
663 ]):
664 self.outputs.append(self.rebase(self.optarg))
665 elif self.get_option(['--snapshot_kind', '--snapshot-kind']):
666 pass
667 elif arg in [
668 '--sound-null-safety',
669 '--deterministic',
670 '--enable-asserts',
671 ]:
672 pass
673 elif not arg.startswith('-'):
674 self.extra_paths.add(self.rebase(arg))
675 else:
676 self.unsupported('gen_snapshot', arg)
677
678
679def main(argv):
680 # Like gn_run_binary, run programs relative to the build directory. The
681 # command is assumed to invoke rewrapper and end its rewrapper arguments
682 # with an -- argument.
683 rewrapper_end = 0
684 for i in range(len(argv)):
685 if argv[i] == '--' and rewrapper_end == 0:
686 rewrapper_end = i + 1
687 if not '/' in argv[i + 1]:
688 argv[i + 1] = './' + argv[i + 1]
689 break
690
691 rewrapper = Rewrapper(argv)
692
693 if rewrapper.exec_root == None:
694 raise Exception('No rewrapper --exec_root was specified')
695
696 if not rewrapper.outputs:
697 raise Exception('No output files were recognized')
698
699 # Run the command directly if it's not supported for remote builds.
700 if rewrapper.no_remote:
701 run_command(argv[rewrapper_end:], 'local')
702 return 0
703
704 # Determine the set of input and output files.
705 package_config = load_package_config(rewrapper.exec_root)
706 if not rewrapper.depfiles:
707 rewrapper.depfiles = [output + '.d' for output in rewrapper.outputs]
708 output_files = rewrapper.outputs + rewrapper.depfiles
709 inputs = find_inputs(rewrapper.entry_points, rewrapper.exec_root,
710 package_config)
711 paths = set(
712 resolve_uri(uri, rewrapper.exec_root, package_config, whole_dir=True)
713 for uri in inputs)
714 paths.add(os.path.join('.dart_tool', 'package_config.json'))
715 for path in rewrapper.extra_paths:
716 paths.add(path)
717 # Ensure the working directory is included if no inputs are inside it.
718 working_directory = rewrapper.rebase('.')
719 if not any([path.startswith(working_directory) for path in paths]):
720 paths.add(rewrapper.rebase('build.ninja.stamp'))
721 paths = list(paths)
722 paths.sort()
723
724 # Construct the final rewrapped command line.
725 command = [argv[1]]
726 command.append('--labels=type=tool')
727 command.append('--inputs=' + ','.join(paths))
728 command.append('--output_files=' + ','.join(output_files))
729 # Absolute paths must not be used with RBE, but since the build currently
730 # heavily relies on them, work around this issue by rewriting the command
731 # to instead use relative paths. The Dart SDK build rules needs to be fixed
732 # rather than doing this, but this is an initial step towards that goal
733 # which will land in subsequent follow up changes.
734 command += argv[2:rewrapper_end] + [
735 rewrite_absolute(arg, rewrapper.exec_root, working_directory)
736 for arg in argv[rewrapper_end:]
737 ]
738
739 # Finally execute the command remotely.
740 run_command(command, rewrapper.exec_strategy)
741
742 # Until the depfiles are fixed so they don't contain absoiute paths, we need
743 # to rewrite the absoute paths appropriately.
744 for depfile in rewrapper.depfiles:
745 lines = []
746 try:
747 with open(os.path.join(rewrapper.exec_root, depfile), 'r') as file:
748 lines = file.readlines()
749 lines = [
750 line.replace('/b/f/w', rewrapper.exec_root) for line in lines
751 ]
752 with open(os.path.join(rewrapper.exec_root, depfile), 'w') as file:
753 file.writelines(lines)
754 except FileNotFoundError:
755 pass
756
757 return 0
758
759
760if __name__ == '__main__':
761 sys.exit(main(sys.argv))
static float next(float f)
void print(void *str)
Definition bridge.cpp:126
unsupported(self, state, arg)
static void append(char **dst, size_t *count, const char *src, size_t n)
Definition editor.cpp:211
Definition main.py:1
load_package_config(exec_root)
list_imports(uri, exec_root, package_config)
run_command(command, strategy)
resolve_uri(uri, exec_root, package_config, whole_dir=False)
rewrite_absolute(arg, exec_root, working_directory)
find_inputs(uris, exec_root, package_config)