Flutter Engine
The Flutter Engine
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
173 self.exec_root = None
174 self.exec_strategy = 'remote'
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', '--coverage',
292 '--ignore-unrecognized-flags'
293 ]):
294 pass
295 elif arg in ['--deterministic', '--sound-null-safety']:
296 pass
297 elif arg == 'compile':
298 self.extra_paths.add(
299 self.rebase(
300 os.path.join(self.dart_subdir,
301 'snapshots/dartdev.dart.snapshot')))
302 self.extra_paths.add(
303 self.rebase(os.path.join(self.dart_subdir, '../lib')))
304 return self.parse_compile()
305 elif arg == '../../pkg/compiler/lib/src/dart2js.dart':
306 self.entry_points.add(self.rebase(arg))
307 return self.parse_dart2js()
308 elif arg == 'gen/utils/compiler/dart2js.dart.dill':
309 self.extra_paths.add(self.rebase(arg))
310 return self.parse_dart2js()
311 elif arg == '../../pkg/dev_compiler/bin/dartdevc.dart':
312 self.entry_points.add(self.rebase(arg))
313 return self.parse_dartdevc()
314 elif arg == 'gen/utils/ddc/dartdevc.dart.dill':
315 self.extra_paths.add(self.rebase(arg))
316 return self.parse_dartdevc()
317 elif arg == 'gen/utils/dartanalyzer/dartanalyzer.dart.dill':
318 self.extra_paths.add(self.rebase(arg))
319 return self.parse_dartanalyzer()
320 elif arg == 'gen/utils/analysis_server/analysis_server.dart.dill':
321 self.extra_paths.add(self.rebase(arg))
322 return self.parse_analysis_server()
323 elif arg == '../../pkg/front_end/tool/_fasta/compile_platform.dart':
324 self.entry_points.add(self.rebase(arg))
325 return self.parse_compile_platform()
326 elif arg == '../../utils/compiler/create_snapshot_entry.dart':
327 self.entry_points.add(self.rebase(arg))
328 self.extra_paths.add('tools/make_version.py')
329 # This step is very cheap and python3 isn't in the docker image.
330 self.no_remote = True
331 return self.parse_create_snapshot_entry()
332 elif arg == '../../utils/bazel/kernel_worker.dart':
333 self.entry_points.add(self.rebase(arg))
335 elif arg == '../../pkg/vm/bin/gen_kernel.dart':
336 self.entry_points.add(self.rebase(arg))
337 return self.parse_gen_kernel()
338 elif arg == 'gen/utils/kernel-service/frontend_server.dart.dill':
339 self.extra_paths.add(self.rebase(arg))
340 return self.parse_frontend_server()
341 elif arg == 'gen/utils/dtd/generate_dtd_snapshot.dart.dill':
342 self.extra_paths.add(self.rebase(arg))
343 return self.parse_generate_dtd_snapshot()
344 elif arg == 'gen/utils/dds/generate_dds_snapshot.dart.dill':
345 self.extra_paths.add(self.rebase(arg))
346 return self.parse_generate_dds_snapshot()
347 elif arg == 'gen/utils/bazel/kernel_worker.dart.dill':
348 self.extra_paths.add(self.rebase(arg))
350 elif arg == 'gen/utils/dartdev/generate_dartdev_snapshot.dart.dill':
351 self.extra_paths.add(self.rebase(arg))
353 elif arg == 'gen/utils/gen_kernel/bootstrap_gen_kernel.dill':
354 self.extra_paths.add(self.rebase(arg))
355 return self.parse_bootstrap_gen_kernel()
356 elif arg == 'gen/utils/kernel-service/kernel-service_snapshot.dart.dill':
357 self.extra_paths.add(self.rebase(arg))
358 self.extra_paths.add(
359 self.rebase(
360 os.path.join(self.dart_subdir,
361 'vm_platform_strong.dill')))
363 else:
364 self.unsupported('dart', arg)
365
366 def parse_compile(self):
367 while self.has_next_arg:
368 arg = self.next_arg()
369 if arg == 'js':
370 self.extra_paths.add(
371 self.rebase(
372 os.path.join(self.dart_subdir,
373 'snapshots/dart2js.dart.snapshot')))
374 return self.parse_dart2js()
375 else:
376 self.unsupported('compile', arg)
377
378 def parse_dart2js(self):
379 while self.has_next_arg:
380 arg = self.next_arg()
381 if self.get_option(['-o', '--output']):
382 self.outputs.append(self.rebase(self.optarg))
383 self.outputs.append(
384 self.rebase(self.optarg.replace('.js', '.js.map')))
385 elif self.get_option(['--platform-binaries']):
386 self.extra_paths.add(
387 self.rebase(
388 os.path.join(self.optarg, 'dart2js_platform.dill')))
389 elif self.get_option([
390 '--invoker', '--packages', '--libraries-spec',
391 '--snapshot-kind', '--depfile_output_filename',
392 '--coverage', '--ignore-unrecognized-flags'
393 ]):
394 pass
395 elif arg in [
396 '--canary',
397 '--enable-asserts',
398 '-m',
399 '--minify',
400 '--no-source-maps',
401 ]:
402 pass
403 elif not arg.startswith('-'):
404 self.entry_points.add(self.rebase(arg))
405 else:
406 self.unsupported('dart2js', arg)
407
408 def parse_dartdevc(self):
409 while self.has_next_arg:
410 arg = self.next_arg()
411 if self.get_option(['-o', '--output']):
412 self.outputs.append(self.rebase(self.optarg))
413 self.outputs.append(
414 self.rebase(self.optarg.replace('.js', '.js.map')))
415 self.outputs.append(
416 self.rebase(self.optarg.replace('.js', '.dill')))
417 elif self.get_option(['--dart-sdk-summary']):
418 self.extra_paths.add(self.rebase(self.optarg))
419 elif self.get_option([
420 '--multi-root-scheme', '--multi-root-output-path',
421 '--modules'
422 ]):
423 pass
424 elif arg in [
425 '--canary', '--no-summarize', '--sound-null-safety',
426 '--no-sound-null-safety'
427 ]:
428 pass
429 elif not arg.startswith('-'):
430 if arg.endswith('.dart'):
431 self.entry_points.add(self.rebase(arg))
432 else:
433 self.extra_paths.add(self.rebase(arg))
434 else:
435 self.unsupported('dartdevc', arg)
436
438 while self.has_next_arg:
439 arg = self.next_arg()
440 if arg in ['--help']:
441 pass
442 else:
443 self.unsupported('dartanalyzer', arg)
444
446 while self.has_next_arg:
447 arg = self.next_arg()
448 if self.get_option(['--sdk']):
449 self.extra_paths.add(self.rebase(self.optarg))
450 elif self.get_option(['--train-using']):
451 self.extra_paths.add(self.rebase(self.optarg))
452 self.entry_points.add(
453 self.rebase(os.path.join(self.optarg, 'compiler_api.dart')))
454 # This file isn't referenced from compiler_api.dart.
455 self.entry_points.add(
456 self.rebase(
457 os.path.join(self.optarg, 'src/io/mapped_file.dart')))
458 else:
459 self.unsupported('analysis_server', arg)
460
462 compile_platform_args = []
463 single_root_scheme = None
464 single_root_base = None
465 while self.has_next_arg:
466 arg = self.next_arg()
467 if self.get_option(['--single-root-scheme']):
468 single_root_scheme = self.optarg
469 elif self.get_option(['--single-root-base']):
470 single_root_base = self.optarg
471 # Remove trailing slash to avoid duplicate slashes later.
472 if 1 < len(single_root_base) and single_root_base[-1] == '/':
473 single_root_base = single_root_base[:-1]
474 elif self.get_option(['-D', '--target']):
475 pass
476 elif arg in [
477 '--no-defines',
478 '--nnbd-strong',
479 '--nnbd-weak',
480 '--exclude-source',
481 ]:
482 pass
483 elif not arg.startswith('-'):
484 if len(compile_platform_args) == 0:
485 pass # e.g. dart:core
486 elif len(compile_platform_args) == 1:
487 sdk = arg # sdk via libraries.json
488 if sdk.startswith(f'{single_root_scheme}:///'):
489 sdk = sdk[len(f'{single_root_scheme}:///'):]
490 sdk = os.path.join(single_root_base, sdk)
491 if sdk.endswith('libraries.json'):
492 sdk = os.path.dirname(sdk)
493 self.extra_paths.add(self.rebase(sdk))
494 elif len(compile_platform_args) == 2: # vm_outline_strong dill
495 arg = self.rebase(arg)
496 elif len(compile_platform_args) == 3: # platform dill
497 arg = self.rebase(arg)
498 self.outputs.append(arg)
499 elif len(compile_platform_args) == 4: # outline dill
500 arg = self.rebase(arg)
501 self.outputs.append(arg)
502 if arg != compile_platform_args[2]:
503 self.extra_paths.add(compile_platform_args[2])
504 else:
505 self.unsupported('compile_platform', arg)
506 compile_platform_args.append(arg)
507 else:
508 self.unsupported('compile_platform', arg)
509
511 while self.has_next_arg:
512 arg = self.next_arg()
513 if self.get_option(['--output_dir']):
514 self.outputs.append(self.rebase(self.optarg))
515 elif arg in ['--no-git-hash']:
516 pass
517 else:
518 self.unsupported('create_snapshot_entry', arg)
519
521 while self.has_next_arg:
522 arg = self.next_arg()
523 if self.get_option(['-o', '--output']):
524 self.outputs.append(self.rebase(self.optarg))
525 elif self.get_option(['--dart-sdk-summary']):
526 self.extra_paths.add(self.rebase(self.optarg))
527 elif self.get_option(['--source']):
528 self.entry_points.add(self.rebase(self.optarg))
529 elif self.get_option(
530 ['--packages-file', '--target', '--dart-sdk-summary']):
531 pass
532 elif arg in [
533 '--summary-only',
534 '--sound-null-safety',
535 '--no-sound-null-safety',
536 ]:
537 pass
538 else:
539 self.unsupported('kernel_worker', arg)
540
542 while self.has_next_arg:
543 arg = self.next_arg()
544 if self.get_option(['-o', '--output']):
545 self.outputs.append(self.rebase(self.optarg))
546 elif self.get_option(['--platform']):
547 self.extra_paths.add(self.rebase(self.optarg))
548 elif self.get_option([
549 '--packages', '-D', '--filesystem-root',
550 '--filesystem-scheme'
551 ]):
552 pass
553 elif arg in ['--no-aot', '--no-embed-sources']:
554 pass
555 elif not arg.startswith('-'):
556 self.entry_points.add(self.rebase(arg))
557 else:
558 self.unsupported('gen_kernel', arg)
559
561 while self.has_next_arg:
562 arg = self.next_arg()
563 if self.get_option(['-o', '--output']):
564 self.outputs.append(self.rebase(self.optarg))
565 elif self.get_option(['--platform']):
566 self.extra_paths.add(self.rebase(self.optarg))
567 elif self.get_option(['--packages', '-D']):
568 pass
569 elif arg in [
570 '--aot',
571 '--no-aot',
572 '--no-embed-sources',
573 '--no-link-platform',
574 '--enable-asserts',
575 ]:
576 pass
577 elif self.get_option(['--depfile']):
578 self.depfiles = [self.rebase(self.optarg)]
579 elif not arg.startswith('-'):
580 self.entry_points.add(self.rebase(arg))
581 else:
582 self.unsupported('bootstrap_gen_kernel', arg)
583
585 while self.has_next_arg:
586 arg = self.next_arg()
587 if self.get_option(['--train']):
588 self.entry_points.add(self.rebase(self.optarg))
589 else:
590 self.unsupported('kernel_service_snapshot', arg)
591
593 while self.has_next_arg:
594 arg = self.next_arg()
595 if self.get_option(['--platform']):
596 self.extra_paths.add(self.rebase(self.optarg))
597 elif self.get_option(['--sdk-root']):
598 pass
599 elif arg in ['--train']:
600 pass
601 elif not arg.startswith('-'):
602 self.entry_points.add(self.rebase(arg))
603 else:
604 self.unsupported('frontend_server', arg)
605
607 while self.has_next_arg:
608 arg = self.next_arg()
609 if arg in ['--train']:
610 pass
611 else:
612 self.unsupported('generate_dtd_snapshot', arg)
613
615 while self.has_next_arg:
616 arg = self.next_arg()
617 if arg in ['--help']:
618 pass
619 else:
620 self.unsupported('generate_dds_snapshot', arg)
621
623 while self.has_next_arg:
624 arg = self.next_arg()
625 if arg in ['--help']:
626 pass
627 elif self.get_option(['-o', '--output']):
628 self.outputs.append(self.rebase(self.optarg))
629 elif self.get_option(['--packages-file']):
630 self.extra_paths.add(self.rebase(self.optarg))
631 elif self.get_option(['--dart-sdk-summary']):
632 self.extra_paths.add(self.rebase(self.optarg))
633 elif self.get_option(['--source']):
634 self.entry_points.add(self.rebase(self.optarg))
635 elif self.get_option(['--target']):
636 pass
637 elif arg in [
638 '--sound-null-safety', '--no-sound-null-safety',
639 '--summary-only'
640 ]:
641 pass
642 else:
643 self.unsupported('kernel_worker', arg)
644
646 while self.has_next_arg:
647 arg = self.next_arg()
648 if arg in ['--help']:
649 pass
650 else:
651 self.unsupported('generate_dartdev_snapshot', arg)
652
654 while self.has_next_arg:
655 arg = self.next_arg()
656 if self.get_option(['-o', '--output']):
657 self.outputs.append(self.rebase(self.optarg))
658 elif self.get_option([
659 '--vm_snapshot_data',
660 '--vm_snapshot_instructions',
661 '--isolate_snapshot_data',
662 '--isolate_snapshot_instructions',
663 '--elf',
664 ]):
665 self.outputs.append(self.rebase(self.optarg))
666 elif self.get_option([
667 '--snapshot_kind', '--snapshot-kind', '--coverage',
668 '--ignore-unrecognized-flags'
669 ]):
670 pass
671 elif arg in [
672 '--sound-null-safety',
673 '--deterministic',
674 '--enable-asserts',
675 ]:
676 pass
677 elif not arg.startswith('-'):
678 self.extra_paths.add(self.rebase(arg))
679 else:
680 self.unsupported('gen_snapshot', arg)
681
682
683def main(argv):
684 # Like gn_run_binary, run programs relative to the build directory. The
685 # command is assumed to invoke rewrapper and end its rewrapper arguments
686 # with an -- argument.
687 rewrapper_end = 0
688 for i in range(len(argv)):
689 if argv[i] == '--' and rewrapper_end == 0:
690 rewrapper_end = i + 1
691 if not '/' in argv[i + 1]:
692 argv[i + 1] = './' + argv[i + 1]
693 break
694
695 rewrapper = Rewrapper(argv)
696
697 if rewrapper.exec_root == None:
698 raise Exception('No rewrapper --exec_root was specified')
699
700 if not rewrapper.outputs:
701 raise Exception('No output files were recognized')
702
703 # Run the command directly if it's not supported for remote builds.
704 if rewrapper.no_remote:
705 run_command(argv[rewrapper_end:], 'local')
706 return 0
707
708 # Determine the set of input and output files.
709 package_config = load_package_config(rewrapper.exec_root)
710 if not rewrapper.depfiles:
711 rewrapper.depfiles = [output + '.d' for output in rewrapper.outputs]
712 output_files = rewrapper.outputs + rewrapper.depfiles
713 inputs = find_inputs(rewrapper.entry_points, rewrapper.exec_root,
714 package_config)
715 paths = set(
716 resolve_uri(uri, rewrapper.exec_root, package_config, whole_dir=True)
717 for uri in inputs)
718 paths.add(os.path.join('.dart_tool', 'package_config.json'))
719 for path in rewrapper.extra_paths:
720 paths.add(path)
721 # Ensure the working directory is included if no inputs are inside it.
722 working_directory = rewrapper.rebase('.')
723 if not any([path.startswith(working_directory) for path in paths]):
724 paths.add(rewrapper.rebase('build.ninja.stamp'))
725 paths = list(paths)
726 paths.sort()
727
728 # Construct the final rewrapped command line.
729 command = [argv[1]]
730 command.append('--labels=type=tool')
731 command.append('--inputs=' + ','.join(paths))
732 command.append('--output_files=' + ','.join(output_files))
733 # Absolute paths must not be used with RBE, but since the build currently
734 # heavily relies on them, work around this issue by rewriting the command
735 # to instead use relative paths. The Dart SDK build rules needs to be fixed
736 # rather than doing this, but this is an initial step towards that goal
737 # which will land in subsequent follow up changes.
738 command += argv[2:rewrapper_end] + [
739 rewrite_absolute(arg, rewrapper.exec_root, working_directory)
740 for arg in argv[rewrapper_end:]
741 ]
742
743 # Finally execute the command remotely.
744 run_command(command, rewrapper.exec_strategy)
745
746 # Until the depfiles are fixed so they don't contain absoiute paths, we need
747 # to rewrite the absoute paths appropriately.
748 for depfile in rewrapper.depfiles:
749 lines = []
750 try:
751 with open(os.path.join(rewrapper.exec_root, depfile), 'r') as file:
752 lines = file.readlines()
753 lines = [
754 line.replace('/b/f/w', rewrapper.exec_root) for line in lines
755 ]
756 with open(os.path.join(rewrapper.exec_root, depfile), 'w') as file:
757 file.writelines(lines)
758 except FileNotFoundError:
759 pass
760
761 return 0
762
763
764if __name__ == '__main__':
765 sys.exit(main(sys.argv))
static float next(float f)
def unsupported(self, state, arg)
def parse_kernel_service_snapshot(self)
def parse_generate_dtd_snapshot(self)
def parse_create_snapshot_entry(self)
def __init__(self, argv)
def parse_generate_dds_snapshot(self)
def parse_generate_dartdev_snapshot(self)
def parse_bootstrap_gen_kernel(self)
def get_option(self, options)
static void append(char **dst, size_t *count, const char *src, size_t n)
Definition: editor.cpp:211
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not set
Definition: switches.h:76
Definition: main.py:1
def resolve_uri(uri, exec_root, package_config, whole_dir=False)
def run_command(command, strategy)
def list_imports(uri, exec_root, package_config)
def find_inputs(uris, exec_root, package_config)
def rewrite_absolute(arg, exec_root, working_directory)
def load_package_config(exec_root)
def print(*args, **kwargs)
Definition: run_tests.py:49
SIT bool any(const Vec< 1, T > &x)
Definition: SkVx.h:530
static SkString join(const CommandLineFlags::StringArray &)
Definition: skpbench.cpp:741