blob: c0d321c9ba64a3cc548253aefa2a2d2ec5a73cae [file] [log] [blame]
nednguyen4b719ca2018-09-07 08:51:29 -04001#!/usr/bin/env python
Zhenyao Mo72712b02018-08-23 15:55:12 -07002# Copyright 2018 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Generate BUILD.gn to define all data required to run telemetry test.
7
8If a file/folder of large size is added to catapult but is not needed to run
9telemetry test, then it should be added to the EXCLUDED_PATHS below and rerun
10this script.
11
12This script can also run with --check to see if it needs to rerun to update
13BUILD.gn.
14
15This script can also run with --chromium and rewrite the chromium file
16 //tools/perf/chrome_telemetry_build/BUILD.gn
17This is for the purpose of running try jobs in chromium.
18
19"""
20
21import difflib
22import logging
23import os
24import optparse
25import sys
26
27LICENSE = """# Copyright 2018 The Chromium Authors. All rights reserved.
28# Use of this source code is governed by a BSD-style license that can be
29# found in the LICENSE file.
30
31"""
32
33DO_NOT_EDIT_WARNING = """# This file is auto-generated from
34# //third_party/catapult/generated_telemetry_build.py
35# DO NOT EDIT!
36
37"""
38
39TELEMETRY_SUPPORT_GROUP_NAME = 'telemetry_chrome_test_support'
40
41EXCLUDED_PATHS = [
42 {
43 # needed for --chromium option; can remove once this CL lands.
44 "path": "BUILD.gn",
45 },
46 {
Zhenyao Moc54a6eb2018-08-29 10:06:31 -070047 "path": "common/node_runner",
Zhenyao Mobc2c0a92018-08-24 14:26:04 -070048 },
49 {
50 "path": "docs",
51 },
52 {
53 "path": "experimental",
54 },
55 {
Zhenyao Mo72712b02018-08-23 15:55:12 -070056 # needed for --chromium option; can remove once this CL lands.
57 "path": "generate_telemetry_build.py",
58 },
59 {
Zhenyao Mob18e8eb2018-08-28 16:43:56 -070060 "path": "telemetry/telemetry/data",
61 },
62 {
Zhenyao Mo72712b02018-08-23 15:55:12 -070063 "path": "telemetry/telemetry/bin",
64 },
65 {
66 "path": "telemetry/telemetry/internal/bin",
67 },
68 {
69 # needed for --check option
70 "path": "TEMP.gn",
71 },
72 {
73 "path": "third_party/google-endpoints",
74 },
75 {
76 "path": "third_party/Paste",
77 },
78 {
79 "path": "third_party/polymer2",
80 },
81 {
82 "path": "third_party/vinn/third_party/v8/linux/arm",
83 "condition": "is_chromeos",
84 },
85 {
86 "path": "third_party/vinn/third_party/v8/linux/mips",
87 "condition": "is_chromeos",
88 },
89 {
90 "path": "third_party/vinn/third_party/v8/linux/mips64",
91 "condition": "is_chromeos",
92 },
93 {
94 "path": "third_party/vinn/third_party/v8/linux/x86_64",
95 "condition": "is_linux || is_android",
96 },
97 {
98 "path": "third_party/vinn/third_party/v8/mac",
99 "condition": "is_mac",
100 },
101 {
102 "path": "third_party/vinn/third_party/v8/win",
103 "condition": "is_win",
104 },
105 {
106 "path": "tracing/test_data",
107 },
108]
109
110def GetFileCondition(rel_path):
111 # Return 'true' if the file should be included; return 'false' if it should
112 # be excluded; return a condition string if it should only be included if
113 # the condition is true.
114 processed_rel_path = rel_path.replace('\\', '/')
115 for exclusion in EXCLUDED_PATHS:
116 assert 'path' in exclusion
117 if exclusion['path'] == processed_rel_path:
118 if 'condition' in exclusion:
119 return exclusion['condition']
120 else:
121 return 'false'
122 return 'true'
123
124def GetDirCondition(rel_path):
125 # Return 'true' if the dir should be included; return 'false' if it should
126 # be excluded; return a condition string if it should only be included if
127 # the condition is true; return 'expand' if some files or sub-dirs under it
128 # are excluded or conditionally included, so the parser needs to go inside
129 # the dir and process further.
130 processed_rel_path = rel_path.replace('\\', '/')
131 for exclusion in EXCLUDED_PATHS:
132 assert 'path' in exclusion
133 if exclusion['path'] == processed_rel_path:
134 if 'condition' in exclusion:
135 return exclusion['condition']
136 else:
137 return 'false'
138 elif exclusion['path'].startswith(processed_rel_path + '/'):
139 return 'expand'
140 return 'true'
141
142def WriteLists(lists, conditional_lists, build_file, path_prefix):
143 first_entry = True
144 for path_list in lists:
145 for path in path_list:
146 path = path.replace('\\', '/')
147 if path_prefix:
148 path = path_prefix + path
149 if first_entry:
150 build_file.write(' data += [\n')
151 first_entry = False
152 build_file.write(' "%s",\n' % path)
153 if not first_entry:
154 build_file.write(' ]\n\n')
155 for conditional_list in conditional_lists:
156 for entry in conditional_list:
157 assert 'path' in entry
158 assert 'condition' in entry
159 path = entry['path'].replace('\\', '/')
160 if path_prefix:
161 path = path_prefix + path
162 build_file.write(""" if (%s) {
163 data += [ "%s" ]
164 }
165
166""" % (entry['condition'], path))
167
168def ProcessDir(root_path, path, build_file, path_prefix):
169 # Write all dirs and files directly under |path| unless they are excluded
170 # or need to be processed further because some of their children are excldued
171 # or conditionally included.
172 # Return a list of dirs that needs to processed further.
173 logging.debug('GenerateList for ' + path)
174 entry_list = os.listdir(path)
Zhenyao Mob18e8eb2018-08-28 16:43:56 -0700175 entry_list.sort()
Zhenyao Mo72712b02018-08-23 15:55:12 -0700176 file_list = []
177 dir_list = []
178 conditional_list = []
179 expand_list = []
180 for entry in entry_list:
181 full_path = os.path.join(path, entry)
182 rel_path = os.path.relpath(full_path, root_path)
Zhenyao Mo074cebc2018-08-27 11:31:05 -0700183 if (entry.startswith('.') or entry.endswith('~') or
184 entry.endswith('.pyc') or entry.endswith('#')):
Zhenyao Mo72712b02018-08-23 15:55:12 -0700185 logging.debug('ignored ' + rel_path)
186 continue
187 if os.path.isfile(full_path):
188 condition = GetFileCondition(rel_path)
189 if condition == 'true':
190 file_list.append(rel_path)
191 elif condition == 'false':
192 logging.debug('excluded ' + rel_path)
193 continue
194 else:
195 conditional_list.append({
196 "condition": condition,
197 "path": rel_path,
198 });
199 elif os.path.isdir(full_path):
200 condition = GetDirCondition(rel_path)
201 if condition == 'true':
202 dir_list.append(rel_path + '/')
203 elif condition == 'false':
204 logging.debug('excluded ' + rel_path)
205 elif condition == 'expand':
206 expand_list.append(full_path)
207 else:
208 conditional_list.append({
209 "condition": condition,
210 "path": rel_path + '/',
211 });
212 else:
213 assert False
Zhenyao Mo72712b02018-08-23 15:55:12 -0700214 WriteLists([file_list, dir_list], [conditional_list],
215 build_file, path_prefix)
216 return expand_list
217
218def WriteBuildFileHeader(build_file):
219 build_file.write(LICENSE)
220 build_file.write(DO_NOT_EDIT_WARNING)
221 build_file.write('import("//build/config/compiler/compiler.gni")\n\n')
222
223def WriteBuildFileBody(build_file, root_path, path_prefix):
224 build_file.write("""group("%s") {
225 testonly = true
226 data = []
227
228""" % TELEMETRY_SUPPORT_GROUP_NAME)
229
230 candidates = [root_path]
231 while len(candidates) > 0:
232 candidate = candidates.pop(0)
233 more = ProcessDir(root_path, candidate, build_file, path_prefix)
234 candidates.extend(more)
235
236 build_file.write("}")
237
238def GenerateBuildFile(root_path, output_path, chromium):
239 CHROMIUM_GROUP = 'group("telemetry_chrome_test_without_chrome")'
240 CATAPULT_PREFIX = '//third_party/catapult'
241 CATAPULT_GROUP_NAME = CATAPULT_PREFIX + ':' + TELEMETRY_SUPPORT_GROUP_NAME
242 TELEMETRY_SUPPORT_GROUP = 'group("%s")' % TELEMETRY_SUPPORT_GROUP_NAME
243 if chromium:
244 build_file = open(output_path, 'r+')
245 contents = build_file.readlines()
246 build_file.seek(0)
247 remove_telemetry_support_group = False
248 for line in contents:
249 if TELEMETRY_SUPPORT_GROUP in line:
250 # --chromium has already run once, so remove the previously inserted
251 # TELEMETRY_SUPPORT_GROUP so we could add an updated one.
252 remove_telemetry_support_group = True
253 continue
254 if remove_telemetry_support_group:
255 if line == '}\n':
256 remove_telemetry_support_group = False
257 continue
258 if CHROMIUM_GROUP in line:
259 WriteBuildFileBody(build_file, root_path, CATAPULT_PREFIX + '/')
260 build_file.write('\n')
261 elif CATAPULT_GROUP_NAME in line:
262 line = line.replace(CATAPULT_GROUP_NAME,
263 ':' + TELEMETRY_SUPPORT_GROUP_NAME)
264 build_file.write(line)
265 build_file.close()
266 else:
267 build_file = open(output_path, 'w')
268 WriteBuildFileHeader(build_file)
269 WriteBuildFileBody(build_file, root_path, None)
270 build_file.close()
271
272def CheckForChanges():
Zhenyao Mo074cebc2018-08-27 11:31:05 -0700273 # Return 0 if no changes are detected; return 1 otherwise.
Zhenyao Mo72712b02018-08-23 15:55:12 -0700274 root_path = os.path.dirname(os.path.realpath(__file__))
275 temp_path = os.path.join(root_path, "TEMP.gn")
276 GenerateBuildFile(root_path, temp_path, chromium=False)
277
278 ref_path = os.path.join(root_path, "BUILD.gn")
279 if not os.path.exists(ref_path):
280 logging.error("Can't localte BUILD.gn!")
Zhenyao Mo074cebc2018-08-27 11:31:05 -0700281 return 1
Zhenyao Mo72712b02018-08-23 15:55:12 -0700282
283 temp_file = open(temp_path, 'r')
284 temp_content = temp_file.readlines()
285 temp_file.close()
286 os.remove(temp_path)
287 ref_file = open(ref_path, 'r')
288 ref_content = ref_file.readlines()
289 ref_file.close()
290
291 diff = difflib.unified_diff(temp_content, ref_content, fromfile=temp_path,
292 tofile=ref_path, lineterm='')
293 diff_data = []
294 for line in diff:
295 diff_data.append(line)
296 if len(diff_data) > 0:
297 logging.error('Diff found. Please rerun generate_telemetry_build.py.')
298 logging.debug('\n' + ''.join(diff_data))
Zhenyao Mo074cebc2018-08-27 11:31:05 -0700299 return 1
Zhenyao Mo72712b02018-08-23 15:55:12 -0700300 logging.debug('No diff found. Everything is good.')
Zhenyao Mo074cebc2018-08-27 11:31:05 -0700301 return 0
Zhenyao Mo72712b02018-08-23 15:55:12 -0700302
303
304def main(argv):
305 parser = optparse.OptionParser()
306 parser.add_option("-v", "--verbose", action="store_true", default=False,
307 help="print out debug information")
308 parser.add_option("-c", "--check", action="store_true", default=False,
309 help="generate a temporary build file and compare if it "
310 "is the same as the current BUILD.gn")
311 parser.add_option("--chromium", action="store_true", default=False,
312 help="generate the build file into chromium workspace. "
313 "This is for the purpose of running try jobs in Chrome.")
314 (options, _) = parser.parse_args(args=argv)
315 if options.verbose:
316 logging.basicConfig(level=logging.DEBUG)
317
318 if options.check:
Zhenyao Mo074cebc2018-08-27 11:31:05 -0700319 return CheckForChanges()
320 if options.chromium:
Zhenyao Mo72712b02018-08-23 15:55:12 -0700321 root_path = os.path.dirname(os.path.realpath(__file__))
322 output_path = os.path.join(
323 root_path, "../../tools/perf/chrome_telemetry_build/BUILD.gn")
324 GenerateBuildFile(root_path, output_path, chromium=True)
325 else:
326 root_path = os.path.dirname(os.path.realpath(__file__))
327 output_path = os.path.join(root_path, "BUILD.gn")
328 GenerateBuildFile(root_path, output_path, chromium=False)
Zhenyao Mo074cebc2018-08-27 11:31:05 -0700329 return 0
Zhenyao Mo72712b02018-08-23 15:55:12 -0700330
331if __name__ == '__main__':
332 sys.exit(main(sys.argv[1:]))