OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | 2 # Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
3 # | 3 # |
4 # Use of this source code is governed by a BSD-style license | 4 # Use of this source code is governed by a BSD-style license |
5 # that can be found in the LICENSE file in the root of the source | 5 # that can be found in the LICENSE file in the root of the source |
6 # tree. An additional intellectual property rights grant can be found | 6 # tree. An additional intellectual property rights grant can be found |
7 # in the file PATENTS. All contributing project authors may | 7 # in the file PATENTS. All contributing project authors may |
8 # be found in the AUTHORS file in the root of the source tree. | 8 # be found in the AUTHORS file in the root of the source tree. |
9 | 9 |
10 """Script to roll chromium_revision in the WebRTC DEPS file.""" | 10 """Script to roll chromium_revision in the WebRTC DEPS file.""" |
11 | 11 |
12 import argparse | 12 import argparse |
13 import base64 | 13 import base64 |
14 import collections | 14 import collections |
15 import logging | 15 import logging |
16 import os | 16 import os |
17 import re | 17 import re |
18 import subprocess | 18 import subprocess |
19 import sys | 19 import sys |
20 import urllib | 20 import urllib |
21 | 21 |
22 | 22 |
23 CHROMIUM_SRC_URL = 'https://chromium.googlesource.com/chromium/src' | 23 CHROMIUM_SRC_URL = 'https://chromium.googlesource.com/chromium/src' |
24 CHROMIUM_COMMIT_TEMPLATE = CHROMIUM_SRC_URL + '/+/%s' | 24 CHROMIUM_COMMIT_TEMPLATE = CHROMIUM_SRC_URL + '/+/%s' |
| 25 CHROMIUM_LOG_TEMPLATE = CHROMIUM_SRC_URL + '/+log/%s' |
25 CHROMIUM_FILE_TEMPLATE = CHROMIUM_SRC_URL + '/+/%s/%s' | 26 CHROMIUM_FILE_TEMPLATE = CHROMIUM_SRC_URL + '/+/%s/%s' |
26 | 27 |
27 COMMIT_POSITION_RE = re.compile('^Cr-Commit-Position: .*#([0-9]+).*$') | 28 COMMIT_POSITION_RE = re.compile('^Cr-Commit-Position: .*#([0-9]+).*$') |
28 CLANG_REVISION_RE = re.compile(r'^CLANG_REVISION=(\d+)$') | 29 CLANG_REVISION_RE = re.compile(r'^CLANG_REVISION=(\d+)$') |
29 ROLL_BRANCH_NAME = 'roll_chromium_revision' | 30 ROLL_BRANCH_NAME = 'roll_chromium_revision' |
30 | 31 |
31 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) | 32 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) |
32 CHECKOUT_ROOT_DIR = os.path.realpath(os.path.join(SCRIPT_DIR, os.pardir, | 33 CHECKOUT_ROOT_DIR = os.path.realpath(os.path.join(SCRIPT_DIR, os.pardir, |
33 os.pardir)) | 34 os.pardir)) |
34 sys.path.append(CHECKOUT_ROOT_DIR) | 35 sys.path.append(CHECKOUT_ROOT_DIR) |
35 import setup_links | 36 import setup_links |
36 | 37 |
37 sys.path.append(os.path.join(CHECKOUT_ROOT_DIR, 'tools')) | 38 sys.path.append(os.path.join(CHECKOUT_ROOT_DIR, 'tools')) |
38 import find_depot_tools | 39 import find_depot_tools |
39 find_depot_tools.add_depot_tools_to_path() | 40 find_depot_tools.add_depot_tools_to_path() |
40 from gclient import GClientKeywords | 41 from gclient import GClientKeywords |
41 | 42 |
42 CLANG_UPDATE_SCRIPT_URL_PATH = 'tools/clang/scripts/update.sh' | 43 CLANG_UPDATE_SCRIPT_URL_PATH = 'tools/clang/scripts/update.sh' |
43 CLANG_UPDATE_SCRIPT_LOCAL_PATH = os.path.join('tools', 'clang', 'scripts', | 44 CLANG_UPDATE_SCRIPT_LOCAL_PATH = os.path.join('tools', 'clang', 'scripts', |
44 'update.sh') | 45 'update.sh') |
45 | 46 |
46 DepsEntry = collections.namedtuple('DepsEntry', 'path url revision') | 47 DepsEntry = collections.namedtuple('DepsEntry', 'path url revision') |
47 ChangedDep = collections.namedtuple('ChangedDep', 'path current_rev new_rev') | 48 ChangedDep = collections.namedtuple('ChangedDep', |
| 49 'path url current_rev new_rev') |
48 | 50 |
49 | 51 |
50 def ParseDepsDict(deps_content): | 52 def ParseDepsDict(deps_content): |
51 local_scope = {} | 53 local_scope = {} |
52 var = GClientKeywords.VarImpl({}, local_scope) | 54 var = GClientKeywords.VarImpl({}, local_scope) |
53 global_scope = { | 55 global_scope = { |
54 'File': GClientKeywords.FileImpl, | 56 'File': GClientKeywords.FileImpl, |
55 'From': GClientKeywords.FromImpl, | 57 'From': GClientKeywords.FromImpl, |
56 'Var': var.Lookup, | 58 'Var': var.Lookup, |
57 'deps_os': {}, | 59 'deps_os': {}, |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
212 for deps_dir in all_deps_dirs: | 214 for deps_dir in all_deps_dirs: |
213 # All deps have 'src' prepended to the path in the Chromium DEPS file. | 215 # All deps have 'src' prepended to the path in the Chromium DEPS file. |
214 dir_path = 'src/%s' % deps_dir | 216 dir_path = 'src/%s' % deps_dir |
215 | 217 |
216 for entry in GetMatchingDepsEntries(current_entries, dir_path): | 218 for entry in GetMatchingDepsEntries(current_entries, dir_path): |
217 new_matching_entries = GetMatchingDepsEntries(new_entries, entry.path) | 219 new_matching_entries = GetMatchingDepsEntries(new_entries, entry.path) |
218 assert len(new_matching_entries) <= 1, ( | 220 assert len(new_matching_entries) <= 1, ( |
219 'Should never find more than one entry matching %s in %s, found %d' % | 221 'Should never find more than one entry matching %s in %s, found %d' % |
220 (entry.path, new_entries, len(new_matching_entries))) | 222 (entry.path, new_entries, len(new_matching_entries))) |
221 if not new_matching_entries: | 223 if not new_matching_entries: |
222 result.append(ChangedDep(entry.path, entry.revision, 'None')) | 224 result.append(ChangedDep(entry.path, entry.url, entry.revision, 'None')) |
223 elif entry != new_matching_entries[0]: | 225 elif entry != new_matching_entries[0]: |
224 result.append(ChangedDep(entry.path, entry.revision, | 226 result.append(ChangedDep(entry.path, entry.url, entry.revision, |
225 new_matching_entries[0].revision)) | 227 new_matching_entries[0].revision)) |
226 return result | 228 return result |
227 | 229 |
228 | 230 |
229 def CalculateChangedClang(new_cr_rev): | 231 def CalculateChangedClang(new_cr_rev): |
230 def GetClangRev(lines): | 232 def GetClangRev(lines): |
231 for line in lines: | 233 for line in lines: |
232 match = CLANG_REVISION_RE.match(line) | 234 match = CLANG_REVISION_RE.match(line) |
233 if match: | 235 if match: |
234 return match.group(1) | 236 return match.group(1) |
235 return None | 237 return None |
236 | 238 |
237 chromium_src_path = os.path.join(CHECKOUT_ROOT_DIR, 'chromium', 'src', | 239 chromium_src_path = os.path.join(CHECKOUT_ROOT_DIR, 'chromium', 'src', |
238 CLANG_UPDATE_SCRIPT_LOCAL_PATH) | 240 CLANG_UPDATE_SCRIPT_LOCAL_PATH) |
239 with open(chromium_src_path, 'rb') as f: | 241 with open(chromium_src_path, 'rb') as f: |
240 current_lines = f.readlines() | 242 current_lines = f.readlines() |
241 current_rev = GetClangRev(current_lines) | 243 current_rev = GetClangRev(current_lines) |
242 | 244 |
243 new_clang_update_sh = ReadRemoteCrFile(CLANG_UPDATE_SCRIPT_URL_PATH, | 245 new_clang_update_sh = ReadRemoteCrFile(CLANG_UPDATE_SCRIPT_URL_PATH, |
244 new_cr_rev).splitlines() | 246 new_cr_rev).splitlines() |
245 new_rev = GetClangRev(new_clang_update_sh) | 247 new_rev = GetClangRev(new_clang_update_sh) |
246 return ChangedDep(CLANG_UPDATE_SCRIPT_LOCAL_PATH, current_rev, new_rev) | 248 return ChangedDep(CLANG_UPDATE_SCRIPT_LOCAL_PATH, None, current_rev, new_rev) |
247 | 249 |
248 | 250 |
249 def GenerateCommitMessage(current_cr_rev, new_cr_rev, changed_deps_list, | 251 def GenerateCommitMessage(current_cr_rev, new_cr_rev, current_commit_pos, |
250 clang_change): | 252 new_commit_pos, changed_deps_list, clang_change): |
251 current_cr_rev = current_cr_rev[0:7] | 253 current_cr_rev = current_cr_rev[0:7] |
252 new_cr_rev = new_cr_rev[0:7] | 254 new_cr_rev = new_cr_rev[0:7] |
253 rev_interval = '%s..%s' % (current_cr_rev, new_cr_rev) | 255 rev_interval = '%s..%s' % (current_cr_rev, new_cr_rev) |
| 256 git_number_interval = '%s:%s' % (current_commit_pos, new_commit_pos) |
254 | 257 |
255 current_git_number = ParseCommitPosition(ReadRemoteCrCommit(current_cr_rev)) | 258 commit_msg = ['Roll chromium_revision %s (%s)\n' % (rev_interval, |
256 new_git_number = ParseCommitPosition(ReadRemoteCrCommit(new_cr_rev)) | 259 git_number_interval)] |
257 git_number_interval = '%s:%s' % (current_git_number, new_git_number) | 260 commit_msg.append('Change log: %s' % (CHROMIUM_LOG_TEMPLATE % rev_interval)) |
| 261 commit_msg.append('Full diff: %s\n' % (CHROMIUM_COMMIT_TEMPLATE % |
| 262 rev_interval)) |
258 | 263 |
259 commit_msg = ['Roll chromium_revision %s (%s)' % (rev_interval, | |
260 git_number_interval)] | |
261 # TBR field will be empty unless in some custom cases, where some engineers | 264 # TBR field will be empty unless in some custom cases, where some engineers |
262 # are added. | 265 # are added. |
263 tbr_authors = '' | 266 tbr_authors = '' |
| 267 |
264 if changed_deps_list: | 268 if changed_deps_list: |
265 commit_msg.append('\nRelevant changes:') | 269 commit_msg.append('Changed dependencies:') |
266 | 270 |
267 for c in changed_deps_list: | 271 for c in changed_deps_list: |
268 commit_msg.append('* %s: %s..%s' % (c.path, c.current_rev[0:7], | 272 commit_msg.append('* %s: %s/+log/%s..%s' % (c.path, c.url, |
269 c.new_rev[0:7])) | 273 c.current_rev[0:7], |
| 274 c.new_rev[0:7])) |
270 if 'libvpx' in c.path: | 275 if 'libvpx' in c.path: |
271 tbr_authors += 'marpan@webrtc.org, stefan@webrtc.org, ' | 276 tbr_authors += 'marpan@webrtc.org, stefan@webrtc.org, ' |
272 | 277 |
273 change_url = CHROMIUM_FILE_TEMPLATE % (rev_interval, 'DEPS') | 278 change_url = CHROMIUM_FILE_TEMPLATE % (rev_interval, 'DEPS') |
274 commit_msg.append('Details: %s' % change_url) | 279 commit_msg.append('DEPS diff: %s\n' % change_url) |
| 280 else: |
| 281 commit_msg.append('No dependencies changed.') |
275 | 282 |
276 if clang_change.current_rev != clang_change.new_rev: | 283 if clang_change.current_rev != clang_change.new_rev: |
277 commit_msg.append('\nClang version changed %s:%s' % | 284 commit_msg.append('Clang version changed %s:%s' % |
278 (clang_change.current_rev, clang_change.new_rev)) | 285 (clang_change.current_rev, clang_change.new_rev)) |
279 change_url = CHROMIUM_FILE_TEMPLATE % (rev_interval, | 286 change_url = CHROMIUM_FILE_TEMPLATE % (rev_interval, |
280 CLANG_UPDATE_SCRIPT_URL_PATH) | 287 CLANG_UPDATE_SCRIPT_URL_PATH) |
281 commit_msg.append('Details: %s' % change_url) | 288 commit_msg.append('Details: %s' % change_url) |
282 tbr_authors += 'pbos@webrtc.org' | 289 tbr_authors += 'pbos@webrtc.org' |
283 else: | 290 else: |
284 commit_msg.append('\nClang version was not updated in this roll.') | 291 commit_msg.append('No update to Clang.') |
| 292 |
285 commit_msg.append('\nTBR=%s\n' % tbr_authors) | 293 commit_msg.append('\nTBR=%s\n' % tbr_authors) |
286 return '\n'.join(commit_msg) | 294 return '\n'.join(commit_msg) |
287 | 295 |
288 | 296 |
289 def UpdateDeps(deps_filename, old_cr_revision, new_cr_revision): | 297 def UpdateDeps(deps_filename, old_cr_revision, new_cr_revision): |
290 """Update the DEPS file with the new revision.""" | 298 """Update the DEPS file with the new revision.""" |
291 with open(deps_filename, 'rb') as deps_file: | 299 with open(deps_filename, 'rb') as deps_file: |
292 deps_content = deps_file.read() | 300 deps_content = deps_file.read() |
293 deps_content = deps_content.replace(old_cr_revision, new_cr_revision) | 301 deps_content = deps_content.replace(old_cr_revision, new_cr_revision) |
294 with open(deps_filename, 'wb') as deps_file: | 302 with open(deps_filename, 'wb') as deps_file: |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
355 p = argparse.ArgumentParser() | 363 p = argparse.ArgumentParser() |
356 p.add_argument('--clean', action='store_true', default=False, | 364 p.add_argument('--clean', action='store_true', default=False, |
357 help='Removes any previous local roll branch.') | 365 help='Removes any previous local roll branch.') |
358 p.add_argument('-r', '--revision', | 366 p.add_argument('-r', '--revision', |
359 help=('Chromium Git revision to roll to. Defaults to the ' | 367 help=('Chromium Git revision to roll to. Defaults to the ' |
360 'Chromium HEAD revision if omitted.')) | 368 'Chromium HEAD revision if omitted.')) |
361 p.add_argument('--dry-run', action='store_true', default=False, | 369 p.add_argument('--dry-run', action='store_true', default=False, |
362 help=('Calculate changes and modify DEPS, but don\'t create ' | 370 help=('Calculate changes and modify DEPS, but don\'t create ' |
363 'any local branch, commit, upload CL or send any ' | 371 'any local branch, commit, upload CL or send any ' |
364 'tryjobs.')) | 372 'tryjobs.')) |
| 373 p.add_argument('--allow-reverse', action='store_true', default=False, |
| 374 help=('Allow rolling back in time (disabled by default but ' |
| 375 'may be useful to be able do to manually).')) |
365 p.add_argument('-s', '--skip-try', action='store_true', default=False, | 376 p.add_argument('-s', '--skip-try', action='store_true', default=False, |
366 help='Do everything except sending tryjobs.') | 377 help='Do everything except sending tryjobs.') |
367 p.add_argument('-v', '--verbose', action='store_true', default=False, | 378 p.add_argument('-v', '--verbose', action='store_true', default=False, |
368 help='Be extra verbose in printing of log messages.') | 379 help='Be extra verbose in printing of log messages.') |
369 opts = p.parse_args() | 380 opts = p.parse_args() |
370 | 381 |
371 if opts.verbose: | 382 if opts.verbose: |
372 logging.basicConfig(level=logging.DEBUG) | 383 logging.basicConfig(level=logging.DEBUG) |
373 else: | 384 else: |
374 logging.basicConfig(level=logging.INFO) | 385 logging.basicConfig(level=logging.INFO) |
375 | 386 |
376 if not _IsTreeClean(): | 387 if not _IsTreeClean(): |
377 logging.error('Please clean your local checkout first.') | 388 logging.error('Please clean your local checkout first.') |
378 return 1 | 389 return 1 |
379 | 390 |
380 if opts.clean: | 391 if opts.clean: |
381 _RemovePreviousRollBranch(opts.dry_run) | 392 _RemovePreviousRollBranch(opts.dry_run) |
382 | 393 |
383 _EnsureUpdatedMasterBranch(opts.dry_run) | 394 _EnsureUpdatedMasterBranch(opts.dry_run) |
384 | 395 |
385 if not opts.revision: | 396 new_cr_rev = opts.revision |
| 397 if not new_cr_rev: |
386 stdout, _ = _RunCommand(['git', 'ls-remote', CHROMIUM_SRC_URL, 'HEAD']) | 398 stdout, _ = _RunCommand(['git', 'ls-remote', CHROMIUM_SRC_URL, 'HEAD']) |
387 head_rev = stdout.strip().split('\t')[0] | 399 head_rev = stdout.strip().split('\t')[0] |
388 logging.info('No revision specified. Using HEAD: %s', head_rev) | 400 logging.info('No revision specified. Using HEAD: %s', head_rev) |
389 opts.revision = head_rev | 401 new_cr_rev = head_rev |
390 | 402 |
391 deps_filename = os.path.join(CHECKOUT_ROOT_DIR, 'DEPS') | 403 deps_filename = os.path.join(CHECKOUT_ROOT_DIR, 'DEPS') |
392 local_deps = ParseLocalDepsFile(deps_filename) | 404 local_deps = ParseLocalDepsFile(deps_filename) |
393 current_cr_rev = local_deps['vars']['chromium_revision'] | 405 current_cr_rev = local_deps['vars']['chromium_revision'] |
394 | 406 |
| 407 current_commit_pos = ParseCommitPosition(ReadRemoteCrCommit(current_cr_rev)) |
| 408 new_commit_pos = ParseCommitPosition(ReadRemoteCrCommit(new_cr_rev)) |
| 409 |
395 current_cr_deps = ParseRemoteCrDepsFile(current_cr_rev) | 410 current_cr_deps = ParseRemoteCrDepsFile(current_cr_rev) |
396 new_cr_deps = ParseRemoteCrDepsFile(opts.revision) | 411 new_cr_deps = ParseRemoteCrDepsFile(new_cr_rev) |
397 | 412 |
398 changed_deps = sorted(CalculateChangedDeps(current_cr_deps, new_cr_deps)) | 413 if new_commit_pos > current_commit_pos or opts.allow_reverse: |
399 clang_change = CalculateChangedClang(opts.revision) | 414 changed_deps = sorted(CalculateChangedDeps(current_cr_deps, new_cr_deps)) |
400 if changed_deps or clang_change: | 415 clang_change = CalculateChangedClang(new_cr_rev) |
401 commit_msg = GenerateCommitMessage(current_cr_rev, opts.revision, | 416 commit_msg = GenerateCommitMessage(current_cr_rev, new_cr_rev, |
| 417 current_commit_pos, new_commit_pos, |
402 changed_deps, clang_change) | 418 changed_deps, clang_change) |
403 logging.debug('Commit message:\n%s', commit_msg) | 419 logging.debug('Commit message:\n%s', commit_msg) |
404 else: | 420 else: |
405 logging.info('No deps changes detected when rolling from %s to %s. ' | 421 logging.info('Currently pinned chromium_revision: %s (#%s) is newer than ' |
406 'Aborting without action.', current_cr_rev, opts.revision) | 422 '%s (#%s). To roll to older revisions, you must pass the ' |
| 423 '--allow-reverse flag.\n' |
| 424 'Aborting without action.', current_cr_rev, current_commit_pos, |
| 425 new_cr_rev, new_commit_pos) |
407 return 0 | 426 return 0 |
408 | 427 |
409 _CreateRollBranch(opts.dry_run) | 428 _CreateRollBranch(opts.dry_run) |
410 UpdateDeps(deps_filename, current_cr_rev, opts.revision) | 429 UpdateDeps(deps_filename, current_cr_rev, new_cr_rev) |
411 _LocalCommit(commit_msg, opts.dry_run) | 430 _LocalCommit(commit_msg, opts.dry_run) |
412 _UploadCL(opts.dry_run) | 431 _UploadCL(opts.dry_run) |
413 _LaunchTrybots(opts.dry_run, opts.skip_try) | 432 _LaunchTrybots(opts.dry_run, opts.skip_try) |
414 return 0 | 433 return 0 |
415 | 434 |
416 | 435 |
417 if __name__ == '__main__': | 436 if __name__ == '__main__': |
418 sys.exit(main()) | 437 sys.exit(main()) |
OLD | NEW |