blob: a726e1edd04cfa7b1ef22ea097b80e54b77404ec [file] [log] [blame]
Ian Zernydcb172e2022-02-22 15:36:45 +01001#!/usr/bin/env python3
Rico Wind800fd712018-09-24 11:29:33 +02002# Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
3# for details. All rights reserved. Use of this source code is governed by a
4# BSD-style license that can be found in the LICENSE file.
5
6# Run all internal tests, archive result to cloud storage.
Rico Wind139eece2018-09-25 09:42:09 +02007# In the continuous operation flow we have a tester continuously checking
8# a specific cloud storage location for a file with a git hash.
9# If the file is there, the tester will remove the file, and add another
10# file stating that this is now being run. After successfully running,
11# the tester will add yet another file, and remove the last one.
12# Complete flow with states:
13# 1:
14# BOT:
15# Add file READY_FOR_TESTING (contains git hash)
16# Wait until file TESTING_COMPLETE exists (contains git hash)
17# Timeout if no progress for RUN_TIMEOUT
18# Cleanup READY_FOR_TESTING and TESTING
19# 2:
20# TESTER:
21# Replace file READY_FOR_TESTING by TESTING (contains git hash)
22# Run tests for git hash
23# Upload commit specific logs if failures
24# Upload git specific overall status file (failed or succeeded)
25# Replace file TESTING by TESTING_COMPLETE (contains git hash)
26# 3:
27# BOT:
28# Read overall status
29# Delete TESTING_COMPLETE
30# Exit based on status
Rico Wind800fd712018-09-24 11:29:33 +020031
Rico Windba63dc82019-03-29 14:33:47 +010032import gradle
Rico Wind800fd712018-09-24 11:29:33 +020033import optparse
34import os
35import subprocess
36import sys
37import time
38import utils
Morten Krogh-Jespersenf2412302019-10-22 10:18:04 +020039import run_on_app
Rico Wind800fd712018-09-24 11:29:33 +020040
Christoffer Quist Adamsen81d41502021-06-25 09:33:43 +020041import chrome_data
42import iosched_data
43import r8_data
Christoffer Quist Adamsen4380de32021-04-23 06:24:31 +020044import youtube_data
45
Rico Wind139eece2018-09-25 09:42:09 +020046# How often the bot/tester should check state
47PULL_DELAY = 30
Rico Wind800fd712018-09-24 11:29:33 +020048TEST_RESULT_DIR = 'internal'
49
Rico Wind139eece2018-09-25 09:42:09 +020050# Magic files
51READY_FOR_TESTING = 'READY_FOR_TESTING'
52TESTING = 'TESTING'
53TESTING_COMPLETE = 'TESTING_COMPLETE'
54
55ALL_MAGIC = [READY_FOR_TESTING, TESTING, TESTING_COMPLETE]
56
57# Log file names
58STDERR = 'stderr'
59STDOUT = 'stdout'
60EXITCODE = 'exitcode'
61TIMED_OUT = 'timed_out'
62
Christoffer Quist Adamsen81d41502021-06-25 09:33:43 +020063BENCHMARK_APPS = [chrome_data, iosched_data, r8_data, youtube_data]
Morten Krogh-Jespersen6cd9f1d2019-10-09 14:01:04 +020064
Christoffer Quist Adamsen81d41502021-06-25 09:33:43 +020065def find_min_xmx_command(app_data):
66 record = app_data.GetMemoryData(app_data.GetLatestVersion())
Jinseong Jeond28cb582019-10-15 00:01:40 -070067 assert record['find-xmx-min'] < record['find-xmx-max']
68 assert record['find-xmx-range'] < record['find-xmx-max'] - record['find-xmx-min']
Morten Krogh-Jespersen6cd9f1d2019-10-09 14:01:04 +020069 return [
70 'tools/run_on_app.py',
71 '--compiler=r8',
72 '--compiler-build=lib',
Christoffer Quist Adamsen81d41502021-06-25 09:33:43 +020073 '--app=%s' % app_data.GetName(),
74 '--version=%s' % app_data.GetLatestVersion(),
Morten Krogh-Jespersen6cd9f1d2019-10-09 14:01:04 +020075 '--no-debug',
76 '--no-build',
77 '--find-min-xmx',
78 '--find-min-xmx-min-memory=%s' % record['find-xmx-min'],
79 '--find-min-xmx-max-memory=%s' % record['find-xmx-max'],
80 '--find-min-xmx-range-size=%s' % record['find-xmx-range'],
81 '--find-min-xmx-archive']
82
Christoffer Quist Adamsen81d41502021-06-25 09:33:43 +020083def compile_with_memory_max_command(app_data):
Morten Krogh-Jespersena0cc49f2020-04-17 08:39:59 +020084 # TODO(b/152939233): Remove this special handling when fixed.
Christoffer Quist Adamsen81d41502021-06-25 09:33:43 +020085 factor = 1.25 if app_data.GetName() == 'chrome' else 1.15
86 record = app_data.GetMemoryData(app_data.GetLatestVersion())
Morten Krogh-Jespersenb042c972019-11-04 08:57:59 +010087 return [] if 'skip-find-xmx-max' in record else [
Morten Krogh-Jespersen3793dc92019-10-09 14:48:48 +020088 'tools/run_on_app.py',
89 '--compiler=r8',
90 '--compiler-build=lib',
Christoffer Quist Adamsen81d41502021-06-25 09:33:43 +020091 '--app=%s' % app_data.GetName(),
92 '--version=%s' % app_data.GetLatestVersion(),
Morten Krogh-Jespersen3793dc92019-10-09 14:48:48 +020093 '--no-debug',
94 '--no-build',
Morten Krogh-Jespersena0cc49f2020-04-17 08:39:59 +020095 '--max-memory=%s' % int(record['oom-threshold'] * factor)
Morten Krogh-Jespersen3793dc92019-10-09 14:48:48 +020096 ]
97
Christoffer Quist Adamsen81d41502021-06-25 09:33:43 +020098def compile_with_memory_min_command(app_data):
99 record = app_data.GetMemoryData(app_data.GetLatestVersion())
Morten Krogh-Jespersen3793dc92019-10-09 14:48:48 +0200100 return [
101 'tools/run_on_app.py',
102 '--compiler=r8',
103 '--compiler-build=lib',
Christoffer Quist Adamsen81d41502021-06-25 09:33:43 +0200104 '--app=%s' % app_data.GetName(),
105 '--version=%s' % app_data.GetLatestVersion(),
Morten Krogh-Jespersen3793dc92019-10-09 14:48:48 +0200106 '--no-debug',
107 '--no-build',
108 '--expect-oom',
Morten Krogh-Jespersen092e9712019-10-24 14:06:32 +0200109 '--max-memory=%s' % int(record['oom-threshold'] * 0.85)
Morten Krogh-Jespersen3793dc92019-10-09 14:48:48 +0200110 ]
111
Morten Krogh-Jespersenfcb06452021-12-16 15:19:49 +0100112# TODO(b/210982978): Enable testing of min xmx again
Rico Wind6847d132018-09-26 08:18:48 +0200113TEST_COMMANDS = [
Rico Wind5a360e92022-03-31 08:49:25 +0200114 # Make sure we have a clean build to not be polluted by old test files
115 ['tools/gradle.py', 'clean'],
Morten Krogh-Jespersen2243b162019-01-14 08:40:53 +0100116 # Run test.py internal testing.
Rico Winde623bf32019-08-28 09:28:00 +0200117 ['tools/test.py', '--only_internal', '--slow_tests',
Rico Wind97b0a992019-08-30 11:09:15 +0200118 '--java_max_memory_size=8G'],
Morten Krogh-Jespersen2243b162019-01-14 08:40:53 +0100119 # Ensure that all internal apps compile.
Morten Krogh-Jespersen82bde822019-10-09 14:50:35 +0200120 ['tools/run_on_app.py', '--run-all', '--out=out'],
Morten Krogh-Jespersen6cd9f1d2019-10-09 14:01:04 +0200121 # Find min xmx for selected benchmark apps
122 ['tools/gradle.py', 'r8lib'],
Morten Krogh-Jespersenfcb06452021-12-16 15:19:49 +0100123]
Morten Krogh-Jespersen3793dc92019-10-09 14:48:48 +0200124
Rico Wind6847d132018-09-26 08:18:48 +0200125# Command timeout, in seconds.
Rico Windf77c5b92019-06-11 08:50:41 +0200126RUN_TIMEOUT = 3600 * 6
Rico Windf021d832018-12-13 11:29:22 +0100127BOT_RUN_TIMEOUT = RUN_TIMEOUT * len(TEST_COMMANDS)
Rico Wind6847d132018-09-26 08:18:48 +0200128
Rico Wind1200f512018-09-26 08:48:37 +0200129def log(str):
Rico Windffccab12018-09-26 12:39:42 +0200130 print("%s: %s" % (time.strftime("%c"), str))
Rico Wind1b09c562019-01-17 08:53:09 +0100131 sys.stdout.flush()
Rico Wind1200f512018-09-26 08:48:37 +0200132
Rico Wind800fd712018-09-24 11:29:33 +0200133def ParseOptions():
134 result = optparse.OptionParser()
135 result.add_option('--continuous',
136 help='Continuously run internal tests and post results to GCS.',
137 default=False, action='store_true')
Rico Wind4fd2dda2018-09-26 17:41:45 +0200138 result.add_option('--print_logs',
139 help='Fetch logs from gcs and print them, takes the commit to print for.',
140 default=None)
Rico Wind139eece2018-09-25 09:42:09 +0200141 result.add_option('--bot',
142 help='Run in bot mode, i.e., scheduling runs.',
143 default=False, action='store_true')
Rico Wind800fd712018-09-24 11:29:33 +0200144 result.add_option('--archive',
145 help='Post result to GCS, implied by --continuous',
146 default=False, action='store_true')
147 return result.parse_args()
148
Christoffer Quist Adamsen81d41502021-06-25 09:33:43 +0200149def get_file_contents():
150 contents = []
Rico Wind800fd712018-09-24 11:29:33 +0200151 with open(sys.argv[0], 'r') as us:
Christoffer Quist Adamsen81d41502021-06-25 09:33:43 +0200152 contents.append(us.read())
153 for app_data in BENCHMARK_APPS:
154 with open(app_data.__file__, 'r') as us:
155 contents.append(us.read())
156 return contents
Rico Wind800fd712018-09-24 11:29:33 +0200157
Christoffer Quist Adamsen81d41502021-06-25 09:33:43 +0200158def restart_if_new_version(original_contents):
159 new_contents = get_file_contents()
160 log('Lengths %s %s' % (
161 [len(data) for data in original_contents],
162 [len(data) for data in new_contents]))
Rico Wind1b52acf2021-03-21 12:36:55 +0100163 log('is main %s ' % utils.is_main())
Rico Wind1b09c562019-01-17 08:53:09 +0100164 # Restart if the script got updated.
Christoffer Quist Adamsen81d41502021-06-25 09:33:43 +0200165 if new_contents != original_contents:
Rico Wind1200f512018-09-26 08:48:37 +0200166 log('Restarting tools/internal_test.py, content changed')
Rico Wind800fd712018-09-24 11:29:33 +0200167 os.execv(sys.argv[0], sys.argv)
168
Rico Wind139eece2018-09-25 09:42:09 +0200169def ensure_git_clean():
Rico Wind800fd712018-09-24 11:29:33 +0200170 # Ensure clean git repo.
Rico Windfd186372022-02-28 08:55:48 +0100171 diff = subprocess.check_output(['git', 'diff']).decode('utf-8')
Rico Wind800fd712018-09-24 11:29:33 +0200172 if len(diff) > 0:
Rico Wind1200f512018-09-26 08:48:37 +0200173 log('Local modifications to the git repo, exiting')
Rico Wind800fd712018-09-24 11:29:33 +0200174 sys.exit(1)
Rico Wind139eece2018-09-25 09:42:09 +0200175
176def git_pull():
177 ensure_git_clean()
Rico Wind1b52acf2021-03-21 12:36:55 +0100178 subprocess.check_call(['git', 'checkout', 'main'])
Rico Wind800fd712018-09-24 11:29:33 +0200179 subprocess.check_call(['git', 'pull'])
180 return utils.get_HEAD_sha1()
181
Rico Wind139eece2018-09-25 09:42:09 +0200182def git_checkout(git_hash):
183 ensure_git_clean()
184 # Ensure that we are up to date to get the commit.
185 git_pull()
Rico Windd7d91062019-04-29 09:24:10 +0200186 exitcode = subprocess.call(['git', 'checkout', git_hash])
187 if exitcode != 0:
188 return None
Rico Wind139eece2018-09-25 09:42:09 +0200189 return utils.get_HEAD_sha1()
190
191def get_test_result_dir():
Rico Wind635b2de2022-04-25 10:35:14 +0200192 return os.path.join(utils.R8_INTERNAL_TEST_RESULTS_BUCKET, TEST_RESULT_DIR)
Rico Wind139eece2018-09-25 09:42:09 +0200193
Rico Wind800fd712018-09-24 11:29:33 +0200194def get_sha_destination(sha):
Rico Wind139eece2018-09-25 09:42:09 +0200195 return os.path.join(get_test_result_dir(), sha)
Rico Wind800fd712018-09-24 11:29:33 +0200196
197def archive_status(failed):
198 gs_destination = 'gs://%s' % get_sha_destination(utils.get_HEAD_sha1())
Morten Krogh-Jespersen0981b722019-10-09 10:00:33 +0200199 utils.archive_value('status', gs_destination, failed)
Rico Wind800fd712018-09-24 11:29:33 +0200200
Rico Wind139eece2018-09-25 09:42:09 +0200201def get_status(sha):
202 gs_destination = 'gs://%s/status' % get_sha_destination(sha)
203 return utils.cat_file_on_cloud_storage(gs_destination)
204
Rico Wind800fd712018-09-24 11:29:33 +0200205def archive_log(stdout, stderr, exitcode, timed_out, cmd):
206 sha = utils.get_HEAD_sha1()
Rico Wind139eece2018-09-25 09:42:09 +0200207 cmd_dir = cmd.replace(' ', '_').replace('/', '_')
Rico Wind800fd712018-09-24 11:29:33 +0200208 destination = os.path.join(get_sha_destination(sha), cmd_dir)
209 gs_destination = 'gs://%s' % destination
210 url = 'https://storage.cloud.google.com/%s' % destination
Rico Wind1200f512018-09-26 08:48:37 +0200211 log('Archiving logs to: %s' % gs_destination)
Morten Krogh-Jespersen0981b722019-10-09 10:00:33 +0200212 utils.archive_value(EXITCODE, gs_destination, exitcode)
213 utils.archive_value(TIMED_OUT, gs_destination, timed_out)
214 utils.archive_file(STDOUT, gs_destination, stdout)
215 utils.archive_file(STDERR, gs_destination, stderr)
Rico Wind1200f512018-09-26 08:48:37 +0200216 log('Logs available at: %s' % url)
Rico Wind800fd712018-09-24 11:29:33 +0200217
Rico Wind139eece2018-09-25 09:42:09 +0200218def get_magic_file_base_path():
219 return 'gs://%s/magic' % get_test_result_dir()
220
221def get_magic_file_gs_path(name):
222 return '%s/%s' % (get_magic_file_base_path(), name)
223
224def get_magic_file_exists(name):
225 return utils.file_exists_on_cloud_storage(get_magic_file_gs_path(name))
226
227def delete_magic_file(name):
228 utils.delete_file_from_cloud_storage(get_magic_file_gs_path(name))
229
230def put_magic_file(name, sha):
Morten Krogh-Jespersen0981b722019-10-09 10:00:33 +0200231 utils.archive_value(name, get_magic_file_base_path(), sha)
Rico Wind139eece2018-09-25 09:42:09 +0200232
233def get_magic_file_content(name, ignore_errors=False):
234 return utils.cat_file_on_cloud_storage(get_magic_file_gs_path(name),
235 ignore_errors=ignore_errors)
236
237def print_magic_file_state():
Rico Wind1200f512018-09-26 08:48:37 +0200238 log('Magic file status:')
Rico Wind139eece2018-09-25 09:42:09 +0200239 for magic in ALL_MAGIC:
240 if get_magic_file_exists(magic):
241 content = get_magic_file_content(magic, ignore_errors=True)
Rico Wind1200f512018-09-26 08:48:37 +0200242 log('%s content: %s' % (magic, content))
Rico Wind139eece2018-09-25 09:42:09 +0200243
Rico Wind4fd2dda2018-09-26 17:41:45 +0200244def fetch_and_print_logs(hash):
245 gs_base = 'gs://%s' % get_sha_destination(hash)
246 listing = utils.ls_files_on_cloud_storage(gs_base).strip().split('\n')
247 for entry in listing:
248 if not entry.endswith('/status'): # Ignore the overall status file
249 for to_print in [EXITCODE, TIMED_OUT, STDERR, STDOUT]:
250 gs_location = '%s%s' % (entry, to_print)
251 value = utils.cat_file_on_cloud_storage(gs_location)
252 print('\n\n%s had value:\n%s' % (to_print, value))
Morten Krogh-Jespersenf2412302019-10-22 10:18:04 +0200253 print("\n\nPrinting find-min-xmx ranges for apps")
254 run_on_app.print_min_xmx_ranges_for_hash(hash, 'r8', 'lib')
Rico Wind4fd2dda2018-09-26 17:41:45 +0200255
Rico Wind139eece2018-09-25 09:42:09 +0200256def run_bot():
257 print_magic_file_state()
258 # Ensure that there is nothing currently scheduled (broken/stopped run)
259 for magic in ALL_MAGIC:
260 if get_magic_file_exists(magic):
Rico Wind1200f512018-09-26 08:48:37 +0200261 log('ERROR: Synchronizing file %s exists, cleaning up' % magic)
Rico Wind139eece2018-09-25 09:42:09 +0200262 delete_magic_file(magic)
263 print_magic_file_state()
264 assert not get_magic_file_exists(READY_FOR_TESTING)
265 git_hash = utils.get_HEAD_sha1()
266 put_magic_file(READY_FOR_TESTING, git_hash)
267 begin = time.time()
268 while True:
269 if time.time() - begin > BOT_RUN_TIMEOUT:
Rico Wind1200f512018-09-26 08:48:37 +0200270 log('Timeout exceeded: http://go/internal-r8-doc')
Rico Wind139eece2018-09-25 09:42:09 +0200271 raise Exception('Bot timeout')
272 if get_magic_file_exists(TESTING_COMPLETE):
273 if get_magic_file_content(TESTING_COMPLETE) == git_hash:
274 break
275 else:
276 raise Exception('Non matching git hashes %s and %s' % (
277 get_magic_file_content(TESTING_COMPLETE), git_hash))
Rico Wind1200f512018-09-26 08:48:37 +0200278 log('Still waiting for test result')
Rico Wind139eece2018-09-25 09:42:09 +0200279 print_magic_file_state()
280 time.sleep(PULL_DELAY)
281 total_time = time.time()-begin
Rico Wind1200f512018-09-26 08:48:37 +0200282 log('Done running test for %s in %ss' % (git_hash, total_time))
Rico Wind139eece2018-09-25 09:42:09 +0200283 test_status = get_status(git_hash)
284 delete_magic_file(TESTING_COMPLETE)
Rico Wind1200f512018-09-26 08:48:37 +0200285 log('Test status is: %s' % test_status)
Rico Wind139eece2018-09-25 09:42:09 +0200286 if test_status != '0':
Rico Wind9e9449e2019-04-04 14:42:29 +0200287 print('Tests failed, you can print the logs by running(googlers only):')
Rico Wind1cb65e12019-04-26 08:54:17 +0200288 print(' tools/internal_test.py --print_logs %s' % git_hash)
Rico Wind139eece2018-09-25 09:42:09 +0200289 return 1
290
Rico Wind800fd712018-09-24 11:29:33 +0200291def run_continuously():
292 # If this script changes, we will restart ourselves
Christoffer Quist Adamsen81d41502021-06-25 09:33:43 +0200293 own_content = get_file_contents()
Rico Wind800fd712018-09-24 11:29:33 +0200294 while True:
295 restart_if_new_version(own_content)
Rico Wind139eece2018-09-25 09:42:09 +0200296 print_magic_file_state()
297 if get_magic_file_exists(READY_FOR_TESTING):
298 git_hash = get_magic_file_content(READY_FOR_TESTING)
299 checked_out = git_checkout(git_hash)
Rico Windd7d91062019-04-29 09:24:10 +0200300 if not checked_out:
301 # Gerrit change, we don't run these on internal.
302 archive_status(0)
303 put_magic_file(TESTING_COMPLETE, git_hash)
304 delete_magic_file(READY_FOR_TESTING)
305 continue
Rico Wind9519a152019-01-23 13:34:20 +0100306 # If the script changed, we need to restart now to get correct commands
307 # Note that we have not removed the READY_FOR_TESTING yet, so if we
308 # execv we will pick up the same version.
309 restart_if_new_version(own_content)
Rico Wind139eece2018-09-25 09:42:09 +0200310 # Sanity check, if this does not succeed stop.
311 if checked_out != git_hash:
Rico Wind1200f512018-09-26 08:48:37 +0200312 log('Inconsistent state: %s %s' % (git_hash, checked_out))
Rico Wind139eece2018-09-25 09:42:09 +0200313 sys.exit(1)
314 put_magic_file(TESTING, git_hash)
315 delete_magic_file(READY_FOR_TESTING)
Rico Wind1200f512018-09-26 08:48:37 +0200316 log('Running with hash: %s' % git_hash)
Rico Wind139eece2018-09-25 09:42:09 +0200317 exitcode = run_once(archive=True)
Rico Wind1200f512018-09-26 08:48:37 +0200318 log('Running finished with exit code %s' % exitcode)
Rico Windf5175ae2020-01-24 08:12:05 +0100319 # If the bot timed out or something else triggered the bot to fail, don't
320 # put up the result (it will not be displayed anywhere, and we can't
321 # remove the magic file if the bot cleaned up).
322 if get_magic_file_exists(TESTING):
323 put_magic_file(TESTING_COMPLETE, git_hash)
324 # There is still a potential race here (we check, bot deletes, we try to
325 # delete) - this is unlikely and we ignore it (restart if it happens).
326 delete_magic_file(TESTING)
Rico Wind139eece2018-09-25 09:42:09 +0200327 time.sleep(PULL_DELAY)
Rico Wind800fd712018-09-24 11:29:33 +0200328
329def handle_output(archive, stderr, stdout, exitcode, timed_out, cmd):
330 if archive:
331 archive_log(stdout, stderr, exitcode, timed_out, cmd)
332 else:
Rico Wind1331ded2022-02-22 14:56:46 +0100333 print('Execution of %s resulted in:' % cmd)
334 print('exit code: %s ' % exitcode)
335 print('timeout: %s ' % timed_out)
Rico Wind800fd712018-09-24 11:29:33 +0200336 with open(stderr, 'r') as f:
Rico Wind1331ded2022-02-22 14:56:46 +0100337 print('stderr: %s' % f.read())
Rico Wind800fd712018-09-24 11:29:33 +0200338 with open(stdout, 'r') as f:
Rico Wind1331ded2022-02-22 14:56:46 +0100339 print('stdout: %s' % f.read())
Rico Wind800fd712018-09-24 11:29:33 +0200340
Rico Wind6e2205d2018-10-25 13:27:13 +0200341def execute(cmd, archive, env=None):
Morten Krogh-Jespersenb042c972019-11-04 08:57:59 +0100342 if cmd == []:
343 return
Christoffer Quist Adamsen280fae02021-11-05 13:06:17 +0100344
Christoffer Quist Adamsene2788d22021-11-05 12:37:39 +0100345 assert(cmd[0].endswith('.py'))
346 cmd = [sys.executable] + cmd
347
Morten Krogh-Jespersenb042c972019-11-04 08:57:59 +0100348
Rico Wind800fd712018-09-24 11:29:33 +0200349 utils.PrintCmd(cmd)
350 with utils.TempDir() as temp:
351 try:
352 stderr_fd = None
353 stdout_fd = None
354 exitcode = 0
355 stderr = os.path.join(temp, 'stderr')
356 stderr_fd = open(stderr, 'w')
357 stdout = os.path.join(temp, 'stdout')
358 stdout_fd = open(stdout, 'w')
359 popen = subprocess.Popen(cmd,
360 bufsize=1024*1024*10,
361 stdout=stdout_fd,
Rico Wind6e2205d2018-10-25 13:27:13 +0200362 stderr=stderr_fd,
363 env=env)
Rico Wind800fd712018-09-24 11:29:33 +0200364 begin = time.time()
365 timed_out = False
366 while popen.poll() == None:
367 if time.time() - begin > RUN_TIMEOUT:
368 popen.terminate()
369 timed_out = True
370 time.sleep(2)
371 exitcode = popen.returncode
372 finally:
373 if stderr_fd:
374 stderr_fd.close()
375 if stdout_fd:
376 stdout_fd.close()
Rico Windc64ace32022-04-26 15:07:28 +0200377 if exitcode != 0:
Morten Krogh-Jespersen4df02ad2019-10-08 14:58:39 +0000378 handle_output(archive, stderr, stdout, popen.returncode,
379 timed_out, ' '.join(cmd))
Rico Wind800fd712018-09-24 11:29:33 +0200380 return exitcode
381
382def run_once(archive):
383 failed = False
384 git_hash = utils.get_HEAD_sha1()
Rico Wind1200f512018-09-26 08:48:37 +0200385 log('Running once with hash %s' % git_hash)
Rico Wind6e2205d2018-10-25 13:27:13 +0200386 env = os.environ.copy()
387 # Bot does not have a lot of memory.
Rico Wind4a7e6202022-03-15 07:08:50 +0100388 env['R8_GRADLE_CORES_PER_FORK'] = '8'
Morten Krogh-Jespersen2243b162019-01-14 08:40:53 +0100389 failed = any([execute(cmd, archive, env) for cmd in TEST_COMMANDS])
Rico Windba63dc82019-03-29 14:33:47 +0100390 # Gradle daemon occasionally leaks memory, stop it.
Rico Wind74233002019-04-04 08:28:58 +0200391 gradle.RunGradle(['--stop'])
Rico Wind800fd712018-09-24 11:29:33 +0200392 archive_status(1 if failed else 0)
Rico Wind139eece2018-09-25 09:42:09 +0200393 return failed
Rico Wind800fd712018-09-24 11:29:33 +0200394
395def Main():
396 (options, args) = ParseOptions()
397 if options.continuous:
398 run_continuously()
Rico Wind139eece2018-09-25 09:42:09 +0200399 elif options.bot:
400 return run_bot()
Rico Wind4fd2dda2018-09-26 17:41:45 +0200401 elif options.print_logs:
402 return fetch_and_print_logs(options.print_logs)
Rico Wind800fd712018-09-24 11:29:33 +0200403 else:
Rico Wind139eece2018-09-25 09:42:09 +0200404 return run_once(options.archive)
Rico Wind800fd712018-09-24 11:29:33 +0200405
406if __name__ == '__main__':
407 sys.exit(Main())