OLD | NEW |
| (Empty) |
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 """Generate a CL to roll a DEPS entry to the specified revision number and post | |
7 it to Rietveld so that the CL will land automatically if it passes the | |
8 commit-queue's checks. | |
9 """ | |
10 | |
11 import logging | |
12 import optparse | |
13 import os | |
14 import re | |
15 import sys | |
16 | |
17 import find_depot_tools | |
18 import scm | |
19 import subprocess2 | |
20 | |
21 | |
22 def die_with_error(msg): | |
23 print >> sys.stderr, msg | |
24 sys.exit(1) | |
25 | |
26 | |
27 def process_deps(path, project, new_rev, is_dry_run): | |
28 """Update project_revision to |new_issue|. | |
29 | |
30 A bit hacky, could it be made better? | |
31 """ | |
32 content = open(path).read() | |
33 # Hack for Blink to get the AutoRollBot running again. | |
34 if project == "blink": | |
35 project = "webkit" | |
36 old_line = r'(\s+)"%s_revision": "([0-9a-f]{2,40})",' % project | |
37 new_line = r'\1"%s_revision": "%s",' % (project, new_rev) | |
38 new_content = re.sub(old_line, new_line, content, 1) | |
39 old_rev = re.search(old_line, content).group(2) | |
40 if not old_rev or new_content == content: | |
41 die_with_error('Failed to update the DEPS file') | |
42 | |
43 if not is_dry_run: | |
44 open(path, 'w').write(new_content) | |
45 return old_rev | |
46 | |
47 | |
48 class PrintSubprocess(object): | |
49 """Wrapper for subprocess2 which prints out every command.""" | |
50 def __getattr__(self, attr): | |
51 def _run_subprocess2(cmd, *args, **kwargs): | |
52 print cmd | |
53 sys.stdout.flush() | |
54 return getattr(subprocess2, attr)(cmd, *args, **kwargs) | |
55 return _run_subprocess2 | |
56 | |
57 prnt_subprocess = PrintSubprocess() | |
58 | |
59 | |
60 def main(): | |
61 tool_dir = os.path.dirname(os.path.abspath(__file__)) | |
62 parser = optparse.OptionParser(usage='%prog [options] <project> <new rev>', | |
63 description=sys.modules[__name__].__doc__) | |
64 parser.add_option('-v', '--verbose', action='count', default=0) | |
65 parser.add_option('--dry-run', action='store_true') | |
66 parser.add_option('-f', '--force', action='store_true', | |
67 help='Make destructive changes to the local checkout if ' | |
68 'necessary.') | |
69 parser.add_option('--commit', action='store_true', default=True, | |
70 help='(default) Put change in commit queue on upload.') | |
71 parser.add_option('--no-commit', action='store_false', dest='commit', | |
72 help='Don\'t put change in commit queue on upload.') | |
73 parser.add_option('-r', '--reviewers', default='', | |
74 help='Add given users as either reviewers or TBR as' | |
75 ' appropriate.') | |
76 parser.add_option('--upstream', default='origin/master', | |
77 help='(default "%default") Use given start point for change' | |
78 ' to upload. For instance, if you use the old git workflow,' | |
79 ' you might set it to "origin/trunk".') | |
80 parser.add_option('--cc', help='CC email addresses for issue.') | |
81 parser.add_option('-m', '--message', help='Custom commit message.') | |
82 | |
83 options, args = parser.parse_args() | |
84 logging.basicConfig( | |
85 level= | |
86 [logging.WARNING, logging.INFO, logging.DEBUG][ | |
87 min(2, options.verbose)]) | |
88 if len(args) != 2: | |
89 parser.print_help() | |
90 exit(0) | |
91 | |
92 root_dir = os.path.dirname(tool_dir) | |
93 os.chdir(root_dir) | |
94 | |
95 project = args[0] | |
96 new_rev = args[1] | |
97 | |
98 # Silence the editor. | |
99 os.environ['EDITOR'] = 'true' | |
100 | |
101 if options.force and not options.dry_run: | |
102 prnt_subprocess.check_call(['git', 'clean', '-d', '-f']) | |
103 prnt_subprocess.call(['git', 'rebase', '--abort']) | |
104 | |
105 old_branch = scm.GIT.GetBranch(root_dir) | |
106 new_branch = '%s_roll' % project | |
107 | |
108 if options.upstream == new_branch: | |
109 parser.error('Cannot set %s as its own upstream.' % new_branch) | |
110 | |
111 if old_branch == new_branch: | |
112 if options.force: | |
113 if not options.dry_run: | |
114 prnt_subprocess.check_call(['git', 'checkout', options.upstream, '-f']) | |
115 prnt_subprocess.call(['git', 'branch', '-D', old_branch]) | |
116 else: | |
117 parser.error('Please delete the branch %s and move to a different branch' | |
118 % new_branch) | |
119 | |
120 if not options.dry_run: | |
121 prnt_subprocess.check_call(['git', 'fetch', 'origin']) | |
122 prnt_subprocess.call(['git', 'svn', 'fetch']) | |
123 branch_cmd = ['git', 'checkout', '-b', new_branch, options.upstream] | |
124 if options.force: | |
125 branch_cmd.append('-f') | |
126 prnt_subprocess.check_output(branch_cmd) | |
127 | |
128 try: | |
129 old_rev = process_deps(os.path.join(root_dir, 'DEPS'), project, new_rev, | |
130 options.dry_run) | |
131 print '%s roll %s:%s' % (project.title(), old_rev, new_rev) | |
132 | |
133 review_field = 'TBR' if options.commit else 'R' | |
134 commit_msg = options.message or '%s roll %s:%s\n' % (project.title(), | |
135 old_rev, new_rev) | |
136 commit_msg += '\n%s=%s\n' % (review_field, options.reviewers) | |
137 | |
138 if options.dry_run: | |
139 print 'Commit message: ' + commit_msg | |
140 return 0 | |
141 | |
142 prnt_subprocess.check_output(['git', 'commit', '-m', commit_msg, 'DEPS']) | |
143 prnt_subprocess.check_call(['git', 'diff', '--no-ext-diff', | |
144 options.upstream]) | |
145 upload_cmd = ['git', 'cl', 'upload'] | |
146 if options.commit: | |
147 upload_cmd.append('--use-commit-queue') | |
148 if options.reviewers: | |
149 upload_cmd.append('--send-mail') | |
150 if options.cc: | |
151 upload_cmd.extend(['--cc', options.cc]) | |
152 prnt_subprocess.check_call(upload_cmd) | |
153 finally: | |
154 if not options.dry_run: | |
155 prnt_subprocess.check_output(['git', 'checkout', old_branch]) | |
156 prnt_subprocess.check_output(['git', 'branch', '-D', new_branch]) | |
157 return 0 | |
158 | |
159 | |
160 if __name__ == '__main__': | |
161 sys.exit(main()) | |
OLD | NEW |