1 #!/usr/bin/env python 2 # Copyright 2014 The Chromium Authors. All rights reserved. 3 # Use of this source code is governed by a BSD-style license that can be 4 # found in the LICENSE file. 5 6 """Rolls swarming_client. 7 8 While it is currently hard coded for swarming_client/, it is potentially 9 modifiable to allow different dependencies. Works only with git checkout and git 10 dependencies. 11 """ 12 13 import optparse 14 import os 15 import re 16 import subprocess 17 import sys 18 19 SRC_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 20 21 22 def is_pristine(root, merge_base='origin/master'): 23 """Returns True is a git checkout is pristine.""" 24 cmd = ['git', 'diff', '--ignore-submodules', merge_base] 25 return not ( 26 subprocess.check_output(cmd, cwd=root).strip() or 27 subprocess.check_output(cmd + ['--cached'], cwd=root).strip()) 28 29 30 def roll(deps_dir, key, reviewer, bug): 31 if not is_pristine(SRC_ROOT): 32 print >> sys.stderr, 'Ensure %s is clean first.' % SRC_ROOT 33 return 1 34 35 full_dir = os.path.join(SRC_ROOT, deps_dir) 36 head = subprocess.check_output( 37 ['git', 'rev-parse', 'HEAD'], cwd=full_dir).strip() 38 deps = os.path.join(SRC_ROOT, 'DEPS') 39 with open(deps, 'rb') as f: 40 deps_content = f.read() 41 42 if not head in deps_content: 43 print('Warning: %s is not checked out at the expected revision in DEPS' % 44 deps_dir) 45 # It happens if the user checked out a branch in the dependency by himself. 46 # Fall back to reading the DEPS to figure out the original commit. 47 for i in deps_content.splitlines(): 48 m = re.match(r'\s+"' + key + '": "([a-z0-9]{40})",', i) 49 if m: 50 head = m.group(1) 51 break 52 else: 53 print >> sys.stderr, 'Expected to find commit %s for %s in DEPS' % ( 54 head, key) 55 return 1 56 57 print('Found old revision %s' % head) 58 59 subprocess.check_call(['git', 'fetch', 'origin'], cwd=full_dir) 60 master = subprocess.check_output( 61 ['git', 'rev-parse', 'origin/master'], cwd=full_dir).strip() 62 print('Found new revision %s' % master) 63 64 if master == head: 65 print('No revision to roll!') 66 return 1 67 68 commit_range = '%s..%s' % (head[:9], master[:9]) 69 logs = subprocess.check_output( 70 ['git', 'log', commit_range, '--date=short', '--format=%ad %ae %s'], 71 cwd=full_dir).strip() 72 logs = logs.replace('@chromium.org', '') 73 cmd = ( 74 'git log %s --date=short --format=\'%%ad %%ae %%s\' | ' 75 'sed \'s/@chromium\.org//\'') % commit_range 76 77 msg = ( 78 'Roll %s/ to %s.\n' 79 '\n' 80 '$ %s\n' 81 '%s\n\n' 82 'R=%s\n' 83 'BUG=%s') % ( 84 deps_dir, 85 master, 86 cmd, 87 logs, 88 reviewer, 89 bug) 90 91 print('Commit message:') 92 print('\n'.join(' ' + i for i in msg.splitlines())) 93 deps_content = deps_content.replace(head, master) 94 with open(deps, 'wb') as f: 95 f.write(deps_content) 96 subprocess.check_call(['git', 'add', 'DEPS'], cwd=SRC_ROOT) 97 subprocess.check_call(['git', 'commit', '-m', msg], cwd=SRC_ROOT) 98 print('Run:') 99 print(' git cl upl --send-mail') 100 return 0 101 102 103 def main(): 104 parser = optparse.OptionParser(description=sys.modules[__name__].__doc__) 105 parser.add_option( 106 '-r', '--reviewer', default='', 107 help='To specify multiple reviewers, use comma separated list, e.g. ' 108 '-r joe,jack,john. Defaults to @chromium.org') 109 parser.add_option('-b', '--bug', default='') 110 options, args = parser.parse_args() 111 if args: 112 parser.error('Unknown argument %s' % args) 113 if not options.reviewer: 114 parser.error('Pass a reviewer right away with -r/--reviewer') 115 116 reviewers = options.reviewer.split(',') 117 for i, r in enumerate(reviewers): 118 if not '@' in r: 119 reviewers[i] = r + '@chromium.org' 120 121 return roll( 122 'tools/swarming_client', 123 'swarming_revision', 124 ','.join(reviewers), 125 options.bug) 126 127 128 if __name__ == '__main__': 129 sys.exit(main()) 130