blob: 2160b0359d2187aa82c6047f18545fe334bae7af [file] [log] [blame]
Kuang-che Wu875c89a2020-01-08 14:30:55 +08001#!/usr/bin/env python3
Kuang-che Wu6e4beca2018-06-27 17:45:02 +08002# -*- coding: utf-8 -*-
Kuang-che Wue2563ea2018-01-05 20:30:28 +08003# 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
8The 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
14Example:
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
21When running switcher and evaluator, following environment variables
22will 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 Wuebc2c362020-12-14 16:27:09 +080030# Note, this script only works for the main branch of chrome.
Kuang-che Wue2563ea2018-01-05 20:30:28 +080031from __future__ import print_function
Kuang-che Wue2563ea2018-01-05 20:30:28 +080032import logging
Kuang-che Wue80bb872018-11-15 19:45:25 +080033import os
Kuang-che Wue2563ea2018-01-05 20:30:28 +080034
Kuang-che Wu2526a672019-09-10 16:23:59 +080035from bisect_kit import bisector_cli
Kuang-che Wue2563ea2018-01-05 20:30:28 +080036from bisect_kit import cli
37from bisect_kit import configure
38from bisect_kit import core
39from bisect_kit import cros_util
40from bisect_kit import cr_util
Kuang-che Wue121fae2018-11-09 16:18:39 +080041from bisect_kit import errors
Kuang-che Wue2563ea2018-01-05 20:30:28 +080042from bisect_kit import git_util
Kuang-che Wue2563ea2018-01-05 20:30:28 +080043
44logger = logging.getLogger(__name__)
45
46revtype = cli.argtype_multiplexer(cr_util.argtype_chrome_version,
47 cros_util.argtype_cros_version,
Kuang-che Wu603cdad2019-01-18 21:32:55 +080048 git_util.argtype_git_rev,
49 cli.argtype_re(r'^#(\d+)$', '#12345'))
Kuang-che Wue2563ea2018-01-05 20:30:28 +080050
Kuang-che Wu13acc7b2020-06-15 10:45:35 +080051chrome_repo_url = 'https://chromium.googlesource.com/chromium/src'
52
Kuang-che Wue2563ea2018-01-05 20:30:28 +080053
54def 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 Wue121fae2018-11-09 16:18:39 +080069 raise errors.ArgumentError(
70 '--dut and --board', 'You specified ChromeOS version number, '
71 'thus either DUT or BOARD is required')
Kuang-che Wue2563ea2018-01-05 20:30:28 +080072 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 Wu2b1286b2019-05-20 20:37:26 +080083 git_util.fetch(chrome_src, '--tags')
Kuang-che Wue2563ea2018-01-05 20:30:28 +080084 else:
Kuang-che Wu2b1286b2019-05-20 20:37:26 +080085 git_util.fetch(chrome_src)
Kuang-che Wue2563ea2018-01-05 20:30:28 +080086
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
93def verify_gclient_dep(chrome_root):
94 """Makes sure gclient deps_file follow git checkout."""
95 context = {}
Kuang-che Wud2646f42019-11-27 18:31:08 +080096 with open(os.path.join(chrome_root, '.gclient')) as f:
97 code = compile(f.read(), '.gclient', 'exec')
Kuang-che Wub1b18ea2021-01-18 15:03:30 +080098 # pylint: disable=exec-used
99 exec(code, context)
Kuang-che Wu25fec6f2021-01-28 12:40:43 +0800100 for solution in context.get('solutions', []):
Kuang-che Wue2563ea2018-01-05 20:30:28 +0800101 if solution['name'] == 'src':
Kuang-che Wu4cc54b52018-08-15 15:57:19 +0800102 return 'deps_file' not in solution or solution['deps_file'] == '.DEPS.git'
Kuang-che Wue2563ea2018-01-05 20:30:28 +0800103 return False
104
105
106class ChromeSrcMasterDomain(core.BisectDomain):
Kuang-che Wuebc2c362020-12-14 16:27:09 +0800107 """BisectDomain for Chrome main tree"""
Kuang-che Wue2563ea2018-01-05 20:30:28 +0800108 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 Wue121fae2018-11-09 16:18:39 +0800138 raise errors.ArgumentError('--chrome_src',
139 "chrome src directory doesn't exist")
Kuang-che Wue2563ea2018-01-05 20:30:28 +0800140
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 Wu848b1af2018-02-01 20:59:36 +0800150
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 Wue2563ea2018-01-05 20:30:28 +0800158 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 Wu13acc7b2020-06-15 10:45:35 +0800165
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 Wue2563ea2018-01-05 20:30:28 +0800173
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 Wu848b1af2018-02-01 20:59:36 +0800184 env['BOARD'] = self.config['board']
Kuang-che Wue2563ea2018-01-05 20:30:28 +0800185 if self.config['dut']:
Kuang-che Wu848b1af2018-02-01 20:59:36 +0800186 env['DUT'] = self.config['dut']
Kuang-che Wue2563ea2018-01-05 20:30:28 +0800187
Kuang-che Wu13acc7b2020-06-15 10:45:35 +0800188 def fill_candidate_summary(self, summary):
Kuang-che Wu948a79c2019-06-19 19:13:56 +0800189 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 Wue80bb872018-11-15 19:45:25 +0800206
Kuang-che Wue2563ea2018-01-05 20:30:28 +0800207
208if __name__ == '__main__':
Kuang-che Wu2526a672019-09-10 16:23:59 +0800209 bisector_cli.BisectorCommandLine(ChromeSrcMasterDomain).main()