| 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 |