Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2011 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 import optparse | 6 import optparse |
| 7 import os | 7 import os |
| 8 import re | 8 import re |
| 9 import string | |
| 9 import sys | 10 import sys |
| 11 import urllib2 | |
| 10 | 12 |
| 11 import breakpad # pylint: disable=W0611 | 13 import breakpad # pylint: disable=W0611 |
| 12 | 14 |
| 13 import gclient_utils | 15 import gclient_utils |
| 14 import subprocess2 | 16 import subprocess2 |
| 15 | 17 |
| 16 USAGE = """ | 18 USAGE = """ |
| 17 WARNING: Please use this tool in an empty directory | 19 WARNING: Please use this tool in an empty directory |
| 18 (or at least one that you don't mind clobbering.) | 20 (or at least one that you don't mind clobbering.) |
| 19 | 21 |
| 20 REQUIRES: SVN 1.5+ | 22 REQUIRES: SVN 1.5+ |
| 21 NOTE: NO NEED TO CHECKOUT ANYTHING IN ADVANCE OF USING THIS TOOL. | 23 NOTE: NO NEED TO CHECKOUT ANYTHING IN ADVANCE OF USING THIS TOOL. |
| 22 Valid parameters: | 24 Valid parameters: |
| 23 | 25 |
| 24 [Merge from trunk to branch] | 26 [Merge from trunk to branch] |
| 25 --merge <revision> --branch <branch_num> | 27 --merge <revision> --branch <branch_num> |
| 26 Example: %(app)s --merge 12345 --branch 187 | 28 Example: %(app)s --merge 12345 --branch 187 |
| 27 | 29 |
| 30 [Merge from trunk to milestone] | |
| 31 --merge <revision> --milestone <milestone_num> | |
| 32 Example: %(app)s -- merge 12345 --milestone 16 | |
| 33 | |
| 28 [Merge from trunk to local copy] | 34 [Merge from trunk to local copy] |
| 29 --merge <revision> --local | 35 --merge <revision> --local |
| 30 Example: %(app)s --merge 12345 --local | 36 Example: %(app)s --merge 12345 --local |
| 31 | 37 |
| 32 [Merge from branch to branch] | 38 [Merge from branch to branch] |
| 33 --merge <revision> --sbranch <branch_num> --branch <branch_num> | 39 --merge <revision> --sbranch <branch_num> --branch <branch_num> |
| 34 Example: %(app)s --merge 12345 --sbranch 248 --branch 249 | 40 Example: %(app)s --merge 12345 --sbranch 248 --branch 249 |
| 35 | 41 |
| 36 [Revert from trunk] | 42 [Revert from trunk] |
| 37 --revert <revision> | 43 --revert <revision> |
| (...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 350 | 356 |
| 351 | 357 |
| 352 def getAllFilesInRevision(files_info): | 358 def getAllFilesInRevision(files_info): |
| 353 """Checks for existing files in the revision. | 359 """Checks for existing files in the revision. |
| 354 | 360 |
| 355 Anything that's A will require special treatment (either a merge or an | 361 Anything that's A will require special treatment (either a merge or an |
| 356 export + add) | 362 export + add) |
| 357 """ | 363 """ |
| 358 return ['%s/%s' % (f[2], f[3]) for f in files_info] | 364 return ['%s/%s' % (f[2], f[3]) for f in files_info] |
| 359 | 365 |
| 366 def getBranchForMilestone(milestone): | |
| 367 """Queries omahaproxy.appspot.com for the branch number given |milestone|. | |
| 368 """ | |
| 369 OMAHA_PROXY_URL = "http://omahaproxy.appspot.com" | |
| 370 request = urllib2.Request(OMAHA_PROXY_URL) | |
| 371 try: | |
| 372 response = urllib2.urlopen(request) | |
| 373 except urllib2.HTTPError, e: | |
| 374 print "Failed to query %s: %d" % (OMAHA_PROXY_URL, e.code) | |
| 375 return None | |
| 376 | |
| 377 # Slice the first line since it's column information text. | |
| 378 for line in response.readlines()[1:]: | |
|
laforge
2011/11/09 05:06:12
This approach is a little dangerous, but will prob
James Hawkins
2011/11/10 03:37:36
There are two separate things we can do here:
* De
| |
| 379 # Version data is CSV. | |
| 380 parameters = string.split(line, ',') | |
| 381 | |
| 382 # Milestone is the third parameter. | |
| 383 full_milestone = parameters[2] | |
|
laforge
2011/11/09 05:06:12
It would probably be clearer to call this var vers
James Hawkins
2011/11/10 03:37:36
Done.
| |
| 384 | |
| 385 # Full milestone is a quad of numbers separated by periods. | |
| 386 milestone_str = string.split(full_milestone, '.')[0] | |
| 387 if int(milestone_str, 10) != milestone: | |
| 388 continue | |
| 389 | |
| 390 # Correct milestone found. Return the branch parameter, which is last. | |
| 391 return parameters[len(parameters) - 1] | |
|
laforge
2011/11/09 05:06:12
It would be better here to return full_mstone.spli
James Hawkins
2011/11/10 03:37:36
Done.
| |
| 392 | |
| 393 # Milestone not found. | |
| 394 print "Milestone provided is invalid" | |
| 395 return None | |
| 396 | |
| 360 def prompt(question): | 397 def prompt(question): |
| 361 while True: | 398 while True: |
| 362 print question + " [y|n]:", | 399 print question + " [y|n]:", |
| 363 answer = sys.stdin.readline() | 400 answer = sys.stdin.readline() |
| 364 if answer.lower().startswith('n'): | 401 if answer.lower().startswith('n'): |
| 365 return False | 402 return False |
| 366 elif answer.lower().startswith('y'): | 403 elif answer.lower().startswith('y'): |
| 367 return True | 404 return True |
| 368 | 405 |
| 369 | 406 |
| 370 def text_prompt(question, default): | 407 def text_prompt(question, default): |
| 371 print question + " [" + default + "]:" | 408 print question + " [" + default + "]:" |
| 372 answer = sys.stdin.readline() | 409 answer = sys.stdin.readline() |
| 373 if answer.strip() == "": | 410 if answer.strip() == "": |
| 374 return default | 411 return default |
| 375 return answer | 412 return answer |
| 376 | 413 |
| 377 | 414 |
| 378 def drover(options, args): | 415 def drover(options, args): |
| 379 revision = options.revert or options.merge | 416 revision = options.revert or options.merge |
| 380 | 417 |
| 381 # Initialize some variables used below. They can be overwritten by | 418 # Initialize some variables used below. They can be overwritten by |
| 382 # the drover.properties file. | 419 # the drover.properties file. |
| 383 BASE_URL = "svn://svn.chromium.org/chrome" | 420 BASE_URL = "svn://svn.chromium.org/chrome" |
| 384 TRUNK_URL = BASE_URL + "/trunk/src" | 421 TRUNK_URL = BASE_URL + "/trunk/src" |
| 385 BRANCH_URL = BASE_URL + "/branches/$branch/src" | 422 BRANCH_URL = BASE_URL + "/branches/$branch/src" |
| 386 SKIP_CHECK_WORKING = True | 423 SKIP_CHECK_WORKING = True |
| 387 PROMPT_FOR_AUTHOR = False | 424 PROMPT_FOR_AUTHOR = False |
| 388 | 425 |
| 426 # Translate a given milestone to the appropriate branch number. | |
| 427 if options.milestone: | |
| 428 options.branch = getBranchForMilestone(options.milestone) | |
| 429 if options.branch is None: | |
| 430 return 1 | |
| 431 | |
| 389 DEFAULT_WORKING = "drover_" + str(revision) | 432 DEFAULT_WORKING = "drover_" + str(revision) |
| 390 if options.branch: | 433 if options.branch: |
| 391 DEFAULT_WORKING += ("_" + options.branch) | 434 DEFAULT_WORKING += ("_" + options.branch) |
| 392 | 435 |
| 393 if not isMinimumSVNVersion(1, 5): | 436 if not isMinimumSVNVersion(1, 5): |
| 394 print "You need to use at least SVN version 1.5.x" | 437 print "You need to use at least SVN version 1.5.x" |
| 395 return 1 | 438 return 1 |
| 396 | 439 |
| 397 # Override the default properties if there is a drover.properties file. | 440 # Override the default properties if there is a drover.properties file. |
| 398 global file_pattern_ | 441 global file_pattern_ |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 515 else: | 558 else: |
| 516 return 0 | 559 return 0 |
| 517 | 560 |
| 518 | 561 |
| 519 def main(): | 562 def main(): |
| 520 option_parser = optparse.OptionParser(usage=USAGE % {"app": sys.argv[0]}) | 563 option_parser = optparse.OptionParser(usage=USAGE % {"app": sys.argv[0]}) |
| 521 option_parser.add_option('-m', '--merge', type="int", | 564 option_parser.add_option('-m', '--merge', type="int", |
| 522 help='Revision to merge from trunk to branch') | 565 help='Revision to merge from trunk to branch') |
| 523 option_parser.add_option('-b', '--branch', | 566 option_parser.add_option('-b', '--branch', |
| 524 help='Branch to revert or merge from') | 567 help='Branch to revert or merge from') |
| 568 option_parser.add_option('-M', '--milestone', type="int", | |
| 569 help='Milestone to revert or merge from') | |
| 525 option_parser.add_option('-l', '--local', action='store_true', | 570 option_parser.add_option('-l', '--local', action='store_true', |
| 526 help='Local working copy to merge to') | 571 help='Local working copy to merge to') |
| 527 option_parser.add_option('-s', '--sbranch', | 572 option_parser.add_option('-s', '--sbranch', |
| 528 help='Source branch for merge') | 573 help='Source branch for merge') |
| 529 option_parser.add_option('-r', '--revert', type="int", | 574 option_parser.add_option('-r', '--revert', type="int", |
| 530 help='Revision to revert') | 575 help='Revision to revert') |
| 531 option_parser.add_option('-w', '--workdir', | 576 option_parser.add_option('-w', '--workdir', |
| 532 help='subdir to use for the revert') | 577 help='subdir to use for the revert') |
| 533 option_parser.add_option('-a', '--auditor', | 578 option_parser.add_option('-a', '--auditor', |
| 534 help='overrides the author for reviewer') | 579 help='overrides the author for reviewer') |
| 535 option_parser.add_option('', '--revertbot', action='store_true', | 580 option_parser.add_option('', '--revertbot', action='store_true', |
| 536 default=False) | 581 default=False) |
| 537 option_parser.add_option('', '--revertbot-commit', action='store_true', | 582 option_parser.add_option('', '--revertbot-commit', action='store_true', |
| 538 default=False) | 583 default=False) |
| 539 option_parser.add_option('', '--revertbot-reviewers') | 584 option_parser.add_option('', '--revertbot-reviewers') |
| 540 options, args = option_parser.parse_args() | 585 options, args = option_parser.parse_args() |
| 541 | 586 |
| 542 if not options.merge and not options.revert: | 587 if not options.merge and not options.revert: |
| 543 option_parser.error("You need at least --merge or --revert") | 588 option_parser.error("You need at least --merge or --revert") |
| 544 return 1 | 589 return 1 |
| 545 | 590 |
| 546 if options.merge and not options.branch and not options.local: | 591 if (options.merge and not options.branch and not options.milestone and |
| 592 not options.local): | |
| 547 option_parser.error("--merge requires either --branch or --local") | 593 option_parser.error("--merge requires either --branch or --local") |
| 548 return 1 | 594 return 1 |
| 549 | 595 |
| 550 if options.local and (options.revert or options.branch): | 596 if options.local and (options.revert or options.branch or options.milestone): |
| 551 option_parser.error("--local cannot be used with --revert or --branch") | 597 option_parser.error("--local cannot be used with --revert or --branch") |
| 552 return 1 | 598 return 1 |
| 553 | 599 |
| 600 if options.branch and options.milestone: | |
| 601 option_parser.error("--branch cannot be used with --milestone") | |
| 602 return 1 | |
| 603 | |
| 554 return drover(options, args) | 604 return drover(options, args) |
| 555 | 605 |
| 556 | 606 |
| 557 if __name__ == "__main__": | 607 if __name__ == "__main__": |
| 558 sys.exit(main()) | 608 sys.exit(main()) |
| OLD | NEW |