OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2014 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2014 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """This scripts takes the path to a dep and an svn revision, and updates the | 6 """This scripts takes the path to a dep and an svn revision, and updates the |
7 parent repo's DEPS file with the corresponding git revision. Sample invocation: | 7 parent repo's DEPS file with the corresponding git revision. Sample invocation: |
8 | 8 |
9 [chromium/src]$ roll-dep third_party/WebKit 12345 | 9 [chromium/src]$ roll-dep third_party/WebKit 12345 |
10 | 10 |
11 After the script completes, the DEPS file will be dirty with the new revision. | 11 After the script completes, the DEPS file will be dirty with the new revision. |
12 The user can then: | 12 The user can then: |
13 | 13 |
14 $ git add DEPS | 14 $ git add DEPS |
15 $ git commit | 15 $ git commit |
16 """ | 16 """ |
17 | 17 |
18 import ast | 18 import ast |
19 import os | 19 import os |
20 import re | 20 import re |
21 import sys | 21 import sys |
22 | 22 |
23 from itertools import izip | 23 from itertools import izip |
24 from subprocess import Popen, PIPE | 24 from subprocess import check_output, Popen, PIPE |
25 from textwrap import dedent | 25 from textwrap import dedent |
26 | 26 |
27 | 27 |
28 SHA1_RE = re.compile('^[a-fA-F0-9]{40}$') | 28 SHA1_RE = re.compile('^[a-fA-F0-9]{40}$') |
29 GIT_SVN_ID_RE = re.compile('^git-svn-id: .*@([0-9]+) .*$') | 29 GIT_SVN_ID_RE = re.compile('^git-svn-id: .*@([0-9]+) .*$') |
30 ROLL_DESCRIPTION_STR = '''Roll %s from %s to %s | 30 ROLL_DESCRIPTION_STR = ( |
| 31 '''Roll %(dep_path)s %(before_rev)s:%(after_rev)s%(svn_range)s |
31 | 32 |
32 Summary of changes available at: | 33 Summary of changes available at: |
33 %s | 34 %(revlog_url)s |
34 ''' | 35 ''') |
35 | 36 |
36 | 37 |
37 def shorten_dep_path(dep): | 38 def shorten_dep_path(dep): |
38 """Shorten the given dep path if necessary.""" | 39 """Shorten the given dep path if necessary.""" |
39 while len(dep) > 31: | 40 while len(dep) > 31: |
40 dep = '.../' + dep.lstrip('./').partition('/')[2] | 41 dep = '.../' + dep.lstrip('./').partition('/')[2] |
41 return dep | 42 return dep |
42 | 43 |
43 | 44 |
44 def posix_path(path): | 45 def posix_path(path): |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
248 git revision.""" | 249 git revision.""" |
249 vars_node = find_deps_section(deps_ast, 'vars') | 250 vars_node = find_deps_section(deps_ast, 'vars') |
250 assert vars_node, 'Could not find "vars" section of DEPS file.' | 251 assert vars_node, 'Could not find "vars" section of DEPS file.' |
251 var_idx = find_dict_index(vars_node, var_name) | 252 var_idx = find_dict_index(vars_node, var_name) |
252 assert var_idx is not None, ( | 253 assert var_idx is not None, ( |
253 'Could not find definition of "%s" var in DEPS file.' % var_name) | 254 'Could not find definition of "%s" var in DEPS file.' % var_name) |
254 val_node = vars_node.values[var_idx] | 255 val_node = vars_node.values[var_idx] |
255 return update_node(deps_lines, deps_ast, val_node, git_revision) | 256 return update_node(deps_lines, deps_ast, val_node, git_revision) |
256 | 257 |
257 | 258 |
258 def generate_commit_message(deps_section, dep_name, new_rev): | 259 def short_rev(rev, dep_path): |
| 260 return check_output(['git', 'rev-parse', '--short', rev], |
| 261 cwd=dep_path).rstrip() |
| 262 |
| 263 |
| 264 def generate_commit_message(deps_section, dep_path, dep_name, new_rev): |
259 (url, _, old_rev) = deps_section[dep_name].partition('@') | 265 (url, _, old_rev) = deps_section[dep_name].partition('@') |
260 if url.endswith('.git'): | 266 if url.endswith('.git'): |
261 url = url[:-4] | 267 url = url[:-4] |
262 url += '/+log/%s..%s' % (old_rev[:12], new_rev[:12]) | 268 old_rev_short = short_rev(old_rev, dep_path) |
263 return dedent(ROLL_DESCRIPTION_STR % ( | 269 new_rev_short = short_rev(new_rev, dep_path) |
264 shorten_dep_path(dep_name), old_rev[:12], new_rev[:12], url)) | 270 url += '/+log/%s..%s' % (old_rev_short, new_rev_short) |
| 271 old_svn_rev = get_svn_revision(dep_path, old_rev) |
| 272 new_svn_rev = get_svn_revision(dep_path, new_rev) |
| 273 svn_range_str = '' |
| 274 if old_svn_rev and new_svn_rev: |
| 275 svn_range_str = ' (svn %s:%s)' % (old_svn_rev, new_svn_rev) |
| 276 return dedent(ROLL_DESCRIPTION_STR % { |
| 277 'dep_path': shorten_dep_path(dep_name), |
| 278 'before_rev': old_rev_short, |
| 279 'after_rev': new_rev_short, |
| 280 'svn_range': svn_range_str, |
| 281 'revlog_url': url, |
| 282 }) |
265 | 283 |
266 def update_deps_entry(deps_lines, deps_ast, value_node, new_rev, comment): | 284 def update_deps_entry(deps_lines, deps_ast, value_node, new_rev, comment): |
267 line_idx = update_node(deps_lines, deps_ast, value_node, new_rev) | 285 line_idx = update_node(deps_lines, deps_ast, value_node, new_rev) |
268 (content, _, _) = deps_lines[line_idx].partition('#') | 286 (content, _, _) = deps_lines[line_idx].partition('#') |
269 if comment: | 287 if comment: |
270 deps_lines[line_idx] = '%s # %s' % (content.rstrip(), comment) | 288 deps_lines[line_idx] = '%s # %s' % (content.rstrip(), comment) |
271 else: | 289 else: |
272 deps_lines[line_idx] = content.rstrip() | 290 deps_lines[line_idx] = content.rstrip() |
273 | 291 |
274 def update_deps(soln_path, dep_name, new_rev, comment): | 292 def update_deps(soln_path, dep_path, dep_name, new_rev, comment): |
275 """Update the DEPS file with the new git revision.""" | 293 """Update the DEPS file with the new git revision.""" |
276 commit_msg = '' | 294 commit_msg = '' |
277 deps_file = os.path.join(soln_path, 'DEPS') | 295 deps_file = os.path.join(soln_path, 'DEPS') |
278 with open(deps_file) as fh: | 296 with open(deps_file) as fh: |
279 deps_content = fh.read() | 297 deps_content = fh.read() |
280 deps_locals = {} | 298 deps_locals = {} |
281 def _Var(key): | 299 def _Var(key): |
282 return deps_locals['vars'][key] | 300 return deps_locals['vars'][key] |
283 deps_locals['Var'] = _Var | 301 deps_locals['Var'] = _Var |
284 exec deps_content in {}, deps_locals | 302 exec deps_content in {}, deps_locals |
285 deps_lines = deps_content.splitlines() | 303 deps_lines = deps_content.splitlines() |
286 deps_ast = ast.parse(deps_content, deps_file) | 304 deps_ast = ast.parse(deps_content, deps_file) |
287 deps_node = find_deps_section(deps_ast, 'deps') | 305 deps_node = find_deps_section(deps_ast, 'deps') |
288 assert deps_node, 'Could not find "deps" section of DEPS file' | 306 assert deps_node, 'Could not find "deps" section of DEPS file' |
289 dep_idx = find_dict_index(deps_node, dep_name) | 307 dep_idx = find_dict_index(deps_node, dep_name) |
290 if dep_idx is not None: | 308 if dep_idx is not None: |
291 value_node = deps_node.values[dep_idx] | 309 value_node = deps_node.values[dep_idx] |
292 update_deps_entry(deps_lines, deps_ast, value_node, new_rev, comment) | 310 update_deps_entry(deps_lines, deps_ast, value_node, new_rev, comment) |
293 commit_msg = generate_commit_message(deps_locals['deps'], dep_name, new_rev) | 311 commit_msg = generate_commit_message(deps_locals['deps'], dep_path, |
| 312 dep_name, new_rev) |
294 deps_os_node = find_deps_section(deps_ast, 'deps_os') | 313 deps_os_node = find_deps_section(deps_ast, 'deps_os') |
295 if deps_os_node: | 314 if deps_os_node: |
296 for (os_name, os_node) in izip(deps_os_node.keys, deps_os_node.values): | 315 for (os_name, os_node) in izip(deps_os_node.keys, deps_os_node.values): |
297 dep_idx = find_dict_index(os_node, dep_name) | 316 dep_idx = find_dict_index(os_node, dep_name) |
298 if dep_idx is not None: | 317 if dep_idx is not None: |
299 value_node = os_node.values[dep_idx] | 318 value_node = os_node.values[dep_idx] |
300 if value_node.__class__ is ast.Name and value_node.id == 'None': | 319 if value_node.__class__ is ast.Name and value_node.id == 'None': |
301 pass | 320 pass |
302 else: | 321 else: |
303 update_deps_entry(deps_lines, deps_ast, value_node, new_rev, comment) | 322 update_deps_entry(deps_lines, deps_ast, value_node, new_rev, comment) |
304 commit_msg = generate_commit_message( | 323 commit_msg = generate_commit_message( |
305 deps_locals['deps_os'][os_name], dep_name, new_rev) | 324 deps_locals['deps_os'][os_name], dep_path, dep_name, new_rev) |
306 if commit_msg: | 325 if commit_msg: |
307 print 'Pinning %s' % dep_name | 326 print 'Pinning %s' % dep_name |
308 print 'to revision %s' % new_rev | 327 print 'to revision %s' % new_rev |
309 print 'in %s' % deps_file | 328 print 'in %s' % deps_file |
310 with open(deps_file, 'w') as fh: | 329 with open(deps_file, 'w') as fh: |
311 for line in deps_lines: | 330 for line in deps_lines: |
312 print >> fh, line | 331 print >> fh, line |
313 with open(os.path.join(soln_path, '.git', 'MERGE_MSG'), 'a') as fh: | 332 with open(os.path.join(soln_path, '.git', 'MERGE_MSG'), 'a') as fh: |
314 fh.write(commit_msg) | 333 fh.write(commit_msg) |
315 else: | 334 else: |
316 print 'Could not find an entry in %s to update.' % deps_file | 335 print 'Could not find an entry in %s to update.' % deps_file |
317 return 0 if commit_msg else 1 | 336 return 0 if commit_msg else 1 |
318 | 337 |
319 | 338 |
320 def main(argv): | 339 def main(argv): |
321 if len(argv) != 2 : | 340 if len(argv) != 2 : |
322 print >> sys.stderr, 'Usage: roll_dep.py <dep path> <svn revision>' | 341 print >> sys.stderr, 'Usage: roll_dep.py <dep path> <svn revision>' |
323 return 1 | 342 return 1 |
324 (dep_path, revision) = argv[0:2] | 343 (dep_path, revision) = argv[0:2] |
325 dep_path = platform_path(dep_path) | 344 dep_path = platform_path(dep_path) |
326 assert os.path.isdir(dep_path), 'No such directory: %s' % dep_path | 345 assert os.path.isdir(dep_path), 'No such directory: %s' % dep_path |
327 gclient_root = find_gclient_root() | 346 gclient_root = find_gclient_root() |
328 soln = get_solution(gclient_root, dep_path) | 347 soln = get_solution(gclient_root, dep_path) |
329 soln_path = os.path.relpath(os.path.join(gclient_root, soln['name'])) | 348 soln_path = os.path.relpath(os.path.join(gclient_root, soln['name'])) |
330 dep_name = posix_path(os.path.relpath(dep_path, gclient_root)) | 349 dep_name = posix_path(os.path.relpath(dep_path, gclient_root)) |
331 (git_rev, svn_rev) = get_git_revision(dep_path, revision) | 350 (git_rev, svn_rev) = get_git_revision(dep_path, revision) |
332 comment = ('from svn revision %s' % svn_rev) if svn_rev else None | 351 comment = ('from svn revision %s' % svn_rev) if svn_rev else None |
333 assert git_rev, 'Could not find git revision matching %s.' % revision | 352 assert git_rev, 'Could not find git revision matching %s.' % revision |
334 return update_deps(soln_path, dep_name, git_rev, comment) | 353 return update_deps(soln_path, dep_path, dep_name, git_rev, comment) |
335 | 354 |
336 if __name__ == '__main__': | 355 if __name__ == '__main__': |
337 sys.exit(main(sys.argv[1:])) | 356 sys.exit(main(sys.argv[1:])) |
OLD | NEW |