Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Classes | Functions
rewrapper_dart Namespace Reference

Classes

class  Rewrapper
 

Functions

 run_command (command, strategy)
 
 load_package_config (exec_root)
 
 resolve_uri (uri, exec_root, package_config, whole_dir=False)
 
 list_imports (uri, exec_root, package_config)
 
 find_inputs (uris, exec_root, package_config)
 
 rewrite_absolute (arg, exec_root, working_directory)
 
 main (argv)
 

Function Documentation

◆ find_inputs()

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.

◆ list_imports()

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.

◆ load_package_config()

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.

◆ main()

rewrapper_dart.main (   argv)

Definition at line 679 of file rewrapper_dart.py.

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
Definition main.py:1

◆ resolve_uri()

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()

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()

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.
void print(void *str)
Definition bridge.cpp:126