OLD | NEW |
1 #!/usr/bin/python2 | 1 #!/usr/bin/python2 |
2 | 2 |
3 # Copyright 2014 Google Inc. | 3 # Copyright 2014 Google Inc. |
4 # | 4 # |
5 # Use of this source code is governed by a BSD-style license that can be | 5 # Use of this source code is governed by a BSD-style license that can be |
6 # found in the LICENSE file. | 6 # found in the LICENSE file. |
7 | 7 |
8 """Skia's Chromium DEPS roll script. | 8 """Skia's Chromium DEPS roll script. |
9 | 9 |
10 This script: | 10 This script: |
(...skipping 20 matching lines...) Expand all Loading... |
31 import sys | 31 import sys |
32 import tempfile | 32 import tempfile |
33 | 33 |
34 import fix_pythonpath # pylint: disable=W0611 | 34 import fix_pythonpath # pylint: disable=W0611 |
35 from common.py.utils import git_utils | 35 from common.py.utils import git_utils |
36 from common.py.utils import misc | 36 from common.py.utils import misc |
37 from common.py.utils import shell_utils | 37 from common.py.utils import shell_utils |
38 | 38 |
39 | 39 |
40 DEFAULT_BOTS_LIST = [ | 40 DEFAULT_BOTS_LIST = [ |
41 'android_clang_dbg', | 41 'android_clang_dbg', |
42 'android_dbg', | 42 'android_dbg', |
43 'android_rel', | 43 'android_rel', |
44 'cros_daisy', | 44 'cros_daisy', |
45 'linux', | 45 'linux', |
46 'linux_asan', | 46 'linux_asan', |
47 'linux_chromeos', | 47 'linux_chromeos', |
48 'linux_chromeos_asan', | 48 'linux_chromeos_asan', |
49 'linux_chromium_gn_dbg', | 49 'linux_chromium_gn_dbg', |
50 'linux_gpu', | 50 'linux_gpu', |
51 'linux_layout', | 51 'linux_layout', |
52 'linux_layout_rel', | 52 'linux_layout_rel', |
53 'mac', | 53 'mac', |
54 'mac_asan', | 54 'mac_asan', |
55 'mac_gpu', | 55 'mac_gpu', |
56 'mac_layout', | 56 'mac_layout', |
57 'mac_layout_rel', | 57 'mac_layout_rel', |
58 'win', | 58 'win', |
59 'win_gpu', | 59 'win_gpu', |
60 'win_layout', | 60 'win_layout', |
61 'win_layout_rel', | 61 'win_layout_rel', |
62 ] | 62 ] |
63 | 63 |
64 REGEXP_SKIA_REVISION = ( | 64 REGEXP_SKIA_REVISION = ( |
65 r'^ "skia_revision": "(?P<revision>[0-9a-fA-F]{2,40})",$') | 65 r'^ "skia_revision": "(?P<revision>[0-9a-fA-F]{2,40})",$') |
66 | 66 |
67 | 67 |
68 class DepsRollConfig(object): | 68 class DepsRollConfig(object): |
69 """Contains configuration options for this module. | 69 """Contains configuration options for this module. |
70 | 70 |
71 Attributes: | 71 Attributes: |
72 chromium_path: (string) path to a local chromium git repository. | 72 chromium_path: (string) path to a local chromium git repository. |
73 save_branches: (boolean) iff false, delete temporary branches. | 73 save_branches: (boolean) iff false, delete temporary branches. |
74 verbose: (boolean) iff false, suppress the output from git-cl. | 74 verbose: (boolean) iff false, suppress the output from git-cl. |
75 skip_cl_upload: (boolean) | 75 skip_cl_upload: (boolean) |
76 cl_bot_list: (list of strings) | 76 cl_bot_list: (list of strings) |
| 77 """ |
| 78 |
| 79 # pylint: disable=I0011,R0903,R0902 |
| 80 def __init__(self, options=None): |
| 81 if not options: |
| 82 options = DepsRollConfig.GetOptionParser() |
| 83 # pylint: disable=I0011,E1103 |
| 84 self.verbose = options.verbose |
| 85 self.save_branches = not options.delete_branches |
| 86 self.chromium_path = options.chromium_path |
| 87 self.skip_cl_upload = options.skip_cl_upload |
| 88 # Split and remove empty strigns from the bot list. |
| 89 self.cl_bot_list = [bot for bot in options.bots.split(',') if bot] |
| 90 self.default_branch_name = 'autogenerated_deps_roll_branch' |
| 91 self.reviewers_list = ','.join([ |
| 92 # 'rmistry@google.com', |
| 93 # 'reed@google.com', |
| 94 # 'bsalomon@google.com', |
| 95 # 'robertphillips@google.com', |
| 96 ]) |
| 97 self.cc_list = ','.join([ |
| 98 # 'skia-team@google.com', |
| 99 ]) |
| 100 |
| 101 @staticmethod |
| 102 def GetOptionParser(): |
| 103 # pylint: disable=I0011,C0103 |
| 104 """Returns an optparse.OptionParser object. |
| 105 |
| 106 Returns: |
| 107 An optparse.OptionParser object. |
| 108 |
| 109 Called by the main() function. |
77 """ | 110 """ |
78 | 111 option_parser = optparse.OptionParser(usage=__doc__) |
79 # pylint: disable=I0011,R0903,R0902 | 112 # Anyone using this script on a regular basis should set the |
80 def __init__(self, options=None): | 113 # CHROMIUM_CHECKOUT_PATH environment variable. |
81 if not options: | 114 option_parser.add_option( |
82 options = DepsRollConfig.GetOptionParser() | 115 '-c', '--chromium_path', help='Path to local Chromium Git' |
83 # pylint: disable=I0011,E1103 | 116 ' repository checkout, defaults to CHROMIUM_CHECKOUT_PATH' |
84 self.verbose = options.verbose | 117 ' if that environment variable is set.', |
85 self.save_branches = not options.delete_branches | 118 default=os.environ.get('CHROMIUM_CHECKOUT_PATH')) |
86 self.chromium_path = options.chromium_path | 119 option_parser.add_option( |
87 self.skip_cl_upload = options.skip_cl_upload | 120 '-r', '--revision', default=None, |
88 # Split and remove empty strigns from the bot list. | 121 help='The Skia Git commit hash.') |
89 self.cl_bot_list = [bot for bot in options.bots.split(',') if bot] | 122 |
90 self.default_branch_name = 'autogenerated_deps_roll_branch' | 123 option_parser.add_option( |
91 self.reviewers_list = ','.join([ | 124 '', '--delete_branches', help='Delete the temporary branches', |
92 # 'rmistry@google.com', | 125 action='store_true', dest='delete_branches', default=False) |
93 # 'reed@google.com', | 126 option_parser.add_option( |
94 # 'bsalomon@google.com', | 127 '', '--verbose', help='Do not suppress the output from `git cl`.', |
95 # 'robertphillips@google.com', | 128 action='store_true', dest='verbose', default=False) |
96 ]) | 129 option_parser.add_option( |
97 self.cc_list = ','.join([ | 130 '', '--skip_cl_upload', help='Skip the cl upload step; useful' |
98 # 'skia-team@google.com', | 131 ' for testing.', |
99 ]) | 132 action='store_true', default=False) |
100 | 133 |
101 @staticmethod | 134 default_bots_help = ( |
102 def GetOptionParser(): | 135 'Comma-separated list of bots, defaults to a list of %d bots.' |
103 # pylint: disable=I0011,C0103 | 136 ' To skip `git cl try`, set this to an empty string.' |
104 """Returns an optparse.OptionParser object. | 137 % len(DEFAULT_BOTS_LIST)) |
105 | 138 default_bots = ','.join(DEFAULT_BOTS_LIST) |
106 Returns: | 139 option_parser.add_option( |
107 An optparse.OptionParser object. | 140 '', '--bots', help=default_bots_help, default=default_bots) |
108 | 141 |
109 Called by the main() function. | 142 return option_parser |
110 """ | |
111 option_parser = optparse.OptionParser(usage=__doc__) | |
112 # Anyone using this script on a regular basis should set the | |
113 # CHROMIUM_CHECKOUT_PATH environment variable. | |
114 option_parser.add_option( | |
115 '-c', '--chromium_path', help='Path to local Chromium Git' | |
116 ' repository checkout, defaults to CHROMIUM_CHECKOUT_PATH' | |
117 ' if that environment variable is set.', | |
118 default=os.environ.get('CHROMIUM_CHECKOUT_PATH')) | |
119 option_parser.add_option( | |
120 '-r', '--revision', default=None, | |
121 help='The Skia Git commit hash.') | |
122 | |
123 option_parser.add_option( | |
124 '', '--delete_branches', help='Delete the temporary branches', | |
125 action='store_true', dest='delete_branches', default=False) | |
126 option_parser.add_option( | |
127 '', '--verbose', help='Do not suppress the output from `git cl`.', | |
128 action='store_true', dest='verbose', default=False) | |
129 option_parser.add_option( | |
130 '', '--skip_cl_upload', help='Skip the cl upload step; useful' | |
131 ' for testing.', | |
132 action='store_true', default=False) | |
133 | |
134 default_bots_help = ( | |
135 'Comma-separated list of bots, defaults to a list of %d bots.' | |
136 ' To skip `git cl try`, set this to an empty string.' | |
137 % len(DEFAULT_BOTS_LIST)) | |
138 default_bots = ','.join(DEFAULT_BOTS_LIST) | |
139 option_parser.add_option( | |
140 '', '--bots', help=default_bots_help, default=default_bots) | |
141 | |
142 return option_parser | |
143 | 143 |
144 | 144 |
145 class DepsRollError(Exception): | 145 class DepsRollError(Exception): |
146 """Exceptions specific to this module.""" | 146 """Exceptions specific to this module.""" |
147 pass | 147 pass |
148 | 148 |
149 | 149 |
150 def change_skia_deps(revision, depspath): | 150 def change_skia_deps(revision, depspath): |
151 """Update the DEPS file. | 151 """Update the DEPS file. |
152 | 152 |
153 Modify the skia_revision entry in the given DEPS file. | 153 Modify the skia_revision entry in the given DEPS file. |
154 | 154 |
155 Args: | 155 Args: |
156 revision: (string) Skia commit hash. | 156 revision: (string) Skia commit hash. |
157 depspath: (string) path to DEPS file. | 157 depspath: (string) path to DEPS file. |
158 """ | 158 """ |
159 temp_file = tempfile.NamedTemporaryFile(delete=False, | 159 temp_file = tempfile.NamedTemporaryFile(delete=False, |
160 prefix='skia_DEPS_ROLL_tmp_') | 160 prefix='skia_DEPS_ROLL_tmp_') |
161 try: | 161 try: |
162 deps_regex_rev = re.compile(REGEXP_SKIA_REVISION) | 162 deps_regex_rev = re.compile(REGEXP_SKIA_REVISION) |
163 deps_regex_rev_repl = ' "skia_revision": "%s",' % revision | 163 deps_regex_rev_repl = ' "skia_revision": "%s",' % revision |
164 | 164 |
165 with open(depspath, 'r') as input_stream: | 165 with open(depspath, 'r') as input_stream: |
166 for line in input_stream: | 166 for line in input_stream: |
167 line = deps_regex_rev.sub(deps_regex_rev_repl, line) | 167 line = deps_regex_rev.sub(deps_regex_rev_repl, line) |
168 temp_file.write(line) | 168 temp_file.write(line) |
169 finally: | 169 finally: |
170 temp_file.close() | 170 temp_file.close() |
171 shutil.move(temp_file.name, depspath) | 171 shutil.move(temp_file.name, depspath) |
172 | 172 |
173 | 173 |
174 def submit_tries(bots_to_run, dry_run=False): | 174 def submit_tries(bots_to_run, dry_run=False): |
175 """Submit try requests for the current branch on the given bots. | 175 """Submit try requests for the current branch on the given bots. |
176 | 176 |
177 Args: | 177 Args: |
178 bots_to_run: (list of strings) bots to request. | 178 bots_to_run: (list of strings) bots to request. |
179 dry_run: (bool) whether to actually submit the try request. | 179 dry_run: (bool) whether to actually submit the try request. |
180 """ | 180 """ |
181 git_try = [ | 181 git_try = [ |
182 git_utils.GIT, 'cl', 'try', '-m', 'tryserver.chromium'] | 182 git_utils.GIT, 'cl', 'try', '-m', 'tryserver.chromium'] |
183 git_try.extend([arg for bot in bots_to_run for arg in ('-b', bot)]) | 183 git_try.extend([arg for bot in bots_to_run for arg in ('-b', bot)]) |
184 | 184 |
185 if dry_run: | 185 if dry_run: |
186 space = ' ' | 186 space = ' ' |
187 print 'You should call:' | 187 print 'You should call:' |
188 print space, git_try | 188 print space, git_try |
189 print | 189 print |
190 else: | 190 else: |
191 shell_utils.run(git_try) | 191 shell_utils.run(git_try) |
192 | 192 |
193 | 193 |
194 def roll_deps(config, revision): | 194 def roll_deps(config, revision): |
195 """Upload changed DEPS and a whitespace change. | 195 """Upload changed DEPS and a whitespace change. |
196 | 196 |
197 Given the correct git_hash, create two Reitveld issues. | 197 Given the correct git_hash, create two Reitveld issues. |
198 | 198 |
199 Args: | 199 Args: |
200 config: (roll_deps.DepsRollConfig) object containing options. | 200 config: (roll_deps.DepsRollConfig) object containing options. |
201 revision: (string) Skia Git hash. | 201 revision: (string) Skia Git hash. |
202 | 202 |
203 Returns: | 203 Returns: |
204 a tuple containing textual description of the two issues. | 204 a tuple containing textual description of the two issues. |
205 | 205 |
206 Raises: | 206 Raises: |
207 OSError: failed to execute git or git-cl. | 207 OSError: failed to execute git or git-cl. |
208 subprocess.CalledProcessError: git returned unexpected status. | 208 subprocess.CalledProcessError: git returned unexpected status. |
209 """ | 209 """ |
210 | 210 with misc.ChDir(config.chromium_path, verbose=config.verbose): |
211 with misc.ChDir(config.chromium_path, verbose=config.verbose): | 211 git_utils.Fetch() |
212 git_utils.Fetch() | 212 output = shell_utils.run([git_utils.GIT, 'show', 'origin/master:DEPS'], |
213 output = shell_utils.run([git_utils.GIT, 'show', 'origin/master:DEPS'], | 213 log_in_real_time=False).rstrip() |
214 log_in_real_time=False).rstrip() | 214 match = re.search(REGEXP_SKIA_REVISION, output, flags=re.MULTILINE) |
215 match = re.search(REGEXP_SKIA_REVISION, output, flags=re.MULTILINE) | 215 old_revision = None |
216 old_revision = None | 216 if match: |
217 if match: | 217 old_revision = match.group('revision') |
218 old_revision = match.group('revision') | 218 assert old_revision |
219 assert old_revision | 219 |
220 | 220 master_hash = git_utils.FullHash('origin/master').rstrip() |
221 master_hash = git_utils.FullHash('origin/master').rstrip() | 221 |
222 | 222 # master_hash[8] gives each whitespace CL a unique name. |
223 # master_hash[8] gives each whitespace CL a unique name. | 223 branch = 'control_%s' % master_hash[:8] |
224 branch = 'control_%s' % master_hash[:8] | 224 message = ('whitespace change %s\n\n' |
225 message = ('whitespace change %s\n\n' | 225 'Chromium base revision: %s\n\n' |
226 'Chromium base revision: %s\n\n' | 226 'This CL was created by Skia\'s roll_deps.py script.\n' |
227 'This CL was created by Skia\'s roll_deps.py script.\n' | 227 ) % (master_hash[:8], master_hash[:8]) |
228 ) % (master_hash[:8], master_hash[:8]) | 228 with git_utils.GitBranch(branch, message, |
229 with git_utils.GitBranch(branch, message, | 229 delete_when_finished=not config.save_branches, |
230 delete_when_finished=not config.save_branches, | 230 upload=not config.skip_cl_upload |
231 upload=not config.skip_cl_upload | 231 ) as whitespace_branch: |
232 ) as whitespace_branch: | 232 branch = git_utils.GetCurrentBranch() |
233 branch = git_utils.GetCurrentBranch() | 233 with open(os.path.join('build', 'whitespace_file.txt'), 'a') as f: |
234 with open(os.path.join('build', 'whitespace_file.txt'), 'a') as f: | 234 f.write('\nCONTROL\n') |
235 f.write('\nCONTROL\n') | 235 |
236 | 236 control_url = whitespace_branch.commit_and_upload() |
237 control_url = whitespace_branch.commit_and_upload() | 237 if config.cl_bot_list: |
238 if config.cl_bot_list: | 238 submit_tries(config.cl_bot_list, dry_run=config.skip_cl_upload) |
239 submit_tries(config.cl_bot_list, dry_run=config.skip_cl_upload) | 239 whitespace_cl = control_url |
240 whitespace_cl = control_url | 240 if config.save_branches: |
241 if config.save_branches: | 241 whitespace_cl += '\n branch: %s' % branch |
242 whitespace_cl += '\n branch: %s' % branch | 242 |
243 | 243 branch = 'roll_%s_%s' % (revision, master_hash[:8]) |
244 branch = 'roll_%s_%s' % (revision, master_hash[:8]) | 244 message = ( |
245 message = ( | 245 'roll skia DEPS to %s\n\n' |
246 'roll skia DEPS to %s\n\n' | 246 'Chromium base revision: %s\n' |
247 'Chromium base revision: %s\n' | 247 'Old Skia revision: %s\n' |
248 'Old Skia revision: %s\n' | 248 'New Skia revision: %s\n' |
249 'New Skia revision: %s\n' | 249 'Control CL: %s\n\n' |
250 'Control CL: %s\n\n' | 250 'This CL was created by Skia\'s roll_deps.py script.\n\n' |
251 'This CL was created by Skia\'s roll_deps.py script.\n\n' | 251 'Bypassing commit queue trybots:\n' |
252 'Bypassing commit queue trybots:\n' | 252 'NOTRY=true\n' |
253 'NOTRY=true\n' | 253 % (revision, master_hash[:8], |
254 % (revision, master_hash[:8], | 254 old_revision[:8], revision[:8], control_url)) |
255 old_revision[:8], revision[:8], control_url)) | 255 with git_utils.GitBranch(branch, message, |
256 with git_utils.GitBranch(branch, message, | 256 delete_when_finished=not config.save_branches, |
257 delete_when_finished=not config.save_branches, | 257 upload=not config.skip_cl_upload |
258 upload=not config.skip_cl_upload | 258 ) as roll_branch: |
259 ) as roll_branch: | 259 change_skia_deps(revision, 'DEPS') |
260 change_skia_deps(revision, 'DEPS') | 260 deps_url = roll_branch.commit_and_upload() |
261 deps_url = roll_branch.commit_and_upload() | 261 if config.cl_bot_list: |
262 if config.cl_bot_list: | 262 submit_tries(config.cl_bot_list, dry_run=config.skip_cl_upload) |
263 submit_tries(config.cl_bot_list, dry_run=config.skip_cl_upload) | 263 deps_cl = deps_url |
264 deps_cl = deps_url | 264 if config.save_branches: |
265 if config.save_branches: | 265 deps_cl += '\n branch: %s' % branch |
266 deps_cl += '\n branch: %s' % branch | 266 |
267 | 267 return deps_cl, whitespace_cl |
268 return deps_cl, whitespace_cl | |
269 | 268 |
270 | 269 |
271 def main(args): | 270 def main(args): |
272 """main function; see module-level docstring and GetOptionParser help. | 271 """main function; see module-level docstring and GetOptionParser help. |
273 | 272 |
274 Args: | 273 Args: |
275 args: sys.argv[1:]-type argument list. | 274 args: sys.argv[1:]-type argument list. |
276 """ | 275 """ |
277 option_parser = DepsRollConfig.GetOptionParser() | 276 option_parser = DepsRollConfig.GetOptionParser() |
278 options = option_parser.parse_args(args)[0] | 277 options = option_parser.parse_args(args)[0] |
279 | 278 |
280 if not options.revision: | 279 if not options.revision: |
281 option_parser.error('Must specify a revision.') | 280 option_parser.error('Must specify a revision.') |
282 if not options.chromium_path: | 281 if not options.chromium_path: |
283 option_parser.error('Must specify chromium_path.') | 282 option_parser.error('Must specify chromium_path.') |
284 if not os.path.isdir(options.chromium_path): | 283 if not os.path.isdir(options.chromium_path): |
285 option_parser.error('chromium_path must be a directory.') | 284 option_parser.error('chromium_path must be a directory.') |
286 | 285 |
287 config = DepsRollConfig(options) | 286 config = DepsRollConfig(options) |
288 shell_utils.VERBOSE = options.verbose | 287 shell_utils.VERBOSE = options.verbose |
289 deps_issue, whitespace_issue = roll_deps(config, options.revision) | 288 deps_issue, whitespace_issue = roll_deps(config, options.revision) |
290 | 289 |
291 if deps_issue and whitespace_issue: | 290 if deps_issue and whitespace_issue: |
292 print 'DEPS roll:\n %s\n' % deps_issue | 291 print 'DEPS roll:\n %s\n' % deps_issue |
293 print 'Whitespace change:\n %s\n' % whitespace_issue | 292 print 'Whitespace change:\n %s\n' % whitespace_issue |
294 else: | 293 else: |
295 print >> sys.stderr, 'No issues created.' | 294 print >> sys.stderr, 'No issues created.' |
296 | 295 |
297 | 296 |
298 if __name__ == '__main__': | 297 if __name__ == '__main__': |
299 main(sys.argv[1:]) | 298 main(sys.argv[1:]) |
OLD | NEW |