Flutter Engine
The Flutter Engine
Classes | Functions
rewrapper_dart Namespace Reference

Classes

class  Rewrapper
 

Functions

def run_command (command, strategy)
 
def load_package_config (exec_root)
 
def resolve_uri (uri, exec_root, package_config, whole_dir=False)
 
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 main (argv)
 

Function Documentation

◆ find_inputs()

def rewrapper_dart.find_inputs (   uris,
  exec_root,
  package_config 
)

Definition at line 112 of file rewrapper_dart.py.

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.
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
def list_imports(uri, exec_root, package_config)
def find_inputs(uris, exec_root, package_config)

◆ list_imports()

def rewrapper_dart.list_imports (   uri,
  exec_root,
  package_config 
)

Definition at line 72 of file rewrapper_dart.py.

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.
def resolve_uri(uri, exec_root, package_config, whole_dir=False)

◆ load_package_config()

def rewrapper_dart.load_package_config (   exec_root)

Definition at line 45 of file rewrapper_dart.py.

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.
def load_package_config(exec_root)

◆ main()

def rewrapper_dart.main (   argv)

Definition at line 683 of file rewrapper_dart.py.

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
def run_command(command, strategy)
def rewrite_absolute(arg, exec_root, working_directory)
SIT bool any(const Vec< 1, T > &x)
Definition: SkVx.h:530
static SkString join(const CommandLineFlags::StringArray &)
Definition: skpbench.cpp:741

◆ resolve_uri()

def rewrapper_dart.resolve_uri (   uri,
  exec_root,
  package_config,
  whole_dir = False 
)

Definition at line 52 of file rewrapper_dart.py.

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.
static float next(float f)

◆ rewrite_absolute()

def rewrapper_dart.rewrite_absolute (   arg,
  exec_root,
  working_directory 
)

Definition at line 126 of file rewrapper_dart.py.

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.

◆ run_command()

def rewrapper_dart.run_command (   command,
  strategy 
)

Definition at line 21 of file rewrapper_dart.py.

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.
def print(*args, **kwargs)
Definition: run_tests.py:49