OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2006-2009 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 """Wrapper script around Rietveld's upload.py that groups files into | 6 """Wrapper script around Rietveld's upload.py that groups files into |
7 changelists.""" | 7 changelists.""" |
8 | 8 |
9 import getpass | 9 import getpass |
10 import os | 10 import os |
11 import random | 11 import random |
12 import re | 12 import re |
13 import shutil | 13 import shutil |
14 import string | 14 import string |
15 import subprocess | 15 import subprocess |
16 import sys | 16 import sys |
17 import tempfile | 17 import tempfile |
18 import time | 18 import time |
19 from third_party import upload | 19 from third_party import upload |
20 import urllib2 | 20 import urllib2 |
21 | 21 |
| 22 __pychecker__ = 'unusednames=breakpad' |
22 import breakpad | 23 import breakpad |
| 24 __pychecker__ = '' |
23 | 25 |
24 # gcl now depends on gclient. | 26 # gcl now depends on gclient. |
25 from scm import SVN | 27 from scm import SVN |
26 import gclient_utils | 28 import gclient_utils |
27 | 29 |
28 __version__ = '1.1.3' | 30 __version__ = '1.1.3' |
29 | 31 |
30 | 32 |
31 CODEREVIEW_SETTINGS = { | 33 CODEREVIEW_SETTINGS = { |
32 # Ideally, we want to set |CODE_REVIEW_SERVER| to a generic server like | 34 # Ideally, we want to set |CODE_REVIEW_SERVER| to a generic server like |
(...skipping 19 matching lines...) Expand all Loading... |
52 | 54 |
53 # Filename where we store repository specific information for gcl. | 55 # Filename where we store repository specific information for gcl. |
54 CODEREVIEW_SETTINGS_FILE = "codereview.settings" | 56 CODEREVIEW_SETTINGS_FILE = "codereview.settings" |
55 | 57 |
56 # Warning message when the change appears to be missing tests. | 58 # Warning message when the change appears to be missing tests. |
57 MISSING_TEST_MSG = "Change contains new or modified methods, but no new tests!" | 59 MISSING_TEST_MSG = "Change contains new or modified methods, but no new tests!" |
58 | 60 |
59 # Global cache of files cached in GetCacheDir(). | 61 # Global cache of files cached in GetCacheDir(). |
60 FILES_CACHE = {} | 62 FILES_CACHE = {} |
61 | 63 |
| 64 # Valid extensions for files we want to lint. |
| 65 DEFAULT_LINT_REGEX = r"(.*\.cpp|.*\.cc|.*\.h)" |
| 66 DEFAULT_LINT_IGNORE_REGEX = r"$^" |
| 67 |
| 68 |
62 def CheckHomeForFile(filename): | 69 def CheckHomeForFile(filename): |
63 """Checks the users home dir for the existence of the given file. Returns | 70 """Checks the users home dir for the existence of the given file. Returns |
64 the path to the file if it's there, or None if it is not. | 71 the path to the file if it's there, or None if it is not. |
65 """ | 72 """ |
66 home_vars = ['HOME'] | 73 home_vars = ['HOME'] |
67 if sys.platform in ('cygwin', 'win32'): | 74 if sys.platform in ('cygwin', 'win32'): |
68 home_vars.append('USERPROFILE') | 75 home_vars.append('USERPROFILE') |
69 for home_var in home_vars: | 76 for home_var in home_vars: |
70 home = os.getenv(home_var) | 77 home = os.getenv(home_var) |
71 if home != None: | 78 if home != None: |
(...skipping 509 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
581 ErrorExit("Error accessing url %s" % request_path) | 588 ErrorExit("Error accessing url %s" % request_path) |
582 else: | 589 else: |
583 return None | 590 return None |
584 | 591 |
585 | 592 |
586 def GetIssueDescription(issue): | 593 def GetIssueDescription(issue): |
587 """Returns the issue description from Rietveld.""" | 594 """Returns the issue description from Rietveld.""" |
588 return SendToRietveld("/%d/description" % issue) | 595 return SendToRietveld("/%d/description" % issue) |
589 | 596 |
590 | 597 |
591 def Opened(show_unknown_files): | 598 def ListFiles(show_unknown_files): |
592 """Prints a list of modified files in the current directory down.""" | |
593 files = GetModifiedFiles() | 599 files = GetModifiedFiles() |
594 cl_keys = files.keys() | 600 cl_keys = files.keys() |
595 cl_keys.sort() | 601 cl_keys.sort() |
596 for cl_name in cl_keys: | 602 for cl_name in cl_keys: |
597 if not cl_name: | 603 if not cl_name: |
598 continue | 604 continue |
599 note = "" | 605 note = "" |
600 change_info = ChangeInfo.Load(cl_name, GetRepositoryRoot(), | 606 change_info = ChangeInfo.Load(cl_name, GetRepositoryRoot(), |
601 fail_on_not_found=True, update_status=False) | 607 fail_on_not_found=True, update_status=False) |
602 if len(change_info.GetFiles()) != len(files[cl_name]): | 608 if len(change_info.GetFiles()) != len(files[cl_name]): |
603 note = " (Note: this changelist contains files outside this directory)" | 609 note = " (Note: this changelist contains files outside this directory)" |
604 print "\n--- Changelist " + cl_name + note + ":" | 610 print "\n--- Changelist " + cl_name + note + ":" |
605 for filename in files[cl_name]: | 611 for filename in files[cl_name]: |
606 print "".join(filename) | 612 print "".join(filename) |
607 if show_unknown_files: | 613 if show_unknown_files: |
608 unknown_files = UnknownFiles([]) | 614 unknown_files = UnknownFiles([]) |
609 if (files.get('') or (show_unknown_files and len(unknown_files))): | 615 if (files.get('') or (show_unknown_files and len(unknown_files))): |
610 print "\n--- Not in any changelist:" | 616 print "\n--- Not in any changelist:" |
611 for item in files.get('', []): | 617 for item in files.get('', []): |
612 print "".join(item) | 618 print "".join(item) |
613 if show_unknown_files: | 619 if show_unknown_files: |
614 for filename in unknown_files: | 620 for filename in unknown_files: |
615 print "? %s" % filename | 621 print "? %s" % filename |
| 622 return 0 |
616 | 623 |
617 | 624 |
618 def Help(argv=None): | 625 def CMDopened(argv): |
619 if argv: | 626 """Lists modified files in the current directory down.""" |
620 if argv[0] == 'try': | 627 __pychecker__ = 'unusednames=argv' |
| 628 return ListFiles(False) |
| 629 |
| 630 |
| 631 def CMDstatus(argv): |
| 632 """Lists modified and unknown files in the current directory down.""" |
| 633 __pychecker__ = 'unusednames=argv' |
| 634 return ListFiles(True) |
| 635 |
| 636 |
| 637 def CMDhelp(argv=None): |
| 638 """Prints this help or help for the given command.""" |
| 639 if len(argv) > 2: |
| 640 if argv[2] == 'try': |
621 TryChange(None, ['--help'], swallow_exception=False) | 641 TryChange(None, ['--help'], swallow_exception=False) |
622 return | 642 return 0 |
623 if argv[0] == 'upload': | 643 if argv[2] == 'upload': |
624 upload.RealMain(['upload.py', '--help']) | 644 upload.RealMain(['upload.py', '--help']) |
625 return | 645 return 0 |
626 | 646 |
627 print ( | 647 print ( |
628 """GCL is a wrapper for Subversion that simplifies working with groups of files. | 648 """GCL is a wrapper for Subversion that simplifies working with groups of files. |
629 version """ + __version__ + """ | 649 version """ + __version__ + """ |
630 | 650 |
631 Basic commands: | 651 Basic commands: |
632 ----------------------------------------- | 652 ----------------------------------------- |
633 gcl change change_name | 653 gcl change change_name |
634 Add/remove files to a changelist. Only scans the current directory and | 654 Add/remove files to a changelist. Only scans the current directory and |
635 subdirectories. | 655 subdirectories. |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
690 of changenames. | 710 of changenames. |
691 --> Use 'gcl help try' for more information! | 711 --> Use 'gcl help try' for more information! |
692 | 712 |
693 gcl deleteempties | 713 gcl deleteempties |
694 Deletes all changelists that have no files associated with them. Careful, | 714 Deletes all changelists that have no files associated with them. Careful, |
695 you can lose your descriptions. | 715 you can lose your descriptions. |
696 | 716 |
697 gcl help [command] | 717 gcl help [command] |
698 Print this help menu, or help for the given command if it exists. | 718 Print this help menu, or help for the given command if it exists. |
699 """) | 719 """) |
| 720 return 0 |
| 721 |
700 | 722 |
701 def GetEditor(): | 723 def GetEditor(): |
702 editor = os.environ.get("SVN_EDITOR") | 724 editor = os.environ.get("SVN_EDITOR") |
703 if not editor: | 725 if not editor: |
704 editor = os.environ.get("EDITOR") | 726 editor = os.environ.get("EDITOR") |
705 | 727 |
706 if not editor: | 728 if not editor: |
707 if sys.platform.startswith("win"): | 729 if sys.platform.startswith("win"): |
708 editor = "notepad" | 730 editor = "notepad" |
709 else: | 731 else: |
710 editor = "vi" | 732 editor = "vi" |
711 | 733 |
712 return editor | 734 return editor |
713 | 735 |
714 | 736 |
715 def GenerateDiff(files, root=None): | 737 def GenerateDiff(files, root=None): |
716 return SVN.GenerateDiff(files, root=root) | 738 return SVN.GenerateDiff(files, root=root) |
717 | 739 |
718 | 740 |
719 def OptionallyDoPresubmitChecks(change_info, committing, args): | 741 def OptionallyDoPresubmitChecks(change_info, committing, args): |
720 if FilterFlag(args, "--no_presubmit") or FilterFlag(args, "--force"): | 742 if FilterFlag(args, "--no_presubmit") or FilterFlag(args, "--force"): |
721 return True | 743 return True |
722 return DoPresubmitChecks(change_info, committing, True) | 744 return DoPresubmitChecks(change_info, committing, True) |
723 | 745 |
724 | 746 |
725 def UploadCL(change_info, args): | 747 def CMDupload(change_info, args): |
726 if not change_info.GetFiles(): | 748 if not change_info.GetFiles(): |
727 print "Nothing to upload, changelist is empty." | 749 print "Nothing to upload, changelist is empty." |
728 return | 750 return |
729 if not OptionallyDoPresubmitChecks(change_info, False, args): | 751 if not OptionallyDoPresubmitChecks(change_info, False, args): |
730 return | 752 return |
731 # Might want to support GetInfoDir()/GetRepositoryRoot() like | 753 # Might want to support GetInfoDir()/GetRepositoryRoot() like |
732 # CheckHomeForFile() so the skip of tries can be per tree basis instead | 754 # CheckHomeForFile() so the skip of tries can be per tree basis instead |
733 # of user global. | 755 # of user global. |
734 no_try = FilterFlag(args, "--no_try") or \ | 756 no_try = FilterFlag(args, "--no_try") or \ |
735 FilterFlag(args, "--no-try") or \ | 757 FilterFlag(args, "--no-try") or \ |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
831 if not no_try: | 853 if not no_try: |
832 try_on_upload = GetCodeReviewSetting('TRY_ON_UPLOAD') | 854 try_on_upload = GetCodeReviewSetting('TRY_ON_UPLOAD') |
833 if try_on_upload and try_on_upload.lower() == 'true': | 855 if try_on_upload and try_on_upload.lower() == 'true': |
834 trychange_args = [] | 856 trychange_args = [] |
835 if clobber: | 857 if clobber: |
836 trychange_args.append('--clobber') | 858 trychange_args.append('--clobber') |
837 TryChange(change_info, trychange_args, swallow_exception=True) | 859 TryChange(change_info, trychange_args, swallow_exception=True) |
838 | 860 |
839 | 861 |
840 | 862 |
841 def PresubmitCL(change_info): | 863 def CMDpresubmit(change_info, argv): |
842 """Reports what presubmit checks on the change would report.""" | 864 """Runs presubmit checks on the change.""" |
| 865 __pychecker__ = 'unusednames=argv' |
843 if not change_info.GetFiles(): | 866 if not change_info.GetFiles(): |
844 print "Nothing to presubmit check, changelist is empty." | 867 print "Nothing to presubmit check, changelist is empty." |
845 return | 868 return 0 |
846 | 869 |
847 print "*** Presubmit checks for UPLOAD would report: ***" | 870 print "*** Presubmit checks for UPLOAD would report: ***" |
848 DoPresubmitChecks(change_info, False, False) | 871 result = DoPresubmitChecks(change_info, False, False) |
849 | 872 |
850 print "\n*** Presubmit checks for COMMIT would report: ***" | 873 print "\n*** Presubmit checks for COMMIT would report: ***" |
851 DoPresubmitChecks(change_info, True, False) | 874 result &= DoPresubmitChecks(change_info, True, False) |
| 875 return not result |
852 | 876 |
853 | 877 |
854 def TryChange(change_info, args, swallow_exception): | 878 def TryChange(change_info, args, swallow_exception): |
855 """Create a diff file of change_info and send it to the try server.""" | 879 """Create a diff file of change_info and send it to the try server.""" |
856 try: | 880 try: |
857 import trychange | 881 import trychange |
858 except ImportError: | 882 except ImportError: |
859 if swallow_exception: | 883 if swallow_exception: |
860 return | 884 return |
861 ErrorExit("You need to install trychange.py to use the try server.") | 885 ErrorExit("You need to install trychange.py to use the try server.") |
862 | 886 |
863 trychange_args = [] | 887 trychange_args = [] |
864 if change_info: | 888 if change_info: |
865 trychange_args.extend(['--name', change_info.name]) | 889 trychange_args.extend(['--name', change_info.name]) |
866 if change_info.issue: | 890 if change_info.issue: |
867 trychange_args.extend(["--issue", str(change_info.issue)]) | 891 trychange_args.extend(["--issue", str(change_info.issue)]) |
868 if change_info.patchset: | 892 if change_info.patchset: |
869 trychange_args.extend(["--patchset", str(change_info.patchset)]) | 893 trychange_args.extend(["--patchset", str(change_info.patchset)]) |
870 trychange_args.extend(args) | 894 trychange_args.extend(args) |
871 file_list = change_info.GetFileNames() | 895 file_list = change_info.GetFileNames() |
872 else: | 896 else: |
873 trychange_args.extend(args) | 897 trychange_args.extend(args) |
874 file_list = None | 898 file_list = None |
875 trychange.TryChange(trychange_args, | 899 trychange.TryChange(trychange_args, |
876 file_list=file_list, | 900 file_list=file_list, |
877 swallow_exception=swallow_exception, | 901 swallow_exception=swallow_exception, |
878 prog='gcl try') | 902 prog='gcl try') |
879 | 903 |
880 | 904 |
881 def Commit(change_info, args): | 905 def CMDcommit(change_info, args): |
882 if not change_info.GetFiles(): | 906 if not change_info.GetFiles(): |
883 print "Nothing to commit, changelist is empty." | 907 print "Nothing to commit, changelist is empty." |
884 return | 908 return 1 |
885 if not OptionallyDoPresubmitChecks(change_info, True, args): | 909 if not OptionallyDoPresubmitChecks(change_info, True, args): |
886 return | 910 return 1 |
887 | 911 |
888 # We face a problem with svn here: Let's say change 'bleh' modifies | 912 # We face a problem with svn here: Let's say change 'bleh' modifies |
889 # svn:ignore on dir1\. but another unrelated change 'pouet' modifies | 913 # svn:ignore on dir1\. but another unrelated change 'pouet' modifies |
890 # dir1\foo.cc. When the user `gcl commit bleh`, foo.cc is *also committed*. | 914 # dir1\foo.cc. When the user `gcl commit bleh`, foo.cc is *also committed*. |
891 # The only fix is to use --non-recursive but that has its issues too: | 915 # The only fix is to use --non-recursive but that has its issues too: |
892 # Let's say if dir1 is deleted, --non-recursive must *not* be used otherwise | 916 # Let's say if dir1 is deleted, --non-recursive must *not* be used otherwise |
893 # you'll get "svn: Cannot non-recursively commit a directory deletion of a | 917 # you'll get "svn: Cannot non-recursively commit a directory deletion of a |
894 # directory with child nodes". Yay... | 918 # directory with child nodes". Yay... |
895 commit_cmd = ["svn", "commit"] | 919 commit_cmd = ["svn", "commit"] |
896 if change_info.issue: | 920 if change_info.issue: |
(...skipping 28 matching lines...) Expand all Loading... |
925 | 949 |
926 if change_info.issue: | 950 if change_info.issue: |
927 revision = re.compile(".*?\nCommitted revision (\d+)", | 951 revision = re.compile(".*?\nCommitted revision (\d+)", |
928 re.DOTALL).match(output).group(1) | 952 re.DOTALL).match(output).group(1) |
929 viewvc_url = GetCodeReviewSetting("VIEW_VC") | 953 viewvc_url = GetCodeReviewSetting("VIEW_VC") |
930 change_info.description = change_info.description + '\n' | 954 change_info.description = change_info.description + '\n' |
931 if viewvc_url: | 955 if viewvc_url: |
932 change_info.description += "\nCommitted: " + viewvc_url + revision | 956 change_info.description += "\nCommitted: " + viewvc_url + revision |
933 change_info.CloseIssue() | 957 change_info.CloseIssue() |
934 os.chdir(previous_cwd) | 958 os.chdir(previous_cwd) |
| 959 return 0 |
935 | 960 |
936 | 961 |
937 def Change(change_info, args): | 962 def CMDchange(change_info, args): |
938 """Creates/edits a changelist.""" | 963 """Creates/edits a changelist.""" |
939 silent = FilterFlag(args, "--silent") | 964 silent = FilterFlag(args, "--silent") |
940 | 965 |
941 # Verify the user is running the change command from a read-write checkout. | 966 # Verify the user is running the change command from a read-write checkout. |
942 svn_info = SVN.CaptureInfo('.') | 967 svn_info = SVN.CaptureInfo('.') |
943 if not svn_info: | 968 if not svn_info: |
944 ErrorExit("Current checkout is unversioned. Please retry with a versioned " | 969 ErrorExit("Current checkout is unversioned. Please retry with a versioned " |
945 "directory.") | 970 "directory.") |
946 | 971 |
947 if (len(args) == 1): | 972 if (len(args) == 1): |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
996 os.write(handle, text) | 1021 os.write(handle, text) |
997 os.close(handle) | 1022 os.close(handle) |
998 | 1023 |
999 if not silent: | 1024 if not silent: |
1000 os.system(GetEditor() + " " + filename) | 1025 os.system(GetEditor() + " " + filename) |
1001 | 1026 |
1002 result = gclient_utils.FileRead(filename, 'r') | 1027 result = gclient_utils.FileRead(filename, 'r') |
1003 os.remove(filename) | 1028 os.remove(filename) |
1004 | 1029 |
1005 if not result: | 1030 if not result: |
1006 return | 1031 return 0 |
1007 | 1032 |
1008 split_result = result.split(separator1, 1) | 1033 split_result = result.split(separator1, 1) |
1009 if len(split_result) != 2: | 1034 if len(split_result) != 2: |
1010 ErrorExit("Don't modify the text starting with ---!\n\n" + result) | 1035 ErrorExit("Don't modify the text starting with ---!\n\n" + result) |
1011 | 1036 |
1012 # Update the CL description if it has changed. | 1037 # Update the CL description if it has changed. |
1013 new_description = split_result[0] | 1038 new_description = split_result[0] |
1014 cl_files_text = split_result[1] | 1039 cl_files_text = split_result[1] |
1015 if new_description != description or override_description: | 1040 if new_description != description or override_description: |
1016 change_info.description = new_description | 1041 change_info.description = new_description |
(...skipping 21 matching lines...) Expand all Loading... |
1038 | 1063 |
1039 print change_info.name + " changelist saved." | 1064 print change_info.name + " changelist saved." |
1040 if change_info.MissingTests(): | 1065 if change_info.MissingTests(): |
1041 Warn("WARNING: " + MISSING_TEST_MSG) | 1066 Warn("WARNING: " + MISSING_TEST_MSG) |
1042 | 1067 |
1043 # Update the Rietveld issue. | 1068 # Update the Rietveld issue. |
1044 if change_info.issue and change_info.NeedsUpload(): | 1069 if change_info.issue and change_info.NeedsUpload(): |
1045 change_info.UpdateRietveldDescription() | 1070 change_info.UpdateRietveldDescription() |
1046 change_info.needs_upload = False | 1071 change_info.needs_upload = False |
1047 change_info.Save() | 1072 change_info.Save() |
| 1073 return 0 |
1048 | 1074 |
1049 | 1075 |
1050 # Valid extensions for files we want to lint. | 1076 def CMDlint(change_info, args): |
1051 DEFAULT_LINT_REGEX = r"(.*\.cpp|.*\.cc|.*\.h)" | |
1052 DEFAULT_LINT_IGNORE_REGEX = r"$^" | |
1053 | |
1054 def Lint(change_info, args): | |
1055 """Runs cpplint.py on all the files in |change_info|""" | 1077 """Runs cpplint.py on all the files in |change_info|""" |
1056 try: | 1078 try: |
1057 import cpplint | 1079 import cpplint |
1058 except ImportError: | 1080 except ImportError: |
1059 ErrorExit("You need to install cpplint.py to lint C++ files.") | 1081 ErrorExit("You need to install cpplint.py to lint C++ files.") |
1060 | 1082 |
1061 # Change the current working directory before calling lint so that it | 1083 # Change the current working directory before calling lint so that it |
1062 # shows the correct base. | 1084 # shows the correct base. |
1063 previous_cwd = os.getcwd() | 1085 previous_cwd = os.getcwd() |
1064 os.chdir(change_info.GetLocalRoot()) | 1086 os.chdir(change_info.GetLocalRoot()) |
(...skipping 13 matching lines...) Expand all Loading... |
1078 if white_regex.match(filename): | 1100 if white_regex.match(filename): |
1079 if black_regex.match(filename): | 1101 if black_regex.match(filename): |
1080 print "Ignoring file %s" % filename | 1102 print "Ignoring file %s" % filename |
1081 else: | 1103 else: |
1082 cpplint.ProcessFile(filename, cpplint._cpplint_state.verbose_level) | 1104 cpplint.ProcessFile(filename, cpplint._cpplint_state.verbose_level) |
1083 else: | 1105 else: |
1084 print "Skipping file %s" % filename | 1106 print "Skipping file %s" % filename |
1085 | 1107 |
1086 print "Total errors found: %d\n" % cpplint._cpplint_state.error_count | 1108 print "Total errors found: %d\n" % cpplint._cpplint_state.error_count |
1087 os.chdir(previous_cwd) | 1109 os.chdir(previous_cwd) |
| 1110 return 1 |
1088 | 1111 |
1089 | 1112 |
1090 def DoPresubmitChecks(change_info, committing, may_prompt): | 1113 def DoPresubmitChecks(change_info, committing, may_prompt): |
1091 """Imports presubmit, then calls presubmit.DoPresubmitChecks.""" | 1114 """Imports presubmit, then calls presubmit.DoPresubmitChecks.""" |
1092 # Need to import here to avoid circular dependency. | 1115 # Need to import here to avoid circular dependency. |
1093 import presubmit_support | 1116 import presubmit_support |
1094 root_presubmit = GetCachedFile('PRESUBMIT.py', use_root=True) | 1117 root_presubmit = GetCachedFile('PRESUBMIT.py', use_root=True) |
1095 change = presubmit_support.SvnChange(change_info.name, | 1118 change = presubmit_support.SvnChange(change_info.name, |
1096 change_info.description, | 1119 change_info.description, |
1097 change_info.GetLocalRoot(), | 1120 change_info.GetLocalRoot(), |
1098 change_info.GetFiles(), | 1121 change_info.GetFiles(), |
1099 change_info.issue, | 1122 change_info.issue, |
1100 change_info.patchset) | 1123 change_info.patchset) |
1101 result = presubmit_support.DoPresubmitChecks(change=change, | 1124 result = presubmit_support.DoPresubmitChecks(change=change, |
1102 committing=committing, | 1125 committing=committing, |
1103 verbose=False, | 1126 verbose=False, |
1104 output_stream=sys.stdout, | 1127 output_stream=sys.stdout, |
1105 input_stream=sys.stdin, | 1128 input_stream=sys.stdin, |
1106 default_presubmit=root_presubmit, | 1129 default_presubmit=root_presubmit, |
1107 may_prompt=may_prompt) | 1130 may_prompt=may_prompt) |
1108 if not result and may_prompt: | 1131 if not result and may_prompt: |
1109 print "\nPresubmit errors, can't continue (use --no_presubmit to bypass)" | 1132 print "\nPresubmit errors, can't continue (use --no_presubmit to bypass)" |
1110 return result | 1133 return result |
1111 | 1134 |
1112 | 1135 |
1113 def Changes(): | 1136 def CMDchanges(argv): |
1114 """Print all the changelists and their files.""" | 1137 """Lists all the changelists and their files.""" |
| 1138 __pychecker__ = 'unusednames=argv' |
1115 for cl in GetCLs(): | 1139 for cl in GetCLs(): |
1116 change_info = ChangeInfo.Load(cl, GetRepositoryRoot(), True, True) | 1140 change_info = ChangeInfo.Load(cl, GetRepositoryRoot(), True, True) |
1117 print "\n--- Changelist " + change_info.name + ":" | 1141 print "\n--- Changelist " + change_info.name + ":" |
1118 for filename in change_info.GetFiles(): | 1142 for filename in change_info.GetFiles(): |
1119 print "".join(filename) | 1143 print "".join(filename) |
| 1144 return 0 |
1120 | 1145 |
1121 | 1146 |
1122 def DeleteEmptyChangeLists(): | 1147 def CMDdeleteempties(argv): |
1123 """Delete all changelists that have no files.""" | 1148 """Delete all changelists that have no files.""" |
| 1149 __pychecker__ = 'unusednames=argv' |
1124 print "\n--- Deleting:" | 1150 print "\n--- Deleting:" |
1125 for cl in GetCLs(): | 1151 for cl in GetCLs(): |
1126 change_info = ChangeInfo.Load(cl, GetRepositoryRoot(), True, True) | 1152 change_info = ChangeInfo.Load(cl, GetRepositoryRoot(), True, True) |
1127 if not len(change_info._files): | 1153 if not len(change_info._files): |
1128 print change_info.name | 1154 print change_info.name |
1129 change_info.Delete() | 1155 change_info.Delete() |
| 1156 return 0 |
| 1157 |
| 1158 |
| 1159 def CMDnothave(argv): |
| 1160 """Lists files unknown to Subversion.""" |
| 1161 __pychecker__ = 'unusednames=argv' |
| 1162 for filename in UnknownFiles(argv[2:]): |
| 1163 print "? " + "".join(filename) |
| 1164 return 0 |
| 1165 |
| 1166 |
| 1167 def CMDdiff(argv): |
| 1168 """Diffs all files in the changelist.""" |
| 1169 __pychecker__ = 'unusednames=argv' |
| 1170 files = GetFilesNotInCL() |
| 1171 print GenerateDiff([x[1] for x in files]) |
| 1172 return 0 |
| 1173 |
| 1174 |
| 1175 def CMDsettings(argv): |
| 1176 """Prints code review settings.""" |
| 1177 __pychecker__ = 'unusednames=argv' |
| 1178 # Force load settings |
| 1179 GetCodeReviewSetting("UNKNOWN"); |
| 1180 del CODEREVIEW_SETTINGS['__just_initialized'] |
| 1181 print '\n'.join(("%s: %s" % (str(k), str(v)) |
| 1182 for (k,v) in CODEREVIEW_SETTINGS.iteritems())) |
| 1183 return 0 |
| 1184 |
| 1185 |
| 1186 def CMDdescription(change_info, argv): |
| 1187 """Prints the description of the specified change to stdout.""" |
| 1188 __pychecker__ = 'unusednames=argv' |
| 1189 print change_info.description |
| 1190 return 0 |
| 1191 |
| 1192 |
| 1193 def CMDdelete(change_info, argv): |
| 1194 """Deletes a changelist.""" |
| 1195 __pychecker__ = 'unusednames=argv' |
| 1196 change_info.Delete() |
| 1197 return 0 |
| 1198 |
| 1199 |
| 1200 def CMDtry(change_info, argv): |
| 1201 """Sends the change to the tryserver so a trybot can do a test run on your |
| 1202 code. |
| 1203 |
| 1204 To send multiple changes as one path, use a comma-separated list of |
| 1205 changenames. Use 'gcl help try' for more information!""" |
| 1206 # When the change contains no file, send the "changename" positional |
| 1207 # argument to trychange.py. |
| 1208 __pychecker__ = 'unusednames=argv' |
| 1209 if change_info.GetFiles(): |
| 1210 args = argv[3:] |
| 1211 else: |
| 1212 change_info = None |
| 1213 args = argv[2:] |
| 1214 TryChange(change_info, args, swallow_exception=False) |
| 1215 return 0 |
| 1216 |
| 1217 |
| 1218 def CMDrename(argv): |
| 1219 """Renames an existing change.""" |
| 1220 if len(argv) != 4: |
| 1221 ErrorExit("Usage: gcl rename <old-name> <new-name>.") |
| 1222 src, dst = argv[2:4] |
| 1223 src_file = GetChangelistInfoFile(src) |
| 1224 if not os.path.isfile(src_file): |
| 1225 ErrorExit("Change '%s' does not exist." % src) |
| 1226 dst_file = GetChangelistInfoFile(dst) |
| 1227 if os.path.isfile(dst_file): |
| 1228 ErrorExit("Change '%s' already exists; pick a new name." % dst) |
| 1229 os.rename(src_file, dst_file) |
| 1230 print "Change '%s' renamed '%s'." % (src, dst) |
| 1231 return 0 |
1130 | 1232 |
1131 | 1233 |
1132 def main(argv=None): | 1234 def main(argv=None): |
| 1235 __pychecker__ = 'maxreturns=0' |
1133 if argv is None: | 1236 if argv is None: |
1134 argv = sys.argv | 1237 argv = sys.argv |
1135 | 1238 |
1136 if len(argv) == 1: | 1239 if len(argv) == 1: |
1137 Help() | 1240 return CMDhelp() |
1138 return 0; | |
1139 | 1241 |
1140 try: | 1242 try: |
1141 # Create the directories where we store information about changelists if it | 1243 # Create the directories where we store information about changelists if it |
1142 # doesn't exist. | 1244 # doesn't exist. |
1143 if not os.path.exists(GetInfoDir()): | 1245 if not os.path.exists(GetInfoDir()): |
1144 os.mkdir(GetInfoDir()) | 1246 os.mkdir(GetInfoDir()) |
1145 if not os.path.exists(GetChangesDir()): | 1247 if not os.path.exists(GetChangesDir()): |
1146 os.mkdir(GetChangesDir()) | 1248 os.mkdir(GetChangesDir()) |
1147 if not os.path.exists(GetCacheDir()): | 1249 if not os.path.exists(GetCacheDir()): |
1148 os.mkdir(GetCacheDir()) | 1250 os.mkdir(GetCacheDir()) |
1149 except gclient_utils.Error: | 1251 except gclient_utils.Error: |
1150 # Will throw an exception if not run in a svn checkout. | 1252 # Will throw an exception if not run in a svn checkout. |
1151 pass | 1253 pass |
1152 | 1254 |
1153 # Commands that don't require an argument. | 1255 # Commands that don't require an argument. |
1154 command = argv[1] | 1256 command = argv[1] |
1155 if command == "opened" or command == "status": | 1257 if command == "opened": |
1156 Opened(command == "status") | 1258 return CMDopened(argv) |
1157 return 0 | 1259 if command == "status": |
| 1260 return CMDstatus(argv) |
1158 if command == "nothave": | 1261 if command == "nothave": |
1159 __pychecker__ = 'no-returnvalues' | 1262 return CMDnothave(argv) |
1160 for filename in UnknownFiles(argv[2:]): | |
1161 print "? " + "".join(filename) | |
1162 return 0 | |
1163 if command == "changes": | 1263 if command == "changes": |
1164 Changes() | 1264 return CMDchanges(argv) |
1165 return 0 | |
1166 if command == "help": | 1265 if command == "help": |
1167 Help(argv[2:]) | 1266 return CMDhelp(argv) |
1168 return 0 | |
1169 if command == "diff" and len(argv) == 2: | 1267 if command == "diff" and len(argv) == 2: |
1170 files = GetFilesNotInCL() | 1268 return CMDdiff(argv) |
1171 print GenerateDiff([x[1] for x in files]) | |
1172 return 0 | |
1173 if command == "settings": | 1269 if command == "settings": |
1174 # Force load settings | 1270 return CMDsettings(argv) |
1175 GetCodeReviewSetting("UNKNOWN"); | |
1176 del CODEREVIEW_SETTINGS['__just_initialized'] | |
1177 print '\n'.join(("%s: %s" % (str(k), str(v)) | |
1178 for (k,v) in CODEREVIEW_SETTINGS.iteritems())) | |
1179 return 0 | |
1180 if command == "deleteempties": | 1271 if command == "deleteempties": |
1181 DeleteEmptyChangeLists() | 1272 return CMDdeleteempties(argv) |
1182 return 0 | |
1183 | |
1184 if command == "rename": | 1273 if command == "rename": |
1185 if len(argv) != 4: | 1274 return CMDrename(argv) |
1186 ErrorExit("Usage: gcl rename <old-name> <new-name>.") | |
1187 src, dst = argv[2:4] | |
1188 src_file = GetChangelistInfoFile(src) | |
1189 if not os.path.isfile(src_file): | |
1190 ErrorExit("Change '%s' does not exist." % src) | |
1191 dst_file = GetChangelistInfoFile(dst) | |
1192 if os.path.isfile(dst_file): | |
1193 ErrorExit("Change '%s' already exists; pick a new name." % dst) | |
1194 os.rename(src_file, dst_file) | |
1195 print "Change '%s' renamed '%s'." % (src, dst) | |
1196 return 0 | |
1197 if command == "change": | 1275 if command == "change": |
1198 if len(argv) == 2: | 1276 if len(argv) == 2: |
1199 # Generate a random changelist name. | 1277 # Generate a random changelist name. |
1200 changename = GenerateChangeName() | 1278 changename = GenerateChangeName() |
1201 elif argv[2] == '--force': | 1279 elif argv[2] == '--force': |
1202 changename = GenerateChangeName() | 1280 changename = GenerateChangeName() |
1203 # argv[3:] is passed to Change() as |args| later. Change() should receive | 1281 # argv[3:] is passed to Change() as |args| later. Change() should receive |
1204 # |args| which includes '--force'. | 1282 # |args| which includes '--force'. |
1205 argv.insert(2, changename) | 1283 argv.insert(2, changename) |
1206 else: | 1284 else: |
1207 changename = argv[2] | 1285 changename = argv[2] |
1208 elif len(argv) == 2: | 1286 elif len(argv) == 2: |
1209 ErrorExit("Need a changelist name.") | 1287 ErrorExit("Need a changelist name.") |
1210 else: | 1288 else: |
1211 changename = argv[2] | 1289 changename = argv[2] |
1212 | 1290 |
1213 # When the command is 'try' and --patchset is used, the patch to try | 1291 # When the command is 'try' and --patchset is used, the patch to try |
1214 # is on the Rietveld server. 'change' creates a change so it's fine if the | 1292 # is on the Rietveld server. 'change' creates a change so it's fine if the |
1215 # change didn't exist. All other commands require an existing change. | 1293 # change didn't exist. All other commands require an existing change. |
1216 fail_on_not_found = command != "try" and command != "change" | 1294 fail_on_not_found = command != "try" and command != "change" |
1217 if command == "try" and changename.find(',') != -1: | 1295 if command == "try" and changename.find(',') != -1: |
1218 change_info = LoadChangelistInfoForMultiple(changename, GetRepositoryRoot(), | 1296 change_info = LoadChangelistInfoForMultiple(changename, GetRepositoryRoot(), |
1219 True, True) | 1297 True, True) |
1220 else: | 1298 else: |
1221 change_info = ChangeInfo.Load(changename, GetRepositoryRoot(), | 1299 change_info = ChangeInfo.Load(changename, GetRepositoryRoot(), |
1222 fail_on_not_found, True) | 1300 fail_on_not_found, True) |
1223 | 1301 |
1224 if command == "change": | 1302 if command == "change": |
1225 Change(change_info, argv[3:]) | 1303 return CMDchange(change_info, argv[3:]) |
1226 elif command == "description": | 1304 elif command == "description": |
1227 print change_info.description | 1305 return CMDdescription(change_info, argv[3:]) |
1228 elif command == "lint": | 1306 elif command == "lint": |
1229 Lint(change_info, argv[3:]) | 1307 return CMDlint(change_info, argv[3:]) |
1230 elif command == "upload": | 1308 elif command == "upload": |
1231 UploadCL(change_info, argv[3:]) | 1309 return CMDupload(change_info, argv[3:]) |
1232 elif command == "presubmit": | 1310 elif command == "presubmit": |
1233 PresubmitCL(change_info) | 1311 return CMDpresubmit(change_info, argv[3:]) |
1234 elif command in ("commit", "submit"): | 1312 elif command in ("commit", "submit"): |
1235 Commit(change_info, argv[3:]) | 1313 return CMDcommit(change_info, argv[3:]) |
1236 elif command == "delete": | 1314 elif command == "delete": |
1237 change_info.Delete() | 1315 return CMDdelete(change_info, argv[3:]) |
1238 elif command == "try": | 1316 elif command == "try": |
1239 # When the change contains no file, send the "changename" positional | 1317 return CMDtry(change_info, argv) |
1240 # argument to trychange.py. | |
1241 if change_info.GetFiles(): | |
1242 args = argv[3:] | |
1243 else: | |
1244 change_info = None | |
1245 args = argv[2:] | |
1246 TryChange(change_info, args, swallow_exception=False) | |
1247 else: | 1318 else: |
1248 # Everything else that is passed into gcl we redirect to svn, after adding | 1319 # Everything else that is passed into gcl we redirect to svn, after adding |
1249 # the files. This allows commands such as 'gcl diff xxx' to work. | 1320 # the files. This allows commands such as 'gcl diff xxx' to work. |
1250 if command == "diff" and not change_info.GetFileNames(): | 1321 if command == "diff" and not change_info.GetFileNames(): |
1251 return 0 | 1322 return 0 |
1252 args =["svn", command] | 1323 args =["svn", command] |
1253 root = GetRepositoryRoot() | 1324 root = GetRepositoryRoot() |
1254 args.extend([os.path.join(root, x) for x in change_info.GetFileNames()]) | 1325 args.extend([os.path.join(root, x) for x in change_info.GetFileNames()]) |
1255 RunShell(args, True) | 1326 RunShell(args, True) |
1256 return 0 | 1327 return 0 |
1257 | 1328 |
1258 | 1329 |
1259 if __name__ == "__main__": | 1330 if __name__ == "__main__": |
1260 sys.exit(main()) | 1331 sys.exit(main()) |
OLD | NEW |