mirror of
https://github.com/dart-lang/sdk
synced 2024-10-01 19:29:09 +00:00
3d8829fad2
Change-Id: I84f8dbc174dbac5a11ca84e248c7aecb3759aaad Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/380283 Reviewed-by: Slava Egorov <vegorov@google.com> Reviewed-by: Sigmund Cherem <sigmund@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com>
768 lines
32 KiB
Python
768 lines
32 KiB
Python
#!/usr/bin/env python3
|
|
# Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
|
|
# for details. All rights reserved. Use of this source code is governed by a
|
|
# BSD-style license that can be found in the LICENSE file.
|
|
|
|
# This program executes Dart programs on RBE using rewrapper by parsing the
|
|
# source code to locate the input files, and recognizes the command line options
|
|
# of well known programs to determine the output files.
|
|
|
|
# New executions during the Dart SDK build needs to be supported here in order
|
|
# to speed up the build with RBE. See the argument parser below.
|
|
|
|
import json
|
|
import os
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
|
|
|
|
# Run a command, swallowing the output unless there is an error.
|
|
def run_command(command, strategy):
|
|
try:
|
|
subprocess.check_output(command, stderr=subprocess.STDOUT)
|
|
return 0
|
|
except subprocess.CalledProcessError as e:
|
|
print(e.output.decode("utf-8"))
|
|
if strategy == 'remote':
|
|
joined = ' '.join(command)
|
|
print(f'''Failed to run command remotely: {joined}
|
|
|
|
If you're seeing this error on a bot and it doesn't happen locally, then you may
|
|
need to teach the script build/rbe/rewrapper_dart.py what the appropriate input
|
|
and outputs files of the command are. You can see the list of used inputs and
|
|
outputs in the rewrapper invocation above. To reproduce this error locally, try
|
|
forcing a remote build by setting the RBE_exec_strategy=remote environment
|
|
variable.
|
|
''')
|
|
sys.exit(1)
|
|
except OSError as e:
|
|
print(e.strerror)
|
|
sys.exit(1)
|
|
|
|
|
|
# Loads the package config file.
|
|
def load_package_config(exec_root):
|
|
path = os.path.join(exec_root, '.dart_tool', 'package_config.json')
|
|
with open(path, 'r') as file:
|
|
return json.load(file)
|
|
|
|
|
|
# Resolves a Dart import URI using the package config.
|
|
def resolve_uri(uri, exec_root, package_config, whole_dir=False):
|
|
if uri.startswith('package:'):
|
|
match = re.search(r'package:([^/]*)/(.*)', uri)
|
|
package_name = match.groups()[0]
|
|
relative = match.groups()[1]
|
|
package_data = next(pkg for pkg in package_config['packages']
|
|
if pkg['name'] == package_name)
|
|
package_root = package_data['rootUri']
|
|
package_root = package_root[3:] # Remove leading ../
|
|
package_uri = package_data['packageUri']
|
|
if whole_dir:
|
|
uri = package_root + '/' + package_uri
|
|
else:
|
|
uri = package_root + '/' + package_uri + relative
|
|
return uri
|
|
|
|
|
|
# Lists the imports of a Dart file uri using the package config and a rough
|
|
# parser that recognizes fairly traditional imports. This is designed to be much
|
|
# faster than actually invoking the front end.
|
|
def list_imports(uri, exec_root, package_config):
|
|
if uri.startswith('dart:'):
|
|
return set()
|
|
path = os.path.join(exec_root, resolve_uri(uri, exec_root, package_config))
|
|
file = open(path, 'r')
|
|
imports = set()
|
|
for line in file.readlines():
|
|
tokens = [token for token in re.split(r'\s+', line) if token != '']
|
|
if not tokens or tokens[0] in [
|
|
'//', '///', '/*', '*/', '#!', 'library', 'show'
|
|
]:
|
|
continue
|
|
# Imports must happen before definitions.
|
|
if tokens[0] in ['const', 'class', 'enum']:
|
|
break
|
|
if 2 <= len(tokens
|
|
) and tokens[0] == 'if' and tokens[1] == '(dart.library.io)':
|
|
tokens = ['import'] + tokens[2:]
|
|
if tokens[0] not in ['import', 'export', 'part']:
|
|
continue
|
|
if len(tokens) < 2:
|
|
raise Exception(f'Bad import statement: {path}: {line}')
|
|
if tokens[0] == 'part' and tokens[1] == 'of':
|
|
continue
|
|
token = tokens[1].replace('"', '').replace("'", '').replace(';', '')
|
|
if token.startswith('dart:'):
|
|
continue
|
|
if not ':' in token:
|
|
dirname = os.path.dirname(uri)
|
|
while token.startswith('..'):
|
|
token = token[3:]
|
|
dirname = os.path.dirname(dirname)
|
|
token = dirname + '/' + token
|
|
imports.add(token)
|
|
file.close()
|
|
return imports
|
|
|
|
|
|
# Transitively compute the set of dart files needed to execute the specified
|
|
# entry point using the package config.
|
|
def find_inputs(uris, exec_root, package_config):
|
|
inputs = set(uris)
|
|
unexplored = set(uris)
|
|
while unexplored:
|
|
uri = unexplored.pop()
|
|
imports = list_imports(uri, exec_root, package_config)
|
|
for uri in imports:
|
|
if not uri in inputs:
|
|
inputs.add(uri)
|
|
unexplored.add(uri)
|
|
return inputs
|
|
|
|
|
|
# Rewrite absolute paths in an argument to be relative.
|
|
def rewrite_absolute(arg, exec_root, working_directory):
|
|
# The file:// schema does not work with relative paths as they are parsed as
|
|
# the authority by the dart Uri class.
|
|
arg = arg.replace('file:///' + exec_root, '../../')
|
|
arg = arg.replace('file://' + exec_root, '../../')
|
|
# Replace the absolute exec root by a relative path to the exec root.
|
|
arg = arg.replace(exec_root, '../../')
|
|
# Simplify paths going to the exec root and back into the out directory.
|
|
# Carefully ensure the whole path isn't optimized away.
|
|
if arg.endswith(f'../../{working_directory}/'):
|
|
arg = arg.replace(f'../../{working_directory}/', '.')
|
|
else:
|
|
arg = arg.replace(f'../../{working_directory}/', '')
|
|
return arg
|
|
|
|
|
|
# Parse the command line execution to recognize well known programs during the
|
|
# Dart SDK build, so the inputs and output files can be determined, and the
|
|
# command can be offloaded to RBE.
|
|
#
|
|
# RBE needs a command to run, a list of input files, and a list of output files,
|
|
# and it then executes the command remotely and caches the result. Absolute
|
|
# paths must not occur in the command as the remote execution will happen in
|
|
# another directory. However, since we currently rely on absolute paths, we work
|
|
# around the issue and rewrite the absolute paths accordingly until the problem
|
|
# is fixed on our end.
|
|
#
|
|
# This is a parser that handles nested commands executing each other, taking
|
|
# care to know whose options it is currently parsing, and extracting the
|
|
# appropriate information from each argument. Every invoked program and option
|
|
# during the build needs to be supported here, otherwise the remote command may
|
|
# be inaccurate and not have right inputs and outputs. Although maintaining this
|
|
# parser takes some effort, it is being paid back in the builders being sped up
|
|
# massively on cache hits, as well as speeding up any local developers that
|
|
# build code already built by the bots.
|
|
#
|
|
# To add a new program, recognize the entry point and define its parser method.
|
|
# To add a new option, parse the option in the appropriate method and either
|
|
# ignore it or recognize any input and output files. All invoked options needs
|
|
# be allowlisted here know we didn't accidentally misunderstand the invoked
|
|
# command when running it remotely.
|
|
class Rewrapper:
|
|
|
|
def __init__(self, argv):
|
|
self.dart_subdir = None
|
|
self.depfiles = None
|
|
self.entry_points = set()
|
|
self.exec_root = None
|
|
self.exec_strategy = 'remote'
|
|
self.exec_strategy_explicit = False
|
|
self.extra_paths = set()
|
|
self.outputs = []
|
|
self.no_remote = None
|
|
self.argv = argv
|
|
self.optarg = None
|
|
self.optind = 0
|
|
self.parse()
|
|
|
|
@property
|
|
def has_next_arg(self):
|
|
return self.optind + 1 < len(self.argv)
|
|
|
|
def next_arg(self):
|
|
self.optind += 1
|
|
return self.argv[self.optind]
|
|
|
|
def get_option(self, options):
|
|
arg = self.argv[self.optind]
|
|
for option in options:
|
|
if arg == option:
|
|
self.optind += 1
|
|
self.optarg = self.argv[self.optind]
|
|
return True
|
|
elif option.startswith('--') and arg.startswith(f'{option}='):
|
|
self.optarg = arg[len(f'{option}='):]
|
|
return True
|
|
elif option[0] == '-' and option[1] != '-' and arg.startswith(
|
|
option):
|
|
self.optarg = arg[len(option):]
|
|
return True
|
|
return False
|
|
|
|
def unsupported(self, state, arg):
|
|
raise Exception(f'''Unsupported operand in state {state}: {arg}
|
|
|
|
You need to recognize the argument/option in the build/rbe/rewrapper_dart.py
|
|
script in order to execute this command remotely on RBE. Read the big comments
|
|
in the file explaining what this script is and how it works. Follow this stack
|
|
trace to find the place to insert the appropriate support.
|
|
''')
|
|
|
|
def rebase(self, path):
|
|
if path.startswith('package:'):
|
|
return path
|
|
# Handle the use of paths starting with an extra slash.
|
|
if path.startswith('org-dartlang-kernel-service:///'):
|
|
path = os.path.join(self.exec_root,
|
|
path[len('org-dartlang-kernel-service:///'):])
|
|
if path.startswith('org-dartlang-kernel-service://'):
|
|
path = os.path.join(self.exec_root,
|
|
path[len('org-dartlang-kernel-service://'):])
|
|
# Handle the use of paths starting with an extra slash.
|
|
if path.startswith('file:////'):
|
|
path = path[len('file:///'):]
|
|
elif path.startswith('file://'):
|
|
path = path[len('file://'):]
|
|
path = os.path.abspath(path)
|
|
if not path.startswith(self.exec_root):
|
|
raise Exception(f"Path isn't inside exec_root: {path}")
|
|
return path[len(self.exec_root):]
|
|
|
|
def parse(self):
|
|
while self.has_next_arg:
|
|
arg = self.next_arg()
|
|
if arg == 'rewrapper' or arg.endswith('/rewrapper'):
|
|
return self.parse_rewrapper()
|
|
else:
|
|
self.unsupported('rewrapper_dart', arg)
|
|
|
|
def parse_rewrapper(self):
|
|
while self.has_next_arg:
|
|
arg = self.next_arg()
|
|
if self.get_option(['--cfg']):
|
|
with open(self.optarg, 'r') as fp:
|
|
for line in fp.readlines():
|
|
key, value = fp.split('=')
|
|
if key == 'exec_root':
|
|
self.exec_root = value
|
|
elif key == 'exec_strategy':
|
|
self.exec_strategy = value
|
|
elif self.get_option(['--exec_root']):
|
|
self.exec_root = os.path.abspath(self.optarg)
|
|
if not self.exec_root.endswith('/'):
|
|
self.exec_root += '/'
|
|
elif self.get_option(['--exec_strategy']):
|
|
self.exec_strategy = self.optarg
|
|
self.exec_strategy_explicit = True
|
|
elif arg == '--':
|
|
env_exec_strategy = os.environ.get('RBE_exec_strategy')
|
|
if env_exec_strategy and not self.exec_strategy_explicit:
|
|
self.exec_strategy = env_exec_strategy
|
|
elif arg.startswith('-'):
|
|
pass # Ignore unknown rewrapper options.
|
|
elif arg.endswith('/dart'):
|
|
self.dart_subdir = os.path.dirname(arg)
|
|
return self.parse_dart()
|
|
elif arg.endswith('/gen_snapshot') or arg.endswith(
|
|
'/gen_snapshot_product'):
|
|
return self.parse_gen_snapshot()
|
|
else:
|
|
self.unsupported('rewrapper', arg)
|
|
|
|
def parse_dart(self):
|
|
while self.has_next_arg:
|
|
arg = self.next_arg()
|
|
if self.get_option(['--dfe']):
|
|
self.extra_paths.add(self.rebase(self.optarg))
|
|
elif self.get_option(['--snapshot']):
|
|
self.outputs.append(self.rebase(self.optarg))
|
|
elif self.get_option(['--depfile']):
|
|
self.depfiles = [self.rebase(self.optarg)]
|
|
elif self.get_option(['--snapshot-depfile']):
|
|
self.depfiles = [self.rebase(self.optarg)]
|
|
elif self.get_option([
|
|
'--packages', '-D', '--snapshot-kind',
|
|
'--depfile_output_filename', '--coverage',
|
|
'--ignore-unrecognized-flags'
|
|
]):
|
|
pass
|
|
elif arg in ['--deterministic', '--sound-null-safety']:
|
|
pass
|
|
elif arg == 'compile':
|
|
self.extra_paths.add(
|
|
self.rebase(
|
|
os.path.join(self.dart_subdir,
|
|
'snapshots/dartdev.dart.snapshot')))
|
|
self.extra_paths.add(
|
|
self.rebase(os.path.join(self.dart_subdir, '../lib')))
|
|
return self.parse_compile()
|
|
elif arg == '../../pkg/compiler/lib/src/dart2js.dart':
|
|
self.entry_points.add(self.rebase(arg))
|
|
return self.parse_dart2js()
|
|
elif arg == 'gen/utils/compiler/dart2js.dart.dill':
|
|
self.extra_paths.add(self.rebase(arg))
|
|
return self.parse_dart2js()
|
|
elif arg == '../../pkg/dev_compiler/bin/dartdevc.dart':
|
|
self.entry_points.add(self.rebase(arg))
|
|
return self.parse_dartdevc()
|
|
elif arg == 'gen/utils/ddc/dartdevc.dart.dill':
|
|
self.extra_paths.add(self.rebase(arg))
|
|
return self.parse_dartdevc()
|
|
elif arg == 'gen/utils/dartanalyzer/dartanalyzer.dart.dill':
|
|
self.extra_paths.add(self.rebase(arg))
|
|
return self.parse_dartanalyzer()
|
|
elif arg == 'gen/utils/analysis_server/analysis_server.dart.dill':
|
|
self.extra_paths.add(self.rebase(arg))
|
|
return self.parse_analysis_server()
|
|
elif arg == '../../pkg/front_end/tool/_fasta/compile_platform.dart':
|
|
self.entry_points.add(self.rebase(arg))
|
|
return self.parse_compile_platform()
|
|
elif arg == '../../utils/compiler/create_snapshot_entry.dart':
|
|
self.entry_points.add(self.rebase(arg))
|
|
self.extra_paths.add('tools/make_version.py')
|
|
# This step is very cheap and python3 isn't in the docker image.
|
|
self.no_remote = True
|
|
return self.parse_create_snapshot_entry()
|
|
elif arg == '../../utils/bazel/kernel_worker.dart':
|
|
self.entry_points.add(self.rebase(arg))
|
|
return self.parse_kernel_worker()
|
|
elif arg == '../../pkg/vm/bin/gen_kernel.dart':
|
|
self.entry_points.add(self.rebase(arg))
|
|
return self.parse_gen_kernel()
|
|
elif arg == 'gen/utils/kernel-service/frontend_server.dart.dill':
|
|
self.extra_paths.add(self.rebase(arg))
|
|
return self.parse_frontend_server()
|
|
elif arg == 'gen/utils/dtd/generate_dtd_snapshot.dart.dill':
|
|
self.extra_paths.add(self.rebase(arg))
|
|
return self.parse_generate_dtd_snapshot()
|
|
elif arg == 'gen/utils/dds/generate_dds_snapshot.dart.dill':
|
|
self.extra_paths.add(self.rebase(arg))
|
|
return self.parse_generate_dds_snapshot()
|
|
elif arg == 'gen/utils/bazel/kernel_worker.dart.dill':
|
|
self.extra_paths.add(self.rebase(arg))
|
|
return self.parse_kernel_worker()
|
|
elif arg == 'gen/utils/dartdev/generate_dartdev_snapshot.dart.dill':
|
|
self.extra_paths.add(self.rebase(arg))
|
|
return self.parse_generate_dartdev_snapshot()
|
|
elif arg == 'gen/utils/gen_kernel/bootstrap_gen_kernel.dill':
|
|
self.extra_paths.add(self.rebase(arg))
|
|
return self.parse_bootstrap_gen_kernel()
|
|
elif arg == 'gen/utils/kernel-service/kernel-service_snapshot.dart.dill':
|
|
self.extra_paths.add(self.rebase(arg))
|
|
self.extra_paths.add(
|
|
self.rebase(
|
|
os.path.join(self.dart_subdir,
|
|
'vm_platform_strong.dill')))
|
|
return self.parse_kernel_service_snapshot()
|
|
else:
|
|
self.unsupported('dart', arg)
|
|
|
|
def parse_compile(self):
|
|
while self.has_next_arg:
|
|
arg = self.next_arg()
|
|
if arg == 'js':
|
|
self.extra_paths.add(
|
|
self.rebase(
|
|
os.path.join(self.dart_subdir,
|
|
'snapshots/dart2js.dart.snapshot')))
|
|
return self.parse_dart2js()
|
|
else:
|
|
self.unsupported('compile', arg)
|
|
|
|
def parse_dart2js(self):
|
|
while self.has_next_arg:
|
|
arg = self.next_arg()
|
|
if self.get_option(['-o', '--output']):
|
|
self.outputs.append(self.rebase(self.optarg))
|
|
self.outputs.append(
|
|
self.rebase(self.optarg.replace('.js', '.js.map')))
|
|
elif self.get_option(['--platform-binaries']):
|
|
self.extra_paths.add(
|
|
self.rebase(
|
|
os.path.join(self.optarg, 'dart2js_platform.dill')))
|
|
elif self.get_option([
|
|
'--invoker', '--packages', '--libraries-spec',
|
|
'--snapshot-kind', '--depfile_output_filename',
|
|
'--coverage', '--ignore-unrecognized-flags'
|
|
]):
|
|
pass
|
|
elif arg in [
|
|
'--canary',
|
|
'--enable-asserts',
|
|
'-m',
|
|
'--minify',
|
|
'--no-source-maps',
|
|
]:
|
|
pass
|
|
elif not arg.startswith('-'):
|
|
self.entry_points.add(self.rebase(arg))
|
|
else:
|
|
self.unsupported('dart2js', arg)
|
|
|
|
def parse_dartdevc(self):
|
|
while self.has_next_arg:
|
|
arg = self.next_arg()
|
|
if self.get_option(['-o', '--output']):
|
|
self.outputs.append(self.rebase(self.optarg))
|
|
self.outputs.append(
|
|
self.rebase(self.optarg.replace('.js', '.js.map')))
|
|
self.outputs.append(
|
|
self.rebase(self.optarg.replace('.js', '.dill')))
|
|
elif self.get_option(['--dart-sdk-summary']):
|
|
self.extra_paths.add(self.rebase(self.optarg))
|
|
elif self.get_option([
|
|
'--multi-root-scheme', '--multi-root-output-path',
|
|
'--modules'
|
|
]):
|
|
pass
|
|
elif arg in [
|
|
'--canary', '--no-summarize', '--sound-null-safety',
|
|
'--no-sound-null-safety'
|
|
]:
|
|
pass
|
|
elif not arg.startswith('-'):
|
|
if arg.endswith('.dart'):
|
|
self.entry_points.add(self.rebase(arg))
|
|
else:
|
|
self.extra_paths.add(self.rebase(arg))
|
|
else:
|
|
self.unsupported('dartdevc', arg)
|
|
|
|
def parse_dartanalyzer(self):
|
|
while self.has_next_arg:
|
|
arg = self.next_arg()
|
|
if arg in ['--help']:
|
|
pass
|
|
else:
|
|
self.unsupported('dartanalyzer', arg)
|
|
|
|
def parse_analysis_server(self):
|
|
while self.has_next_arg:
|
|
arg = self.next_arg()
|
|
if self.get_option(['--sdk']):
|
|
self.extra_paths.add(self.rebase(self.optarg))
|
|
elif self.get_option(['--train-using']):
|
|
self.extra_paths.add(self.rebase(self.optarg))
|
|
self.entry_points.add(
|
|
self.rebase(os.path.join(self.optarg, 'compiler_api.dart')))
|
|
# This file isn't referenced from compiler_api.dart.
|
|
self.entry_points.add(
|
|
self.rebase(
|
|
os.path.join(self.optarg, 'src/io/mapped_file.dart')))
|
|
else:
|
|
self.unsupported('analysis_server', arg)
|
|
|
|
def parse_compile_platform(self):
|
|
compile_platform_args = []
|
|
single_root_scheme = None
|
|
single_root_base = None
|
|
while self.has_next_arg:
|
|
arg = self.next_arg()
|
|
if self.get_option(['--single-root-scheme']):
|
|
single_root_scheme = self.optarg
|
|
elif self.get_option(['--single-root-base']):
|
|
single_root_base = self.optarg
|
|
# Remove trailing slash to avoid duplicate slashes later.
|
|
if 1 < len(single_root_base) and single_root_base[-1] == '/':
|
|
single_root_base = single_root_base[:-1]
|
|
elif self.get_option(['-D', '--target']):
|
|
pass
|
|
elif arg in [
|
|
'--no-defines',
|
|
'--nnbd-strong',
|
|
'--nnbd-weak',
|
|
'--exclude-source',
|
|
]:
|
|
pass
|
|
elif not arg.startswith('-'):
|
|
if len(compile_platform_args) == 0:
|
|
pass # e.g. dart:core
|
|
elif len(compile_platform_args) == 1:
|
|
sdk = arg # sdk via libraries.json
|
|
if sdk.startswith(f'{single_root_scheme}:///'):
|
|
sdk = sdk[len(f'{single_root_scheme}:///'):]
|
|
sdk = os.path.join(single_root_base, sdk)
|
|
if sdk.endswith('libraries.json'):
|
|
sdk = os.path.dirname(sdk)
|
|
self.extra_paths.add(self.rebase(sdk))
|
|
elif len(compile_platform_args) == 2: # vm_outline_strong dill
|
|
arg = self.rebase(arg)
|
|
elif len(compile_platform_args) == 3: # platform dill
|
|
arg = self.rebase(arg)
|
|
self.outputs.append(arg)
|
|
elif len(compile_platform_args) == 4: # outline dill
|
|
arg = self.rebase(arg)
|
|
self.outputs.append(arg)
|
|
if arg != compile_platform_args[2]:
|
|
self.extra_paths.add(compile_platform_args[2])
|
|
else:
|
|
self.unsupported('compile_platform', arg)
|
|
compile_platform_args.append(arg)
|
|
else:
|
|
self.unsupported('compile_platform', arg)
|
|
|
|
def parse_create_snapshot_entry(self):
|
|
while self.has_next_arg:
|
|
arg = self.next_arg()
|
|
if self.get_option(['--output_dir']):
|
|
self.outputs.append(self.rebase(self.optarg))
|
|
elif arg in ['--no-git-hash']:
|
|
pass
|
|
else:
|
|
self.unsupported('create_snapshot_entry', arg)
|
|
|
|
def parse_kernel_worker(self):
|
|
while self.has_next_arg:
|
|
arg = self.next_arg()
|
|
if self.get_option(['-o', '--output']):
|
|
self.outputs.append(self.rebase(self.optarg))
|
|
elif self.get_option(['--dart-sdk-summary']):
|
|
self.extra_paths.add(self.rebase(self.optarg))
|
|
elif self.get_option(['--source']):
|
|
self.entry_points.add(self.rebase(self.optarg))
|
|
elif self.get_option(
|
|
['--packages-file', '--target', '--dart-sdk-summary']):
|
|
pass
|
|
elif arg in [
|
|
'--summary-only',
|
|
'--sound-null-safety',
|
|
'--no-sound-null-safety',
|
|
]:
|
|
pass
|
|
else:
|
|
self.unsupported('kernel_worker', arg)
|
|
|
|
def parse_gen_kernel(self):
|
|
while self.has_next_arg:
|
|
arg = self.next_arg()
|
|
if self.get_option(['-o', '--output']):
|
|
self.outputs.append(self.rebase(self.optarg))
|
|
elif self.get_option(['--platform']):
|
|
self.extra_paths.add(self.rebase(self.optarg))
|
|
elif self.get_option([
|
|
'--packages', '-D', '--filesystem-root',
|
|
'--filesystem-scheme'
|
|
]):
|
|
pass
|
|
elif arg in ['--no-aot', '--no-embed-sources']:
|
|
pass
|
|
elif not arg.startswith('-'):
|
|
self.entry_points.add(self.rebase(arg))
|
|
else:
|
|
self.unsupported('gen_kernel', arg)
|
|
|
|
def parse_bootstrap_gen_kernel(self):
|
|
while self.has_next_arg:
|
|
arg = self.next_arg()
|
|
if self.get_option(['-o', '--output']):
|
|
self.outputs.append(self.rebase(self.optarg))
|
|
elif self.get_option(['--platform']):
|
|
self.extra_paths.add(self.rebase(self.optarg))
|
|
elif self.get_option(['--dynamic-interface']):
|
|
self.extra_paths.add(self.rebase(self.optarg))
|
|
elif self.get_option(['--packages', '-D']):
|
|
pass
|
|
elif arg in [
|
|
'--aot',
|
|
'--no-aot',
|
|
'--no-embed-sources',
|
|
'--no-link-platform',
|
|
'--enable-asserts',
|
|
]:
|
|
pass
|
|
elif self.get_option(['--depfile']):
|
|
self.depfiles = [self.rebase(self.optarg)]
|
|
elif not arg.startswith('-'):
|
|
self.entry_points.add(self.rebase(arg))
|
|
else:
|
|
self.unsupported('bootstrap_gen_kernel', arg)
|
|
|
|
def parse_kernel_service_snapshot(self):
|
|
while self.has_next_arg:
|
|
arg = self.next_arg()
|
|
if self.get_option(['--train']):
|
|
self.entry_points.add(self.rebase(self.optarg))
|
|
else:
|
|
self.unsupported('kernel_service_snapshot', arg)
|
|
|
|
def parse_frontend_server(self):
|
|
while self.has_next_arg:
|
|
arg = self.next_arg()
|
|
if self.get_option(['--platform']):
|
|
self.extra_paths.add(self.rebase(self.optarg))
|
|
elif self.get_option(['--sdk-root']):
|
|
pass
|
|
elif arg in ['--train']:
|
|
pass
|
|
elif not arg.startswith('-'):
|
|
self.entry_points.add(self.rebase(arg))
|
|
else:
|
|
self.unsupported('frontend_server', arg)
|
|
|
|
def parse_generate_dtd_snapshot(self):
|
|
while self.has_next_arg:
|
|
arg = self.next_arg()
|
|
if arg in ['--train']:
|
|
pass
|
|
else:
|
|
self.unsupported('generate_dtd_snapshot', arg)
|
|
|
|
def parse_generate_dds_snapshot(self):
|
|
while self.has_next_arg:
|
|
arg = self.next_arg()
|
|
if arg in ['--help']:
|
|
pass
|
|
else:
|
|
self.unsupported('generate_dds_snapshot', arg)
|
|
|
|
def parse_kernel_worker(self):
|
|
while self.has_next_arg:
|
|
arg = self.next_arg()
|
|
if arg in ['--help']:
|
|
pass
|
|
elif self.get_option(['-o', '--output']):
|
|
self.outputs.append(self.rebase(self.optarg))
|
|
elif self.get_option(['--packages-file']):
|
|
self.extra_paths.add(self.rebase(self.optarg))
|
|
elif self.get_option(['--dart-sdk-summary']):
|
|
self.extra_paths.add(self.rebase(self.optarg))
|
|
elif self.get_option(['--source']):
|
|
self.entry_points.add(self.rebase(self.optarg))
|
|
elif self.get_option(['--target']):
|
|
pass
|
|
elif arg in [
|
|
'--sound-null-safety', '--no-sound-null-safety',
|
|
'--summary-only'
|
|
]:
|
|
pass
|
|
else:
|
|
self.unsupported('kernel_worker', arg)
|
|
|
|
def parse_generate_dartdev_snapshot(self):
|
|
while self.has_next_arg:
|
|
arg = self.next_arg()
|
|
if arg in ['--help']:
|
|
pass
|
|
else:
|
|
self.unsupported('generate_dartdev_snapshot', arg)
|
|
|
|
def parse_gen_snapshot(self):
|
|
while self.has_next_arg:
|
|
arg = self.next_arg()
|
|
if self.get_option(['-o', '--output']):
|
|
self.outputs.append(self.rebase(self.optarg))
|
|
elif self.get_option([
|
|
'--vm_snapshot_data',
|
|
'--vm_snapshot_instructions',
|
|
'--isolate_snapshot_data',
|
|
'--isolate_snapshot_instructions',
|
|
'--elf',
|
|
]):
|
|
self.outputs.append(self.rebase(self.optarg))
|
|
elif self.get_option([
|
|
'--snapshot_kind', '--snapshot-kind', '--coverage',
|
|
'--ignore-unrecognized-flags'
|
|
]):
|
|
pass
|
|
elif arg in [
|
|
'--sound-null-safety',
|
|
'--deterministic',
|
|
'--enable-asserts',
|
|
]:
|
|
pass
|
|
elif not arg.startswith('-'):
|
|
self.extra_paths.add(self.rebase(arg))
|
|
else:
|
|
self.unsupported('gen_snapshot', arg)
|
|
|
|
|
|
def main(argv):
|
|
# Like gn_run_binary, run programs relative to the build directory. The
|
|
# command is assumed to invoke rewrapper and end its rewrapper arguments
|
|
# with an -- argument.
|
|
rewrapper_end = 0
|
|
for i in range(len(argv)):
|
|
if argv[i] == '--' and rewrapper_end == 0:
|
|
rewrapper_end = i + 1
|
|
if not '/' in argv[i + 1]:
|
|
argv[i + 1] = './' + argv[i + 1]
|
|
break
|
|
|
|
rewrapper = Rewrapper(argv)
|
|
|
|
if rewrapper.exec_root == None:
|
|
raise Exception('No rewrapper --exec_root was specified')
|
|
|
|
if not rewrapper.outputs:
|
|
raise Exception('No output files were recognized')
|
|
|
|
# Run the command directly if it's not supported for remote builds.
|
|
if rewrapper.no_remote:
|
|
run_command(argv[rewrapper_end:], 'local')
|
|
return 0
|
|
|
|
# Determine the set of input and output files.
|
|
package_config = load_package_config(rewrapper.exec_root)
|
|
if not rewrapper.depfiles:
|
|
rewrapper.depfiles = [output + '.d' for output in rewrapper.outputs]
|
|
output_files = rewrapper.outputs + rewrapper.depfiles
|
|
inputs = find_inputs(rewrapper.entry_points, rewrapper.exec_root,
|
|
package_config)
|
|
paths = set(
|
|
resolve_uri(uri, rewrapper.exec_root, package_config, whole_dir=True)
|
|
for uri in inputs)
|
|
paths.add(os.path.join('.dart_tool', 'package_config.json'))
|
|
for path in rewrapper.extra_paths:
|
|
paths.add(path)
|
|
# Ensure the working directory is included if no inputs are inside it.
|
|
working_directory = rewrapper.rebase('.')
|
|
if not any([path.startswith(working_directory) for path in paths]):
|
|
paths.add(rewrapper.rebase('build.ninja.stamp'))
|
|
paths = list(paths)
|
|
paths.sort()
|
|
|
|
# Construct the final rewrapped command line.
|
|
command = [argv[1]]
|
|
command.append('--labels=type=tool')
|
|
command.append('--inputs=' + ','.join(paths))
|
|
command.append('--output_files=' + ','.join(output_files))
|
|
# Absolute paths must not be used with RBE, but since the build currently
|
|
# heavily relies on them, work around this issue by rewriting the command
|
|
# to instead use relative paths. The Dart SDK build rules needs to be fixed
|
|
# rather than doing this, but this is an initial step towards that goal
|
|
# which will land in subsequent follow up changes.
|
|
command += argv[2:rewrapper_end] + [
|
|
rewrite_absolute(arg, rewrapper.exec_root, working_directory)
|
|
for arg in argv[rewrapper_end:]
|
|
]
|
|
|
|
# Finally execute the command remotely.
|
|
run_command(command, rewrapper.exec_strategy)
|
|
|
|
# Until the depfiles are fixed so they don't contain absoiute paths, we need
|
|
# to rewrite the absoute paths appropriately.
|
|
for depfile in rewrapper.depfiles:
|
|
lines = []
|
|
try:
|
|
with open(os.path.join(rewrapper.exec_root, depfile), 'r') as file:
|
|
lines = file.readlines()
|
|
lines = [
|
|
line.replace('/b/f/w', rewrapper.exec_root) for line in lines
|
|
]
|
|
with open(os.path.join(rewrapper.exec_root, depfile), 'w') as file:
|
|
file.writelines(lines)
|
|
except FileNotFoundError:
|
|
pass
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main(sys.argv))
|