blob: 344341010c2a9a289c304e3cb752c3b0f88a854f [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
nednguyenfebcf872018-09-07 14:19:11 -040026import subprocess
John Budoricka9c4beb2019-04-24 10:45:35 -070027import textwrap
Zhenyao Mo72712b02018-08-23 15:55:12 -070028
John Budoricka9c4beb2019-04-24 10:45:35 -070029LICENSE = textwrap.dedent(
30 """\
31 # Copyright 2018 The Chromium Authors. All rights reserved.
32 # Use of this source code is governed by a BSD-style license that can be
33 # found in the LICENSE file.
Zhenyao Mo72712b02018-08-23 15:55:12 -070034
John Budoricka9c4beb2019-04-24 10:45:35 -070035 """)
Zhenyao Mo72712b02018-08-23 15:55:12 -070036
John Budoricka9c4beb2019-04-24 10:45:35 -070037DO_NOT_EDIT_WARNING = textwrap.dedent(
38 """\
39 # This file is auto-generated from
40 # //third_party/catapult/generated_telemetry_build.py
41 # DO NOT EDIT!
Zhenyao Mo72712b02018-08-23 15:55:12 -070042
John Budoricka9c4beb2019-04-24 10:45:35 -070043 """)
Zhenyao Mo72712b02018-08-23 15:55:12 -070044
45TELEMETRY_SUPPORT_GROUP_NAME = 'telemetry_chrome_test_support'
46
John Budoricka9c4beb2019-04-24 10:45:35 -070047EXCLUDED_PATHS = {
48 'BUILD.gn',
49 'TEMP.gn',
50 'common/node_runner/',
51 'docs/',
52 'experimental/',
53 'generate_telemetry_build.py',
John Budoricka9c4beb2019-04-24 10:45:35 -070054 'third_party/Paste/',
55 'third_party/google-endpoints/',
56 'third_party/polymer2/',
57 'tracing/test_data/',
58}
59
60
61SEPARATE_TARGETS = {
John Budorick6ea34cc2019-05-16 11:55:56 -070062 'devil': 'devil',
63 'telemetry': 'telemetry',
64 'third_party/gsutil': 'third_party/gsutil',
65 'third_party/typ': 'third_party/typ',
John Budoricka9c4beb2019-04-24 10:45:35 -070066 'third_party/vinn': 'third_party/vinn',
67}
Zhenyao Mo72712b02018-08-23 15:55:12 -070068
nednguyenfebcf872018-09-07 14:19:11 -040069
70def GetUntrackedPaths():
71 """Return directories/files in catapult/ that are not tracked by git."""
72 output = subprocess.check_output([
73 'git', 'ls-files', '--others', '--exclude-standard', '--directory',
74 '--full-name'])
75 paths = output.split('\n')
76 return [os.path.abspath(p) for p in paths if p]
77
78
John Budoricka9c4beb2019-04-24 10:45:35 -070079def WriteLists(data, data_deps, build_file, path_prefix):
80 if data:
81 build_file.write(' data += [\n')
82 for path in data:
Zhenyao Mo72712b02018-08-23 15:55:12 -070083 if path_prefix:
84 path = path_prefix + path
Zhenyao Mo72712b02018-08-23 15:55:12 -070085 build_file.write(' "%s",\n' % path)
Zhenyao Mo72712b02018-08-23 15:55:12 -070086 build_file.write(' ]\n\n')
Zhenyao Mo72712b02018-08-23 15:55:12 -070087
John Budoricka9c4beb2019-04-24 10:45:35 -070088 if data_deps:
89 build_file.write(' data_deps += [\n')
90 for data_dep in data_deps:
91 build_file.write(' "%s",\n' % data_dep)
92 build_file.write(' ]\n\n')
93
Zhenyao Mo72712b02018-08-23 15:55:12 -070094
95def ProcessDir(root_path, path, build_file, path_prefix):
96 # Write all dirs and files directly under |path| unless they are excluded
John Budoricka9c4beb2019-04-24 10:45:35 -070097 # or need to be processed further because some of their children are excluded.
Zhenyao Mo72712b02018-08-23 15:55:12 -070098 # Return a list of dirs that needs to processed further.
99 logging.debug('GenerateList for ' + path)
John Budoricka9c4beb2019-04-24 10:45:35 -0700100 entries = os.listdir(path)
101 entries.sort()
102 files = []
103 dirs = []
104 data_deps = []
105 dirs_to_expand = []
nednguyenfebcf872018-09-07 14:19:11 -0400106 untracked_paths = GetUntrackedPaths()
John Budoricka9c4beb2019-04-24 10:45:35 -0700107 for entry in entries:
Zhenyao Mo72712b02018-08-23 15:55:12 -0700108 full_path = os.path.join(path, entry)
John Budoricka9c4beb2019-04-24 10:45:35 -0700109 rel_path = os.path.relpath(full_path, root_path).replace('\\', '/')
nednguyenfebcf872018-09-07 14:19:11 -0400110 if (any(full_path.startswith(p) for p in untracked_paths) or
111 entry.startswith('.') or entry.endswith('~') or
Zhenyao Mo074cebc2018-08-27 11:31:05 -0700112 entry.endswith('.pyc') or entry.endswith('#')):
nednguyenfebcf872018-09-07 14:19:11 -0400113 logging.debug('ignored %s', rel_path)
Zhenyao Mo72712b02018-08-23 15:55:12 -0700114 continue
John Budoricka9c4beb2019-04-24 10:45:35 -0700115 if rel_path in SEPARATE_TARGETS:
116 data_deps.append(SEPARATE_TARGETS[rel_path])
117 elif os.path.isfile(full_path):
118 if rel_path in EXCLUDED_PATHS:
nednguyenfebcf872018-09-07 14:19:11 -0400119 logging.debug('excluded %s', rel_path)
Zhenyao Mo72712b02018-08-23 15:55:12 -0700120 else:
John Budoricka9c4beb2019-04-24 10:45:35 -0700121 files.append(rel_path)
Zhenyao Mo72712b02018-08-23 15:55:12 -0700122 elif os.path.isdir(full_path):
John Budoricka9c4beb2019-04-24 10:45:35 -0700123 rel_path = rel_path + '/'
124 if rel_path in EXCLUDED_PATHS:
nednguyenfebcf872018-09-07 14:19:11 -0400125 logging.debug('excluded %s', rel_path)
John Budoricka9c4beb2019-04-24 10:45:35 -0700126 elif any(e.startswith(rel_path) for e in EXCLUDED_PATHS):
127 dirs_to_expand.append(full_path)
Zhenyao Mo72712b02018-08-23 15:55:12 -0700128 else:
John Budoricka9c4beb2019-04-24 10:45:35 -0700129 dirs.append(rel_path)
Zhenyao Mo72712b02018-08-23 15:55:12 -0700130 else:
131 assert False
John Budoricka9c4beb2019-04-24 10:45:35 -0700132 WriteLists(files + dirs,
133 data_deps,
Zhenyao Mo72712b02018-08-23 15:55:12 -0700134 build_file, path_prefix)
John Budoricka9c4beb2019-04-24 10:45:35 -0700135 return dirs_to_expand
Zhenyao Mo72712b02018-08-23 15:55:12 -0700136
137def WriteBuildFileHeader(build_file):
138 build_file.write(LICENSE)
139 build_file.write(DO_NOT_EDIT_WARNING)
140 build_file.write('import("//build/config/compiler/compiler.gni")\n\n')
141
142def WriteBuildFileBody(build_file, root_path, path_prefix):
John Budoricka9c4beb2019-04-24 10:45:35 -0700143 build_file.write(textwrap.dedent(
144 """\
145 group("%s") {
146 testonly = true
147 data = []
148 data_deps = []
Zhenyao Mo72712b02018-08-23 15:55:12 -0700149
John Budoricka9c4beb2019-04-24 10:45:35 -0700150 """ % TELEMETRY_SUPPORT_GROUP_NAME))
Zhenyao Mo72712b02018-08-23 15:55:12 -0700151
152 candidates = [root_path]
153 while len(candidates) > 0:
154 candidate = candidates.pop(0)
155 more = ProcessDir(root_path, candidate, build_file, path_prefix)
156 candidates.extend(more)
157
158 build_file.write("}")
159
160def GenerateBuildFile(root_path, output_path, chromium):
161 CHROMIUM_GROUP = 'group("telemetry_chrome_test_without_chrome")'
162 CATAPULT_PREFIX = '//third_party/catapult'
163 CATAPULT_GROUP_NAME = CATAPULT_PREFIX + ':' + TELEMETRY_SUPPORT_GROUP_NAME
164 TELEMETRY_SUPPORT_GROUP = 'group("%s")' % TELEMETRY_SUPPORT_GROUP_NAME
165 if chromium:
166 build_file = open(output_path, 'r+')
167 contents = build_file.readlines()
168 build_file.seek(0)
169 remove_telemetry_support_group = False
170 for line in contents:
171 if TELEMETRY_SUPPORT_GROUP in line:
172 # --chromium has already run once, so remove the previously inserted
173 # TELEMETRY_SUPPORT_GROUP so we could add an updated one.
174 remove_telemetry_support_group = True
175 continue
176 if remove_telemetry_support_group:
177 if line == '}\n':
178 remove_telemetry_support_group = False
179 continue
180 if CHROMIUM_GROUP in line:
181 WriteBuildFileBody(build_file, root_path, CATAPULT_PREFIX + '/')
182 build_file.write('\n')
183 elif CATAPULT_GROUP_NAME in line:
184 line = line.replace(CATAPULT_GROUP_NAME,
185 ':' + TELEMETRY_SUPPORT_GROUP_NAME)
186 build_file.write(line)
187 build_file.close()
188 else:
189 build_file = open(output_path, 'w')
190 WriteBuildFileHeader(build_file)
191 WriteBuildFileBody(build_file, root_path, None)
192 build_file.close()
193
194def CheckForChanges():
Zhenyao Mo074cebc2018-08-27 11:31:05 -0700195 # Return 0 if no changes are detected; return 1 otherwise.
Zhenyao Mo72712b02018-08-23 15:55:12 -0700196 root_path = os.path.dirname(os.path.realpath(__file__))
197 temp_path = os.path.join(root_path, "TEMP.gn")
198 GenerateBuildFile(root_path, temp_path, chromium=False)
199
200 ref_path = os.path.join(root_path, "BUILD.gn")
201 if not os.path.exists(ref_path):
202 logging.error("Can't localte BUILD.gn!")
Zhenyao Mo074cebc2018-08-27 11:31:05 -0700203 return 1
Zhenyao Mo72712b02018-08-23 15:55:12 -0700204
205 temp_file = open(temp_path, 'r')
206 temp_content = temp_file.readlines()
207 temp_file.close()
208 os.remove(temp_path)
209 ref_file = open(ref_path, 'r')
210 ref_content = ref_file.readlines()
211 ref_file.close()
212
213 diff = difflib.unified_diff(temp_content, ref_content, fromfile=temp_path,
214 tofile=ref_path, lineterm='')
215 diff_data = []
216 for line in diff:
217 diff_data.append(line)
218 if len(diff_data) > 0:
219 logging.error('Diff found. Please rerun generate_telemetry_build.py.')
220 logging.debug('\n' + ''.join(diff_data))
Zhenyao Mo074cebc2018-08-27 11:31:05 -0700221 return 1
Zhenyao Mo72712b02018-08-23 15:55:12 -0700222 logging.debug('No diff found. Everything is good.')
Zhenyao Mo074cebc2018-08-27 11:31:05 -0700223 return 0
Zhenyao Mo72712b02018-08-23 15:55:12 -0700224
225
226def main(argv):
227 parser = optparse.OptionParser()
228 parser.add_option("-v", "--verbose", action="store_true", default=False,
229 help="print out debug information")
230 parser.add_option("-c", "--check", action="store_true", default=False,
231 help="generate a temporary build file and compare if it "
232 "is the same as the current BUILD.gn")
233 parser.add_option("--chromium", action="store_true", default=False,
234 help="generate the build file into chromium workspace. "
235 "This is for the purpose of running try jobs in Chrome.")
236 (options, _) = parser.parse_args(args=argv)
237 if options.verbose:
238 logging.basicConfig(level=logging.DEBUG)
239
240 if options.check:
Zhenyao Mo074cebc2018-08-27 11:31:05 -0700241 return CheckForChanges()
242 if options.chromium:
Zhenyao Mo72712b02018-08-23 15:55:12 -0700243 root_path = os.path.dirname(os.path.realpath(__file__))
244 output_path = os.path.join(
245 root_path, "../../tools/perf/chrome_telemetry_build/BUILD.gn")
246 GenerateBuildFile(root_path, output_path, chromium=True)
247 else:
248 root_path = os.path.dirname(os.path.realpath(__file__))
249 output_path = os.path.join(root_path, "BUILD.gn")
250 GenerateBuildFile(root_path, output_path, chromium=False)
Zhenyao Mo074cebc2018-08-27 11:31:05 -0700251 return 0
Zhenyao Mo72712b02018-08-23 15:55:12 -0700252
253if __name__ == '__main__':
254 sys.exit(main(sys.argv[1:]))