Kuang-che Wu | 875c89a | 2020-01-08 14:30:55 +0800 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
Kuang-che Wu | 6e4beca | 2018-06-27 17:45:02 +0800 | [diff] [blame] | 2 | # -*- coding: utf-8 -*- |
Kuang-che Wu | e2563ea | 2018-01-05 20:30:28 +0800 | [diff] [blame] | 3 | # Copyright 2017 The Chromium OS Authors. All rights reserved. |
| 4 | # Use of this source code is governed by a BSD-style license that can be |
| 5 | # found in the LICENSE file. |
| 6 | """Chrome bisector to bisect a range of chrome commits. |
| 7 | |
| 8 | The supported version format for --old and --new are: |
| 9 | - ChromeOS version: 9876.0.0 or R62-9876.0.0 |
| 10 | - Chrome version: 62.0.1234.0 |
| 11 | - Chrome commit position: #1234 |
| 12 | - git commit hash |
| 13 | |
| 14 | Example: |
| 15 | $ ./bisect_cr_localbuild_master.py init --old rev1 --new rev2 --dut DUT |
| 16 | $ ./bisect_cr_localbuild_master.py config switch \ |
| 17 | ./switch_cros_cr_localbuild_master.py |
| 18 | $ ./bisect_cr_localbuild_master.py config eval ./eval-manually.sh |
| 19 | $ ./bisect_cr_localbuild_master.py run |
| 20 | |
| 21 | When running switcher and evaluator, following environment variables |
| 22 | will be set: |
| 23 | CHROME_ROOT (e.g. ~/chromium), |
| 24 | CHROME_BRANCH (i.e. master), |
| 25 | GIT_REPO (e.g. ~/chromium/src), |
| 26 | REV (git commit hash), |
| 27 | BOARD (e.g. samus, if available), and |
| 28 | DUT (e.g. samus-dut, if available). |
| 29 | """ |
Kuang-che Wu | ebc2c36 | 2020-12-14 16:27:09 +0800 | [diff] [blame] | 30 | # Note, this script only works for the main branch of chrome. |
Kuang-che Wu | e2563ea | 2018-01-05 20:30:28 +0800 | [diff] [blame] | 31 | from __future__ import print_function |
Kuang-che Wu | e2563ea | 2018-01-05 20:30:28 +0800 | [diff] [blame] | 32 | import logging |
Kuang-che Wu | e80bb87 | 2018-11-15 19:45:25 +0800 | [diff] [blame] | 33 | import os |
Kuang-che Wu | e2563ea | 2018-01-05 20:30:28 +0800 | [diff] [blame] | 34 | |
Kuang-che Wu | 2526a67 | 2019-09-10 16:23:59 +0800 | [diff] [blame] | 35 | from bisect_kit import bisector_cli |
Kuang-che Wu | e2563ea | 2018-01-05 20:30:28 +0800 | [diff] [blame] | 36 | from bisect_kit import cli |
| 37 | from bisect_kit import configure |
| 38 | from bisect_kit import core |
| 39 | from bisect_kit import cros_util |
| 40 | from bisect_kit import cr_util |
Kuang-che Wu | e121fae | 2018-11-09 16:18:39 +0800 | [diff] [blame] | 41 | from bisect_kit import errors |
Kuang-che Wu | e2563ea | 2018-01-05 20:30:28 +0800 | [diff] [blame] | 42 | from bisect_kit import git_util |
Kuang-che Wu | e2563ea | 2018-01-05 20:30:28 +0800 | [diff] [blame] | 43 | |
| 44 | logger = logging.getLogger(__name__) |
| 45 | |
| 46 | revtype = cli.argtype_multiplexer(cr_util.argtype_chrome_version, |
| 47 | cros_util.argtype_cros_version, |
Kuang-che Wu | 603cdad | 2019-01-18 21:32:55 +0800 | [diff] [blame] | 48 | git_util.argtype_git_rev, |
| 49 | cli.argtype_re(r'^#(\d+)$', '#12345')) |
Kuang-che Wu | e2563ea | 2018-01-05 20:30:28 +0800 | [diff] [blame] | 50 | |
Kuang-che Wu | 13acc7b | 2020-06-15 10:45:35 +0800 | [diff] [blame] | 51 | chrome_repo_url = 'https://chromium.googlesource.com/chromium/src' |
| 52 | |
Kuang-che Wu | e2563ea | 2018-01-05 20:30:28 +0800 | [diff] [blame] | 53 | |
| 54 | def guess_git_rev(opts, rev): |
| 55 | """Recognizes version number and determines the corresponding git hash. |
| 56 | |
| 57 | It will also fetch latest source if necessary. |
| 58 | |
| 59 | Args: |
| 60 | opts: An argparse.Namespace to hold command line arguments. |
| 61 | rev: could be chromeos version, chrome version, chrome commit position, or |
| 62 | git commit hash |
| 63 | |
| 64 | Returns: |
| 65 | full git commit hash |
| 66 | """ |
| 67 | if cros_util.is_cros_version(rev): |
| 68 | if not opts.board and not opts.dut: |
Kuang-che Wu | e121fae | 2018-11-09 16:18:39 +0800 | [diff] [blame] | 69 | raise errors.ArgumentError( |
| 70 | '--dut and --board', 'You specified ChromeOS version number, ' |
| 71 | 'thus either DUT or BOARD is required') |
Kuang-che Wu | e2563ea | 2018-01-05 20:30:28 +0800 | [diff] [blame] | 72 | assert opts.board |
| 73 | chrome_version = cros_util.query_chrome_version(opts.board, rev) |
| 74 | assert cr_util.is_chrome_version(chrome_version) |
| 75 | logger.info('Converted given CrOS version %s to Chrome version %s', rev, |
| 76 | chrome_version) |
| 77 | rev = chrome_version |
| 78 | |
| 79 | chrome_src = os.path.join(opts.chrome_root, 'src') |
| 80 | |
| 81 | if cr_util.is_chrome_version(rev): |
| 82 | if not git_util.is_containing_commit(chrome_src, rev): |
Kuang-che Wu | 2b1286b | 2019-05-20 20:37:26 +0800 | [diff] [blame] | 83 | git_util.fetch(chrome_src, '--tags') |
Kuang-che Wu | e2563ea | 2018-01-05 20:30:28 +0800 | [diff] [blame] | 84 | else: |
Kuang-che Wu | 2b1286b | 2019-05-20 20:37:26 +0800 | [diff] [blame] | 85 | git_util.fetch(chrome_src) |
Kuang-che Wu | e2563ea | 2018-01-05 20:30:28 +0800 | [diff] [blame] | 86 | |
| 87 | git_rev = cr_util.query_git_rev(chrome_src, rev) |
| 88 | logger.info('Git hash of %s is %s', rev, git_rev) |
| 89 | assert git_util.is_containing_commit(chrome_src, git_rev) |
| 90 | return git_rev |
| 91 | |
| 92 | |
| 93 | def verify_gclient_dep(chrome_root): |
| 94 | """Makes sure gclient deps_file follow git checkout.""" |
| 95 | context = {} |
Kuang-che Wu | d2646f4 | 2019-11-27 18:31:08 +0800 | [diff] [blame] | 96 | with open(os.path.join(chrome_root, '.gclient')) as f: |
| 97 | code = compile(f.read(), '.gclient', 'exec') |
Kuang-che Wu | b1b18ea | 2021-01-18 15:03:30 +0800 | [diff] [blame] | 98 | # pylint: disable=exec-used |
| 99 | exec(code, context) |
Kuang-che Wu | 25fec6f | 2021-01-28 12:40:43 +0800 | [diff] [blame] | 100 | for solution in context.get('solutions', []): |
Kuang-che Wu | e2563ea | 2018-01-05 20:30:28 +0800 | [diff] [blame] | 101 | if solution['name'] == 'src': |
Kuang-che Wu | 4cc54b5 | 2018-08-15 15:57:19 +0800 | [diff] [blame] | 102 | return 'deps_file' not in solution or solution['deps_file'] == '.DEPS.git' |
Kuang-che Wu | e2563ea | 2018-01-05 20:30:28 +0800 | [diff] [blame] | 103 | return False |
| 104 | |
| 105 | |
| 106 | class ChromeSrcMasterDomain(core.BisectDomain): |
Kuang-che Wu | ebc2c36 | 2020-12-14 16:27:09 +0800 | [diff] [blame] | 107 | """BisectDomain for Chrome main tree""" |
Kuang-che Wu | e2563ea | 2018-01-05 20:30:28 +0800 | [diff] [blame] | 108 | revtype = staticmethod(revtype) |
| 109 | help = globals()['__doc__'] |
| 110 | |
| 111 | @staticmethod |
| 112 | def add_init_arguments(parser): |
| 113 | parser.add_argument( |
| 114 | '--chrome_root', |
| 115 | required=True, |
| 116 | metavar='CHROME_ROOT', |
| 117 | type=cli.argtype_dir_path, |
| 118 | default=configure.get('CHROME_ROOT'), |
| 119 | help='Root of chrome source tree, like ~/chromium') |
| 120 | |
| 121 | # Only used for Chrome on ChromeOS. |
| 122 | parser.add_argument( |
| 123 | '--dut', |
| 124 | type=cli.argtype_notempty, |
| 125 | metavar='DUT', |
| 126 | default=configure.get('DUT'), |
| 127 | help='For ChromeOS, address of DUT (Device Under Test)') |
| 128 | parser.add_argument( |
| 129 | '--board', |
| 130 | metavar='BOARD', |
| 131 | default=configure.get('BOARD'), |
| 132 | help='For ChromeOS, board name') |
| 133 | |
| 134 | @staticmethod |
| 135 | def init(opts): |
| 136 | chrome_src = os.path.join(opts.chrome_root, 'src') |
| 137 | if not os.path.exists(chrome_src): |
Kuang-che Wu | e121fae | 2018-11-09 16:18:39 +0800 | [diff] [blame] | 138 | raise errors.ArgumentError('--chrome_src', |
| 139 | "chrome src directory doesn't exist") |
Kuang-che Wu | e2563ea | 2018-01-05 20:30:28 +0800 | [diff] [blame] | 140 | |
| 141 | if opts.dut: |
| 142 | assert cros_util.is_dut(opts.dut) |
| 143 | if not opts.board: |
| 144 | opts.board = cros_util.query_dut_board(opts.dut) |
| 145 | |
| 146 | old = guess_git_rev(opts, opts.old) |
| 147 | new = guess_git_rev(opts, opts.new) |
| 148 | |
| 149 | revlist = git_util.get_revlist(chrome_src, old, new) |
Kuang-che Wu | 848b1af | 2018-02-01 20:59:36 +0800 | [diff] [blame] | 150 | |
| 151 | # If opts.old is chromeos version or chrome version, `old` is pointed to a |
| 152 | # git tag commit. But what we used to bisect is the parent of the tag. In |
| 153 | # other words, `old` is not in the returned list of get_revlist(). Here I |
| 154 | # don't verify the commit graph carefully and just re-assign revlist[0] as |
| 155 | # `old`. |
| 156 | old = revlist[0] |
| 157 | |
Kuang-che Wu | e2563ea | 2018-01-05 20:30:28 +0800 | [diff] [blame] | 158 | config = dict( |
| 159 | chrome_root=opts.chrome_root, |
| 160 | chrome_src=chrome_src, |
| 161 | old=old, |
| 162 | new=new, |
| 163 | board=opts.board, |
| 164 | dut=opts.dut) |
Kuang-che Wu | 13acc7b | 2020-06-15 10:45:35 +0800 | [diff] [blame] | 165 | |
| 166 | details = {} |
| 167 | for rev in revlist: |
| 168 | link = '%s/+/%s' % (chrome_repo_url, rev) |
| 169 | action = {'link': link} |
| 170 | details[rev] = {'actions': [action]} |
| 171 | |
| 172 | return config, {'revlist': revlist, 'details': details} |
Kuang-che Wu | e2563ea | 2018-01-05 20:30:28 +0800 | [diff] [blame] | 173 | |
| 174 | def __init__(self, config): |
| 175 | self.config = config |
| 176 | |
| 177 | def setenv(self, env, rev): |
| 178 | env['CHROME_ROOT'] = self.config['chrome_root'] |
| 179 | env['CHROME_BRANCH'] = 'master' |
| 180 | env['GIT_REPO'] = self.config['chrome_src'] |
| 181 | env['REV'] = rev |
| 182 | |
| 183 | if self.config['board']: |
Kuang-che Wu | 848b1af | 2018-02-01 20:59:36 +0800 | [diff] [blame] | 184 | env['BOARD'] = self.config['board'] |
Kuang-che Wu | e2563ea | 2018-01-05 20:30:28 +0800 | [diff] [blame] | 185 | if self.config['dut']: |
Kuang-che Wu | 848b1af | 2018-02-01 20:59:36 +0800 | [diff] [blame] | 186 | env['DUT'] = self.config['dut'] |
Kuang-che Wu | e2563ea | 2018-01-05 20:30:28 +0800 | [diff] [blame] | 187 | |
Kuang-che Wu | 13acc7b | 2020-06-15 10:45:35 +0800 | [diff] [blame] | 188 | def fill_candidate_summary(self, summary): |
Kuang-che Wu | 948a79c | 2019-06-19 19:13:56 +0800 | [diff] [blame] | 189 | if 'current_range' in summary: |
| 190 | old, new = summary['current_range'] |
| 191 | log_url = '%s/+log/%s..%s?n=10000' % (chrome_repo_url, old, new) |
| 192 | summary['links'] = [ |
| 193 | { |
| 194 | 'name': 'change_list', |
| 195 | 'url': log_url, |
| 196 | 'note': |
| 197 | 'The link of change list only lists chrome src/ commits. For ' |
| 198 | 'example, commits inside v8 and third party repos are not ' |
| 199 | 'listed.', |
| 200 | }, |
| 201 | { |
| 202 | 'name': 'fuller', |
| 203 | 'url': log_url + '&pretty=fuller', |
| 204 | }, |
| 205 | ] |
Kuang-che Wu | e80bb87 | 2018-11-15 19:45:25 +0800 | [diff] [blame] | 206 | |
Kuang-che Wu | e2563ea | 2018-01-05 20:30:28 +0800 | [diff] [blame] | 207 | |
| 208 | if __name__ == '__main__': |
Kuang-che Wu | 2526a67 | 2019-09-10 16:23:59 +0800 | [diff] [blame] | 209 | bisector_cli.BisectorCommandLine(ChromeSrcMasterDomain).main() |