OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 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 string |
10 import sys | 10 import sys |
11 import urllib2 | 11 import urllib2 |
| 12 import urlparse |
12 | 13 |
13 import breakpad # pylint: disable=W0611 | 14 import breakpad # pylint: disable=W0611 |
14 | 15 |
15 import gclient_utils | 16 import gclient_utils |
16 import subprocess2 | 17 import subprocess2 |
17 | 18 |
18 USAGE = """ | 19 USAGE = """ |
19 WARNING: Please use this tool in an empty directory | 20 WARNING: Please use this tool in an empty directory |
20 (or at least one that you don't mind clobbering.) | 21 (or at least one that you don't mind clobbering.) |
21 | 22 |
(...skipping 392 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
414 # Not all of the platforms have the same branch. Prompt the user and return | 415 # Not all of the platforms have the same branch. Prompt the user and return |
415 # the greatest (by value) branch on success. | 416 # the greatest (by value) branch on success. |
416 if prompt("Not all platforms have the same branch number, " | 417 if prompt("Not all platforms have the same branch number, " |
417 "continue with branch %s?" % branch): | 418 "continue with branch %s?" % branch): |
418 return branch | 419 return branch |
419 | 420 |
420 # User cancelled. | 421 # User cancelled. |
421 return None | 422 return None |
422 | 423 |
423 | 424 |
| 425 def getSVNAuthInfo(folder=None): |
| 426 """Fetches SVN authorization information in the subversion auth folder and |
| 427 returns it as a dictionary of dictionaries.""" |
| 428 if not folder: |
| 429 if sys.platform == 'win32': |
| 430 folder = '%%APPDATA%\\Subversion\\auth' |
| 431 else: |
| 432 folder = '~/.subversion/auth' |
| 433 folder = os.path.expandvars(os.path.expanduser(folder)) |
| 434 svn_simple_folder = os.path.join(folder, 'svn.simple') |
| 435 results = {} |
| 436 try: |
| 437 for auth_file in os.listdir(svn_simple_folder): |
| 438 # Read the SVN auth file, convert it into a dictionary, and store it. |
| 439 results[auth_file] = dict(re.findall(r'K [0-9]+\n(.*)\nV [0-9]+\n(.*)\n', |
| 440 open(os.path.join(svn_simple_folder, auth_file)).read())) |
| 441 except Exception as _: |
| 442 pass |
| 443 return results |
| 444 |
| 445 |
| 446 def getCurrentSVNUsers(url): |
| 447 """Tries to fetch the current SVN in the current checkout by scanning the |
| 448 SVN authorization folder for a match with the current SVN URL.""" |
| 449 netloc = urlparse.urlparse(url)[1] |
| 450 auth_infos = getSVNAuthInfo() |
| 451 results = [] |
| 452 for _, auth_info in auth_infos.iteritems(): |
| 453 if ('svn:realmstring' in auth_info |
| 454 and netloc in auth_info['svn:realmstring']): |
| 455 username = auth_info['username'] |
| 456 results.append(username) |
| 457 if 'google.com' in username: |
| 458 results.append(username.replace('google.com', 'chromium.org')) |
| 459 return results |
| 460 |
| 461 |
424 def prompt(question): | 462 def prompt(question): |
425 while True: | 463 while True: |
426 print question + " [y|n]:", | 464 print question + " [y|n]:", |
427 answer = sys.stdin.readline() | 465 answer = sys.stdin.readline() |
428 if answer.lower().startswith('n'): | 466 if answer.lower().startswith('n'): |
429 return False | 467 return False |
430 elif answer.lower().startswith('y'): | 468 elif answer.lower().startswith('y'): |
431 return True | 469 return True |
432 | 470 |
433 | 471 |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
530 revertExportRevision(url, revision) | 568 revertExportRevision(url, revision) |
531 | 569 |
532 # Check the base url so we actually find the author who made the change | 570 # Check the base url so we actually find the author who made the change |
533 if options.auditor: | 571 if options.auditor: |
534 author = options.auditor | 572 author = options.auditor |
535 else: | 573 else: |
536 author = getAuthor(url, revision) | 574 author = getAuthor(url, revision) |
537 if not author: | 575 if not author: |
538 author = getAuthor(TRUNK_URL, revision) | 576 author = getAuthor(TRUNK_URL, revision) |
539 | 577 |
| 578 # Check that the author of the CL is different than the user making |
| 579 # the revert. If they're the same, then we'll want to prompt the user |
| 580 # for a different reviewer to TBR. |
| 581 current_users = getCurrentSVNUsers(BASE_URL) |
| 582 is_self_revert = options.revert and author in current_users |
| 583 |
540 filename = str(revision)+".txt" | 584 filename = str(revision)+".txt" |
541 out = open(filename,"w") | 585 out = open(filename,"w") |
542 out.write(action +" " + str(revision) + " - ") | 586 out.write(action +" " + str(revision) + "\n") |
543 out.write(getRevisionLog(url, revision)) | 587 for line in getRevisionLog(url, revision).splitlines(): |
| 588 out.write('> %s\n' % line) |
544 if (author): | 589 if (author): |
545 out.write("\nTBR=" + author) | 590 out.write("\nTBR=" + author) |
546 out.close() | 591 out.close() |
547 | 592 |
548 change_cmd = 'change ' + str(revision) + " " + filename | 593 change_cmd = 'change ' + str(revision) + " " + filename |
549 if options.revertbot: | 594 if options.revertbot: |
550 if sys.platform == 'win32': | 595 if sys.platform == 'win32': |
551 os.environ['SVN_EDITOR'] = 'cmd.exe /c exit' | 596 os.environ['SVN_EDITOR'] = 'cmd.exe /c exit' |
552 else: | 597 else: |
553 os.environ['SVN_EDITOR'] = 'true' | 598 os.environ['SVN_EDITOR'] = 'true' |
554 runGcl(change_cmd) | 599 runGcl(change_cmd) |
555 os.unlink(filename) | 600 os.unlink(filename) |
556 | 601 |
557 if options.local: | 602 if options.local: |
558 return 0 | 603 return 0 |
559 | 604 |
560 print author | 605 print author |
561 print revision | 606 print revision |
562 print ("gcl upload " + str(revision) + | 607 print ("gcl upload " + str(revision) + |
563 " --send_mail --no_presubmit --reviewers=" + author) | 608 " --send_mail --no_presubmit --reviewers=" + author) |
564 | 609 |
565 if options.revertbot or prompt("Would you like to upload?"): | 610 if options.revertbot or prompt("Would you like to upload?"): |
566 if PROMPT_FOR_AUTHOR: | 611 if PROMPT_FOR_AUTHOR or is_self_revert: |
567 author = text_prompt("Enter new author or press enter to accept default", | 612 author = text_prompt("Enter new author or press enter to accept default", |
568 author) | 613 author) |
569 if options.revertbot and options.revertbot_reviewers: | 614 if options.revertbot and options.revertbot_reviewers: |
570 author += "," | 615 author += "," |
571 author += options.revertbot_reviewers | 616 author += options.revertbot_reviewers |
572 gclUpload(revision, author) | 617 gclUpload(revision, author) |
573 else: | 618 else: |
574 print "Deleting the changelist." | 619 print "Deleting the changelist." |
575 print "gcl delete " + str(revision) | 620 print "gcl delete " + str(revision) |
576 runGcl("delete " + str(revision)) | 621 runGcl("delete " + str(revision)) |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
628 | 673 |
629 if options.branch and options.milestone: | 674 if options.branch and options.milestone: |
630 option_parser.error("--branch cannot be used with --milestone") | 675 option_parser.error("--branch cannot be used with --milestone") |
631 return 1 | 676 return 1 |
632 | 677 |
633 return drover(options, args) | 678 return drover(options, args) |
634 | 679 |
635 | 680 |
636 if __name__ == "__main__": | 681 if __name__ == "__main__": |
637 sys.exit(main()) | 682 sys.exit(main()) |
OLD | NEW |