315 lines
9.6 KiB
Python
Executable File
315 lines
9.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
# Copyright 2019 The Chromium OS Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
"""Runs a tryjob/tryjobs after updating the packages."""
|
|
|
|
from __future__ import print_function
|
|
|
|
import argparse
|
|
import datetime
|
|
import json
|
|
import os
|
|
|
|
from assert_not_in_chroot import VerifyOutsideChroot
|
|
from failure_modes import FailureModes
|
|
from get_llvm_hash import GetLLVMHashAndVersionFromSVNOption
|
|
from get_llvm_hash import is_svn_option
|
|
from subprocess_helpers import ChrootRunCommand
|
|
from subprocess_helpers import ExecCommandAndCaptureOutput
|
|
import update_chromeos_llvm_next_hash
|
|
|
|
|
|
def GetCommandLineArgs():
|
|
"""Parses the command line for the command line arguments.
|
|
|
|
Returns:
|
|
The log level to use when retrieving the LLVM hash or google3 LLVM version,
|
|
the chroot path to use for executing chroot commands,
|
|
a list of a package or packages to update their LLVM next hash,
|
|
and the LLVM version to use when retrieving the LLVM hash.
|
|
"""
|
|
|
|
# Default path to the chroot if a path is not specified.
|
|
cros_root = os.path.expanduser('~')
|
|
cros_root = os.path.join(cros_root, 'chromiumos')
|
|
|
|
# Create parser and add optional command-line arguments.
|
|
parser = argparse.ArgumentParser(
|
|
description='Runs a tryjob if successfully updated packages\''
|
|
'"LLVM_NEXT_HASH".')
|
|
|
|
# Add argument for the absolute path to the file that contains information on
|
|
# the previous tested svn version.
|
|
parser.add_argument(
|
|
'--last_tested',
|
|
help='the absolute path to the file that contains the last tested '
|
|
'svn version')
|
|
|
|
# Add argument for other change lists that want to run alongside the tryjob
|
|
# which has a change list of updating a package's git hash.
|
|
parser.add_argument(
|
|
'--extra_change_lists',
|
|
type=int,
|
|
nargs='+',
|
|
help='change lists that would like to be run alongside the change list '
|
|
'of updating the packages')
|
|
|
|
# Add argument for custom options for the tryjob.
|
|
parser.add_argument(
|
|
'--options',
|
|
required=False,
|
|
nargs='+',
|
|
help='options to use for the tryjob testing')
|
|
|
|
# Add argument for builders for the tryjob.
|
|
parser.add_argument(
|
|
'--builders',
|
|
required=True,
|
|
nargs='+',
|
|
help='builders to use for the tryjob testing')
|
|
|
|
# Add argument for the description of the tryjob.
|
|
parser.add_argument(
|
|
'--description',
|
|
required=False,
|
|
nargs='+',
|
|
help='the description of the tryjob')
|
|
|
|
# Add argument for a specific chroot path.
|
|
parser.add_argument(
|
|
'--chroot_path',
|
|
default=cros_root,
|
|
help='the path to the chroot (default: %(default)s)')
|
|
|
|
# Add argument for whether to display command contents to `stdout`.
|
|
parser.add_argument(
|
|
'--verbose',
|
|
action='store_true',
|
|
help='display contents of a command to the terminal '
|
|
'(default: %(default)s)')
|
|
|
|
# Add argument for the LLVM version to use.
|
|
parser.add_argument(
|
|
'--llvm_version',
|
|
type=is_svn_option,
|
|
required=True,
|
|
help='which git hash of LLVM to find '
|
|
'{google3, ToT, <svn_version>} '
|
|
'(default: finds the git hash of the google3 LLVM '
|
|
'version)')
|
|
|
|
args_output = parser.parse_args()
|
|
|
|
return args_output
|
|
|
|
|
|
def GetLastTestedSVNVersion(last_tested_file):
|
|
"""Gets the lasted tested svn version from the file.
|
|
|
|
Args:
|
|
last_tested_file: The absolute path to the file that contains the last
|
|
tested svn version.
|
|
|
|
Returns:
|
|
The last tested svn version or 'None' if the file did not have a last tested
|
|
svn version (the file exists, but failed to convert the contents to an
|
|
integer) or the file does not exist.
|
|
"""
|
|
|
|
if not last_tested_file:
|
|
return None
|
|
|
|
last_svn_version = None
|
|
|
|
# Get the last tested svn version if the file exists.
|
|
try:
|
|
with open(last_tested_file) as file_obj:
|
|
# For now, the first line contains the last tested svn version.
|
|
return int(file_obj.read().rstrip())
|
|
|
|
except IOError:
|
|
pass
|
|
except ValueError:
|
|
pass
|
|
|
|
return last_svn_version
|
|
|
|
|
|
def GetTryJobCommand(change_list, extra_change_lists, options, builder):
|
|
"""Constructs the 'tryjob' command.
|
|
|
|
Args:
|
|
change_list: The CL obtained from updating the packages.
|
|
extra_change_lists: Extra change lists that would like to be run alongside
|
|
the change list of updating the packages.
|
|
options: Options to be passed into the tryjob command.
|
|
builder: The builder to be passed into the tryjob command.
|
|
|
|
Returns:
|
|
The 'tryjob' command with the change list of updating the packages and
|
|
any extra information that was passed into the command line.
|
|
"""
|
|
|
|
tryjob_cmd = ['cros', 'tryjob', '--yes', '--json', '-g', '%d' % change_list]
|
|
|
|
if extra_change_lists:
|
|
for extra_cl in extra_change_lists:
|
|
tryjob_cmd.extend(['-g', '%d' % extra_cl])
|
|
|
|
tryjob_cmd.append(builder)
|
|
|
|
if options:
|
|
tryjob_cmd.extend('--%s' % option for option in options)
|
|
|
|
return tryjob_cmd
|
|
|
|
|
|
def GetCurrentTimeInUTC():
|
|
"""Returns the current time via `datetime.datetime.utcnow()`."""
|
|
return datetime.datetime.utcnow()
|
|
|
|
|
|
def RunTryJobs(cl_number, extra_change_lists, options, builders, chroot_path,
|
|
verbose):
|
|
"""Runs a tryjob/tryjobs.
|
|
|
|
Args:
|
|
cl_number: The CL created by updating the packages.
|
|
extra_change_lists: Any extra change lists that would run alongside the CL
|
|
that was created by updating the packages ('cl_number').
|
|
options: Any options to be passed into the 'tryjob' command.
|
|
builders: All the builders to run the 'tryjob' with.
|
|
chroot_path: The absolute path to the chroot.
|
|
verbose: Print command contents to `stdout`.
|
|
|
|
Returns:
|
|
A list that contains stdout contents of each tryjob, where stdout is
|
|
information (a hashmap) about the tryjob. The hashmap also contains stderr
|
|
if there was an error when running a tryjob.
|
|
|
|
Raises:
|
|
ValueError: Failed to submit a tryjob.
|
|
"""
|
|
|
|
# Contains the results of each tryjob. The results are retrieved from 'out'
|
|
# which is stdout of the command executer.
|
|
tryjob_results = []
|
|
|
|
# For each builder passed into the command line:
|
|
#
|
|
# Run a tryjob with the change list number obtained from updating the
|
|
# packages and append additional changes lists and options obtained from the
|
|
# command line.
|
|
for cur_builder in builders:
|
|
tryjob_cmd = GetTryJobCommand(cl_number, extra_change_lists, options,
|
|
cur_builder)
|
|
|
|
out = ChrootRunCommand(chroot_path, tryjob_cmd, verbose=verbose)
|
|
|
|
tryjob_launch_time = GetCurrentTimeInUTC()
|
|
|
|
tryjob_contents = json.loads(out)
|
|
|
|
buildbucket_id = int(tryjob_contents[0]['buildbucket_id'])
|
|
|
|
new_tryjob = {
|
|
'launch_time': str(tryjob_launch_time),
|
|
'link': str(tryjob_contents[0]['url']),
|
|
'buildbucket_id': buildbucket_id,
|
|
'extra_cls': extra_change_lists,
|
|
'options': options,
|
|
'builder': [cur_builder]
|
|
}
|
|
|
|
tryjob_results.append(new_tryjob)
|
|
|
|
AddTryjobLinkToCL(tryjob_results, cl_number, chroot_path)
|
|
|
|
return tryjob_results
|
|
|
|
|
|
def AddTryjobLinkToCL(tryjobs, cl, chroot_path):
|
|
"""Adds the tryjob link(s) to the CL via `gerrit message <CL> <message>`."""
|
|
|
|
# NOTE: Invoking `cros_sdk` does not make each tryjob link appear on its own
|
|
# line, so invoking the `gerrit` command directly instead of using `cros_sdk`
|
|
# to do it for us.
|
|
#
|
|
# FIXME: Need to figure out why `cros_sdk` does not add each tryjob link as a
|
|
# newline.
|
|
gerrit_abs_path = os.path.join(chroot_path, 'chromite/bin/gerrit')
|
|
|
|
tryjob_links = ['Started the following tryjobs:']
|
|
tryjob_links.extend(tryjob['link'] for tryjob in tryjobs)
|
|
|
|
add_message_cmd = [
|
|
gerrit_abs_path, 'message',
|
|
str(cl), '\n'.join(tryjob_links)
|
|
]
|
|
|
|
ExecCommandAndCaptureOutput(add_message_cmd)
|
|
|
|
|
|
def main():
|
|
"""Updates the packages' 'LLVM_NEXT_HASH' and submits tryjobs.
|
|
|
|
Raises:
|
|
AssertionError: The script was run inside the chroot.
|
|
"""
|
|
|
|
VerifyOutsideChroot()
|
|
|
|
args_output = GetCommandLineArgs()
|
|
|
|
last_svn_version = GetLastTestedSVNVersion(args_output.last_tested)
|
|
|
|
update_packages = [
|
|
'sys-devel/llvm', 'sys-libs/compiler-rt', 'sys-libs/libcxx',
|
|
'sys-libs/libcxxabi', 'sys-libs/llvm-libunwind'
|
|
]
|
|
|
|
patch_metadata_file = 'PATCHES.json'
|
|
|
|
svn_option = args_output.llvm_version
|
|
|
|
git_hash, svn_version = GetLLVMHashAndVersionFromSVNOption(svn_option)
|
|
|
|
# There is no need to run tryjobs when the SVN version matches the last tested
|
|
# SVN version.
|
|
if last_svn_version == svn_version:
|
|
print('svn version (%d) matches the last tested svn version (%d) in %s' %
|
|
(svn_version, last_svn_version, args_output.last_tested))
|
|
return
|
|
|
|
update_chromeos_llvm_next_hash.verbose = args_output.verbose
|
|
|
|
change_list = update_chromeos_llvm_next_hash.UpdatePackages(
|
|
update_packages, git_hash, svn_version, args_output.chroot_path,
|
|
patch_metadata_file, FailureModes.DISABLE_PATCHES, svn_option)
|
|
|
|
print('Successfully updated packages to %d' % svn_version)
|
|
print('Gerrit URL: %s' % change_list.url)
|
|
print('Change list number: %d' % change_list.cl_number)
|
|
|
|
tryjob_results = RunTryJobs(change_list.cl_number,
|
|
args_output.extra_change_lists,
|
|
args_output.options, args_output.builders,
|
|
args_output.chroot_path, args_output.verbose)
|
|
|
|
print('Tryjobs:')
|
|
for tryjob in tryjob_results:
|
|
print(tryjob)
|
|
|
|
# Updated the packages and submitted tryjobs successfully, so the file will
|
|
# contain 'svn_version' which will now become the last tested svn version.
|
|
if args_output.last_tested:
|
|
with open(args_output.last_tested, 'w') as file_obj:
|
|
file_obj.write(str(svn_version))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|