Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(217)

Side by Side Diff: gcl.py

Issue 2301003: Massive overhaul for gcl help (Closed)
Patch Set: Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | tests/gcl_unittest.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 """\
7 changelists.""" 7 Wrapper script around Rietveld's upload.py that simplifies working with groups
8 of files.
9 """
8 10
9 import getpass 11 import getpass
10 import os 12 import os
11 import random 13 import random
12 import re 14 import re
13 import shutil 15 import shutil
14 import string 16 import string
15 import subprocess 17 import subprocess
16 import sys 18 import sys
17 import tempfile 19 import tempfile
18 import time 20 import time
19 from third_party import upload 21 from third_party import upload
20 import urllib2 22 import urllib2
21 23
22 __pychecker__ = 'unusednames=breakpad' 24 __pychecker__ = 'unusednames=breakpad'
23 import breakpad 25 import breakpad
24 __pychecker__ = '' 26 __pychecker__ = ''
25 27
26 # gcl now depends on gclient. 28 # gcl now depends on gclient.
27 from scm import SVN 29 from scm import SVN
28 import gclient_utils 30 import gclient_utils
29 31
30 __version__ = '1.1.4' 32 __version__ = '1.2'
31 33
32 34
33 CODEREVIEW_SETTINGS = { 35 CODEREVIEW_SETTINGS = {
34 # Ideally, we want to set |CODE_REVIEW_SERVER| to a generic server like 36 # Ideally, we want to set |CODE_REVIEW_SERVER| to a generic server like
35 # codereview.appspot.com and remove |CC_LIST| and |VIEW_VC|. In practice, we 37 # codereview.appspot.com and remove |CC_LIST| and |VIEW_VC|. In practice, we
36 # need these settings so developers making changes in directories such as 38 # need these settings so developers making changes in directories such as
37 # Chromium's src/third_party/WebKit will send change lists to the correct 39 # Chromium's src/third_party/WebKit will send change lists to the correct
38 # server. 40 # server.
39 # 41 #
40 # To make gcl send reviews to a different server, check in a file named 42 # To make gcl send reviews to a different server, check in a file named
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
75 home_vars.append('USERPROFILE') 77 home_vars.append('USERPROFILE')
76 for home_var in home_vars: 78 for home_var in home_vars:
77 home = os.getenv(home_var) 79 home = os.getenv(home_var)
78 if home != None: 80 if home != None:
79 full_path = os.path.join(home, filename) 81 full_path = os.path.join(home, filename)
80 if os.path.exists(full_path): 82 if os.path.exists(full_path):
81 return full_path 83 return full_path
82 return None 84 return None
83 85
84 86
85 def UnknownFiles(extra_args): 87 def UnknownFiles():
86 """Runs svn status and returns unknown files. 88 """Runs svn status and returns unknown files."""
87 89 return [item[1] for item in SVN.CaptureStatus([]) if item[0][0] == '?']
88 Any args in |extra_args| are passed to the tool to support giving alternate
89 code locations.
90 """
91 return [item[1] for item in SVN.CaptureStatus(extra_args)
92 if item[0][0] == '?']
93 90
94 91
95 def GetRepositoryRoot(): 92 def GetRepositoryRoot():
96 """Returns the top level directory of the current repository. 93 """Returns the top level directory of the current repository.
97 94
98 The directory is returned as an absolute path. 95 The directory is returned as an absolute path.
99 """ 96 """
100 global REPOSITORY_ROOT 97 global REPOSITORY_ROOT
101 if not REPOSITORY_ROOT: 98 if not REPOSITORY_ROOT:
102 REPOSITORY_ROOT = SVN.GetCheckoutRoot(os.getcwd()) 99 REPOSITORY_ROOT = SVN.GetCheckoutRoot(os.getcwd())
(...skipping 502 matching lines...) Expand 10 before | Expand all | Expand 10 after
605 continue 602 continue
606 note = "" 603 note = ""
607 change_info = ChangeInfo.Load(cl_name, GetRepositoryRoot(), 604 change_info = ChangeInfo.Load(cl_name, GetRepositoryRoot(),
608 fail_on_not_found=True, update_status=False) 605 fail_on_not_found=True, update_status=False)
609 if len(change_info.GetFiles()) != len(files[cl_name]): 606 if len(change_info.GetFiles()) != len(files[cl_name]):
610 note = " (Note: this changelist contains files outside this directory)" 607 note = " (Note: this changelist contains files outside this directory)"
611 print "\n--- Changelist " + cl_name + note + ":" 608 print "\n--- Changelist " + cl_name + note + ":"
612 for filename in files[cl_name]: 609 for filename in files[cl_name]:
613 print "".join(filename) 610 print "".join(filename)
614 if show_unknown_files: 611 if show_unknown_files:
615 unknown_files = UnknownFiles([]) 612 unknown_files = UnknownFiles()
616 if (files.get('') or (show_unknown_files and len(unknown_files))): 613 if (files.get('') or (show_unknown_files and len(unknown_files))):
617 print "\n--- Not in any changelist:" 614 print "\n--- Not in any changelist:"
618 for item in files.get('', []): 615 for item in files.get('', []):
619 print "".join(item) 616 print "".join(item)
620 if show_unknown_files: 617 if show_unknown_files:
621 for filename in unknown_files: 618 for filename in unknown_files:
622 print "? %s" % filename 619 print "? %s" % filename
623 return 0 620 return 0
624 621
625 622
626 def CMDopened(args):
627 """Lists modified files in the current directory down."""
628 if args:
629 ErrorExit("Doesn't support arguments")
630 return ListFiles(False)
631
632
633 def CMDstatus(args):
634 """Lists modified and unknown files in the current directory down."""
635 if args:
636 ErrorExit("Doesn't support arguments")
637 return ListFiles(True)
638
639
640 def CMDhelp(args):
641 """Prints this help or help for the given command."""
642 if args and len(args) > 2:
643 if args[2] == 'try':
644 return TryChange(None, ['--help'], swallow_exception=False)
645 if args[2] == 'upload':
646 upload.RealMain(['upload.py', '--help'])
647 return 0
648
649 print (
650 """GCL is a wrapper for Subversion that simplifies working with groups of files.
651 version """ + __version__ + """
652
653 Basic commands:
654 -----------------------------------------
655 gcl change change_name
656 Add/remove files to a changelist. Only scans the current directory and
657 subdirectories.
658
659 gcl upload change_name [-r reviewer1@gmail.com,reviewer2@gmail.com,...]
660 [--send_mail] [--no_try] [--no_presubmit]
661 [--no_watchlists]
662 Uploads the changelist to the server for review.
663 (You can create the file '.gcl_upload_no_try' in your home dir to
664 skip the automatic tries.)
665
666 gcl commit change_name [--no_presubmit]
667 Commits the changelist to the repository.
668
669 gcl lint change_name
670 Check all the files in the changelist for possible style violations.
671
672 Advanced commands:
673 -----------------------------------------
674 gcl delete change_name
675 Deletes a changelist.
676
677 gcl diff change_name
678 Diffs all files in the changelist.
679
680 gcl presubmit change_name
681 Runs presubmit checks without uploading the changelist.
682
683 gcl diff
684 Diffs all files in the current directory and subdirectories that aren't in
685 a changelist.
686
687 gcl description
688 Prints the description of the specified change to stdout.
689
690 gcl changes
691 Lists all the the changelists and the files in them.
692
693 gcl rename <old-name> <new-name>
694 Renames an existing change.
695
696 gcl nothave [optional directory]
697 Lists files unknown to Subversion.
698
699 gcl opened
700 Lists modified files in the current directory and subdirectories.
701
702 gcl settings
703 Print the code review settings for this directory.
704
705 gcl status
706 Lists modified and unknown files in the current directory and
707 subdirectories.
708
709 gcl try change_name
710 Sends the change to the tryserver so a trybot can do a test run on your
711 code. To send multiple changes as one path, use a comma-separated list
712 of changenames.
713 --> Use 'gcl help try' for more information!
714
715 gcl deleteempties
716 Deletes all changelists that have no files associated with them. Careful,
717 you can lose your descriptions.
718
719 gcl help [command]
720 Print this help menu, or help for the given command if it exists.
721 """)
722 return 0
723
724
725 def GetEditor(): 623 def GetEditor():
726 editor = os.environ.get("SVN_EDITOR") 624 editor = os.environ.get("SVN_EDITOR")
727 if not editor: 625 if not editor:
728 editor = os.environ.get("EDITOR") 626 editor = os.environ.get("EDITOR")
729 627
730 if not editor: 628 if not editor:
731 if sys.platform.startswith("win"): 629 if sys.platform.startswith("win"):
732 editor = "notepad" 630 editor = "notepad"
733 else: 631 else:
734 editor = "vi" 632 editor = "vi"
735 633
736 return editor 634 return editor
737 635
738 636
739 def GenerateDiff(files, root=None): 637 def GenerateDiff(files, root=None):
740 return SVN.GenerateDiff(files, root=root) 638 return SVN.GenerateDiff(files, root=root)
741 639
742 640
743 def OptionallyDoPresubmitChecks(change_info, committing, args): 641 def OptionallyDoPresubmitChecks(change_info, committing, args):
744 if FilterFlag(args, "--no_presubmit") or FilterFlag(args, "--force"): 642 if FilterFlag(args, "--no_presubmit") or FilterFlag(args, "--force"):
745 return True 643 return True
746 return DoPresubmitChecks(change_info, committing, True) 644 return DoPresubmitChecks(change_info, committing, True)
747 645
748 646
647 def defer_attributes(a, b):
648 """Copy attributes from an object (like a function) to another."""
649 for x in dir(a):
650 if not getattr(b, x, None):
651 setattr(b, x, getattr(a, x))
652
653
749 def need_change(function): 654 def need_change(function):
750 """Converts args -> change_info.""" 655 """Converts args -> change_info."""
751 def hook(args): 656 def hook(args):
752 if not len(args) == 1: 657 if not len(args) == 1:
753 ErrorExit("You need to pass a change list name") 658 ErrorExit("You need to pass a change list name")
754 change_info = ChangeInfo.Load(args[0], GetRepositoryRoot(), True, True) 659 change_info = ChangeInfo.Load(args[0], GetRepositoryRoot(), True, True)
755 return function(change_info) 660 return function(change_info)
661 defer_attributes(function, hook)
662 hook.need_change = True
663 hook.no_args = True
756 return hook 664 return hook
757 665
758 666
759 def CMDupload(args): 667 def need_change_and_args(function):
760 if not args: 668 """Converts args -> change_info."""
761 ErrorExit("You need to pass a change list name") 669 def hook(args):
762 change_info = ChangeInfo.Load(args.pop(0), GetRepositoryRoot(), True, True) 670 change_info = ChangeInfo.Load(args.pop(0), GetRepositoryRoot(), True, True)
671 return function(change_info, args)
672 defer_attributes(function, hook)
673 hook.need_change = True
674 return hook
675
676
677 def no_args(function):
678 """Make sure no args are passed."""
679 def hook(args):
680 if args:
681 ErrorExit("Doesn't support arguments")
682 return function()
683 defer_attributes(function, hook)
684 hook.no_args = True
685 return hook
686
687
688 def attrs(**kwargs):
689 """Decorate a function with new attributes."""
690 def decorate(function):
691 for k in kwargs:
692 setattr(function, k, kwargs[k])
693 return function
694 return decorate
695
696
697 @no_args
698 def CMDopened():
699 """Lists modified files in the current directory down."""
700 return ListFiles(False)
701
702
703 @no_args
704 def CMDstatus():
705 """Lists modified and unknown files in the current directory down."""
706 return ListFiles(True)
707
708
709 @need_change_and_args
710 @attrs(usage='[--no_try] [--no_presubmit] [--clobber]\n'
711 ' [--no_watchlists]')
712 def CMDupload(change_info, args):
713 """Uploads the changelist to the server for review.
714
715 (You can create the file '.gcl_upload_no_try' in your home dir to
716 skip the automatic tries.)
717 """
763 if not change_info.GetFiles(): 718 if not change_info.GetFiles():
764 print "Nothing to upload, changelist is empty." 719 print "Nothing to upload, changelist is empty."
765 return 0 720 return 0
766 if not OptionallyDoPresubmitChecks(change_info, False, args): 721 if not OptionallyDoPresubmitChecks(change_info, False, args):
767 return 1 722 return 1
768 # Might want to support GetInfoDir()/GetRepositoryRoot() like 723 # Might want to support GetInfoDir()/GetRepositoryRoot() like
769 # CheckHomeForFile() so the skip of tries can be per tree basis instead 724 # CheckHomeForFile() so the skip of tries can be per tree basis instead
770 # of user global. 725 # of user global.
771 no_try = FilterFlag(args, "--no_try") or \ 726 no_try = (FilterFlag(args, "--no_try") or
772 FilterFlag(args, "--no-try") or \ 727 FilterFlag(args, "--no-try") or
773 not (CheckHomeForFile(".gcl_upload_no_try") is None) 728 not (CheckHomeForFile(".gcl_upload_no_try") is None))
774 no_watchlists = FilterFlag(args, "--no_watchlists") or \ 729 no_watchlists = (FilterFlag(args, "--no_watchlists") or
775 FilterFlag(args, "--no-watchlists") 730 FilterFlag(args, "--no-watchlists"))
776 731
777 # Map --send-mail to --send_mail 732 # Map --send-mail to --send_mail
778 if FilterFlag(args, "--send-mail"): 733 if FilterFlag(args, "--send-mail"):
779 args.append("--send_mail") 734 args.append("--send_mail")
780 735
781 # Supports --clobber for the try server. 736 # Supports --clobber for the try server.
782 clobber = FilterFlag(args, "--clobber") 737 clobber = FilterFlag(args, "--clobber")
783 738
784 # Disable try when the server is overridden. 739 # Disable try when the server is overridden.
785 server_1 = re.compile(r"^-s\b.*") 740 server_1 = re.compile(r"^-s\b.*")
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
870 if try_on_upload and try_on_upload.lower() == 'true': 825 if try_on_upload and try_on_upload.lower() == 'true':
871 trychange_args = [] 826 trychange_args = []
872 if clobber: 827 if clobber:
873 trychange_args.append('--clobber') 828 trychange_args.append('--clobber')
874 return TryChange(change_info, trychange_args, swallow_exception=True) 829 return TryChange(change_info, trychange_args, swallow_exception=True)
875 return 0 830 return 0
876 831
877 832
878 @need_change 833 @need_change
879 def CMDpresubmit(change_info): 834 def CMDpresubmit(change_info):
880 """Runs presubmit checks on the change.""" 835 """Runs presubmit checks on the change.
836
837 The actual presubmit code is implemented in presubmit_support.py and looks
838 for PRESUBMIT.py files."""
881 if not change_info.GetFiles(): 839 if not change_info.GetFiles():
882 print "Nothing to presubmit check, changelist is empty." 840 print "Nothing to presubmit check, changelist is empty."
883 return 0 841 return 0
884 842
885 print "*** Presubmit checks for UPLOAD would report: ***" 843 print "*** Presubmit checks for UPLOAD would report: ***"
886 result = DoPresubmitChecks(change_info, False, False) 844 result = DoPresubmitChecks(change_info, False, False)
887 845
888 print "\n*** Presubmit checks for COMMIT would report: ***" 846 print "\n*** Presubmit checks for COMMIT would report: ***"
889 result &= DoPresubmitChecks(change_info, True, False) 847 result &= DoPresubmitChecks(change_info, True, False)
890 return not result 848 return not result
(...skipping 19 matching lines...) Expand all
910 file_list = change_info.GetFileNames() 868 file_list = change_info.GetFileNames()
911 else: 869 else:
912 trychange_args.extend(args) 870 trychange_args.extend(args)
913 file_list = None 871 file_list = None
914 return trychange.TryChange(trychange_args, 872 return trychange.TryChange(trychange_args,
915 file_list=file_list, 873 file_list=file_list,
916 swallow_exception=swallow_exception, 874 swallow_exception=swallow_exception,
917 prog='gcl try') 875 prog='gcl try')
918 876
919 877
920 def CMDcommit(args): 878 @need_change_and_args
921 if not args: 879 @attrs(usage='[--no_presubmit]')
922 ErrorExit("You need to pass a change list name") 880 def CMDcommit(change_list, args):
923 change_info = ChangeInfo.Load(args.pop(0), GetRepositoryRoot(), True, True) 881 """Commits the changelist to the repository."""
924 if not change_info.GetFiles(): 882 if not change_info.GetFiles():
925 print "Nothing to commit, changelist is empty." 883 print "Nothing to commit, changelist is empty."
926 return 1 884 return 1
927 if not OptionallyDoPresubmitChecks(change_info, True, args): 885 if not OptionallyDoPresubmitChecks(change_info, True, args):
928 return 1 886 return 1
929 887
930 # We face a problem with svn here: Let's say change 'bleh' modifies 888 # We face a problem with svn here: Let's say change 'bleh' modifies
931 # svn:ignore on dir1\. but another unrelated change 'pouet' modifies 889 # svn:ignore on dir1\. but another unrelated change 'pouet' modifies
932 # dir1\foo.cc. When the user `gcl commit bleh`, foo.cc is *also committed*. 890 # dir1\foo.cc. When the user `gcl commit bleh`, foo.cc is *also committed*.
933 # The only fix is to use --non-recursive but that has its issues too: 891 # The only fix is to use --non-recursive but that has its issues too:
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
971 viewvc_url = GetCodeReviewSetting("VIEW_VC") 929 viewvc_url = GetCodeReviewSetting("VIEW_VC")
972 change_info.description = change_info.description + '\n' 930 change_info.description = change_info.description + '\n'
973 if viewvc_url: 931 if viewvc_url:
974 change_info.description += "\nCommitted: " + viewvc_url + revision 932 change_info.description += "\nCommitted: " + viewvc_url + revision
975 change_info.CloseIssue() 933 change_info.CloseIssue()
976 os.chdir(previous_cwd) 934 os.chdir(previous_cwd)
977 return 0 935 return 0
978 936
979 937
980 def CMDchange(args): 938 def CMDchange(args):
981 """Creates/edits a changelist.""" 939 """Creates or edits a changelist.
940
941 Only scans the current directory and subdirectories."""
982 if len(args) == 0: 942 if len(args) == 0:
983 # Generate a random changelist name. 943 # Generate a random changelist name.
984 changename = GenerateChangeName() 944 changename = GenerateChangeName()
985 elif args[0] == '--force': 945 elif args[0] == '--force':
986 changename = GenerateChangeName() 946 changename = GenerateChangeName()
987 else: 947 else:
988 changename = args[0] 948 changename = args[0]
989 change_info = ChangeInfo.Load(changename, GetRepositoryRoot(), False, True) 949 change_info = ChangeInfo.Load(changename, GetRepositoryRoot(), False, True)
990 silent = FilterFlag(args, "--silent") 950 silent = FilterFlag(args, "--silent")
991 951
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
1091 Warn("WARNING: " + MISSING_TEST_MSG) 1051 Warn("WARNING: " + MISSING_TEST_MSG)
1092 1052
1093 # Update the Rietveld issue. 1053 # Update the Rietveld issue.
1094 if change_info.issue and change_info.NeedsUpload(): 1054 if change_info.issue and change_info.NeedsUpload():
1095 change_info.UpdateRietveldDescription() 1055 change_info.UpdateRietveldDescription()
1096 change_info.needs_upload = False 1056 change_info.needs_upload = False
1097 change_info.Save() 1057 change_info.Save()
1098 return 0 1058 return 0
1099 1059
1100 1060
1101 @need_change 1061 @need_change_and_args
1102 def CMDlint(change_info): 1062 def CMDlint(change_info, args):
1103 """Runs cpplint.py on all the files in |change_info|""" 1063 """Runs cpplint.py on all the files in the change list.
1064
1065 Checks all the files in the changelist for possible style violations.
1066 """
1104 try: 1067 try:
1105 import cpplint 1068 import cpplint
1106 except ImportError: 1069 except ImportError:
1107 ErrorExit("You need to install cpplint.py to lint C++ files.") 1070 ErrorExit("You need to install cpplint.py to lint C++ files.")
1108 # Change the current working directory before calling lint so that it 1071 # Change the current working directory before calling lint so that it
1109 # shows the correct base. 1072 # shows the correct base.
1110 previous_cwd = os.getcwd() 1073 previous_cwd = os.getcwd()
1111 os.chdir(change_info.GetLocalRoot()) 1074 os.chdir(change_info.GetLocalRoot())
1112 1075
1113 # Process cpplints arguments if any. 1076 # Process cpplints arguments if any.
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1151 verbose=False, 1114 verbose=False,
1152 output_stream=sys.stdout, 1115 output_stream=sys.stdout,
1153 input_stream=sys.stdin, 1116 input_stream=sys.stdin,
1154 default_presubmit=root_presubmit, 1117 default_presubmit=root_presubmit,
1155 may_prompt=may_prompt) 1118 may_prompt=may_prompt)
1156 if not result and may_prompt: 1119 if not result and may_prompt:
1157 print "\nPresubmit errors, can't continue (use --no_presubmit to bypass)" 1120 print "\nPresubmit errors, can't continue (use --no_presubmit to bypass)"
1158 return result 1121 return result
1159 1122
1160 1123
1161 def CMDchanges(args): 1124 @no_args
1125 def CMDchanges():
1162 """Lists all the changelists and their files.""" 1126 """Lists all the changelists and their files."""
1163 if args:
1164 ErrorExit("Doesn't support arguments")
1165 for cl in GetCLs(): 1127 for cl in GetCLs():
1166 change_info = ChangeInfo.Load(cl, GetRepositoryRoot(), True, True) 1128 change_info = ChangeInfo.Load(cl, GetRepositoryRoot(), True, True)
1167 print "\n--- Changelist " + change_info.name + ":" 1129 print "\n--- Changelist " + change_info.name + ":"
1168 for filename in change_info.GetFiles(): 1130 for filename in change_info.GetFiles():
1169 print "".join(filename) 1131 print "".join(filename)
1170 return 0 1132 return 0
1171 1133
1172 1134
1173 def CMDdeleteempties(args): 1135 @no_args
1136 def CMDdeleteempties():
1174 """Delete all changelists that have no files.""" 1137 """Delete all changelists that have no files."""
1175 if args:
1176 ErrorExit("Doesn't support arguments")
1177 print "\n--- Deleting:" 1138 print "\n--- Deleting:"
1178 for cl in GetCLs(): 1139 for cl in GetCLs():
1179 change_info = ChangeInfo.Load(cl, GetRepositoryRoot(), True, True) 1140 change_info = ChangeInfo.Load(cl, GetRepositoryRoot(), True, True)
1180 if not len(change_info._files): 1141 if not len(change_info._files):
1181 print change_info.name 1142 print change_info.name
1182 change_info.Delete() 1143 change_info.Delete()
1183 return 0 1144 return 0
1184 1145
1185 1146
1186 def CMDnothave(args): 1147 @no_args
1148 def CMDnothave():
1187 """Lists files unknown to Subversion.""" 1149 """Lists files unknown to Subversion."""
1188 if args: 1150 for filename in UnknownFiles():
1189 ErrorExit("Doesn't support arguments")
1190 for filename in UnknownFiles(args):
1191 print "? " + "".join(filename) 1151 print "? " + "".join(filename)
1192 return 0 1152 return 0
1193 1153
1194 1154
1155 @attrs(usage='<svn options>')
1195 def CMDdiff(args): 1156 def CMDdiff(args):
1196 """Diffs all files in the changelist.""" 1157 """Diffs all files in the changelist or all files that aren't in a CL."""
1197 files = None 1158 files = None
1198 if args: 1159 if args:
1199 change_info = ChangeInfo.Load(args[0], GetRepositoryRoot(), True, True) 1160 change_info = ChangeInfo.Load(args.pop(0), GetRepositoryRoot(), True, True)
1200 args.pop(0)
1201 files = change_info.GetFileNames() 1161 files = change_info.GetFileNames()
1202 else: 1162 else:
1203 files = GetFilesNotInCL() 1163 files = GetFilesNotInCL()
1204 return RunShellWithReturnCode(['svn', 'diff'] + files + args, 1164 return RunShellWithReturnCode(['svn', 'diff'] + files + args,
1205 print_output=True)[1] 1165 print_output=True)[1]
1206 1166
1207 1167
1208 def CMDsettings(args): 1168 @no_args
1209 """Prints code review settings.""" 1169 def CMDsettings():
1210 __pychecker__ = 'unusednames=args' 1170 """Prints code review settings for this checkout."""
1211 # Force load settings 1171 # Force load settings
1212 GetCodeReviewSetting("UNKNOWN"); 1172 GetCodeReviewSetting("UNKNOWN");
1213 del CODEREVIEW_SETTINGS['__just_initialized'] 1173 del CODEREVIEW_SETTINGS['__just_initialized']
1214 print '\n'.join(("%s: %s" % (str(k), str(v)) 1174 print '\n'.join(("%s: %s" % (str(k), str(v))
1215 for (k,v) in CODEREVIEW_SETTINGS.iteritems())) 1175 for (k,v) in CODEREVIEW_SETTINGS.iteritems()))
1216 return 0 1176 return 0
1217 1177
1218 1178
1219 @need_change 1179 @need_change
1220 def CMDdescription(change_info): 1180 def CMDdescription(change_info):
1221 """Prints the description of the specified change to stdout.""" 1181 """Prints the description of the specified change to stdout."""
1222 print change_info.description 1182 print change_info.description
1223 return 0 1183 return 0
1224 1184
1225 1185
1226 @need_change 1186 @need_change
1227 def CMDdelete(change_info): 1187 def CMDdelete(change_info):
1228 """Deletes a changelist.""" 1188 """Deletes a changelist."""
1229 change_info.Delete() 1189 change_info.Delete()
1230 return 0 1190 return 0
1231 1191
1232 1192
1233 def CMDtry(args): 1193 def CMDtry(args):
1234 """Sends the change to the tryserver so a trybot can do a test run on your 1194 """Sends the change to the tryserver to do a test run on your code.
1235 code.
1236 1195
1237 To send multiple changes as one path, use a comma-separated list of 1196 To send multiple changes as one path, use a comma-separated list of
1238 changenames. Use 'gcl help try' for more information!""" 1197 changenames. Use 'gcl help try' for more information!"""
1239 # When the change contains no file, send the "changename" positional 1198 # When the change contains no file, send the "changename" positional
1240 # argument to trychange.py. 1199 # argument to trychange.py.
1241 # When the command is 'try' and --patchset is used, the patch to try 1200 # When the command is 'try' and --patchset is used, the patch to try
1242 # is on the Rietveld server. 1201 # is on the Rietveld server.
1243 if not args: 1202 if not args:
1244 ErrorExit("You need to pass a change list name") 1203 ErrorExit("You need to pass a change list name")
1245 if args[0].find(',') != -1: 1204 if args[0].find(',') != -1:
1246 change_info = LoadChangelistInfoForMultiple(args[0], GetRepositoryRoot(), 1205 change_info = LoadChangelistInfoForMultiple(args[0], GetRepositoryRoot(),
1247 True, True) 1206 True, True)
1248 else: 1207 else:
1249 change_info = ChangeInfo.Load(args[0], GetRepositoryRoot(), 1208 change_info = ChangeInfo.Load(args[0], GetRepositoryRoot(),
1250 False, True) 1209 False, True)
1251 if change_info.GetFiles(): 1210 if change_info.GetFiles():
1252 args = args[1:] 1211 args = args[1:]
1253 else: 1212 else:
1254 change_info = None 1213 change_info = None
1255 return TryChange(change_info, args, swallow_exception=False) 1214 return TryChange(change_info, args, swallow_exception=False)
1256 1215
1257 1216
1217 @attrs(usage='<old-name> <new-name>')
1258 def CMDrename(args): 1218 def CMDrename(args):
1259 """Renames an existing change.""" 1219 """Renames an existing change."""
1260 if len(args) != 2: 1220 if len(args) != 2:
1261 ErrorExit("Usage: gcl rename <old-name> <new-name>.") 1221 ErrorExit("Usage: gcl rename <old-name> <new-name>.")
1262 src, dst = args 1222 src, dst = args
1263 src_file = GetChangelistInfoFile(src) 1223 src_file = GetChangelistInfoFile(src)
1264 if not os.path.isfile(src_file): 1224 if not os.path.isfile(src_file):
1265 ErrorExit("Change '%s' does not exist." % src) 1225 ErrorExit("Change '%s' does not exist." % src)
1266 dst_file = GetChangelistInfoFile(dst) 1226 dst_file = GetChangelistInfoFile(dst)
1267 if os.path.isfile(dst_file): 1227 if os.path.isfile(dst_file):
1268 ErrorExit("Change '%s' already exists; pick a new name." % dst) 1228 ErrorExit("Change '%s' already exists; pick a new name." % dst)
1269 os.rename(src_file, dst_file) 1229 os.rename(src_file, dst_file)
1270 print "Change '%s' renamed '%s'." % (src, dst) 1230 print "Change '%s' renamed '%s'." % (src, dst)
1271 return 0 1231 return 0
1272 1232
1273 1233
1274 def CMDpassthru(args): 1234 def CMDpassthru(args):
1275 # Everything else that is passed into gcl we redirect to svn, after adding 1235 """Everything else that is passed into gcl we redirect to svn.
1276 # the files. 1236
1277 # args is guaranteed to be len(args) >= 1 1237 It assumes a change list name is passed and is converted with the files names.
1238 """
1278 args = ["svn", args[0]] 1239 args = ["svn", args[0]]
1279 if len(args) > 1: 1240 if len(args) > 1:
1280 root = GetRepositoryRoot() 1241 root = GetRepositoryRoot()
1281 change_info = ChangeInfo.Load(args[1], root, True, True) 1242 change_info = ChangeInfo.Load(args[1], root, True, True)
1282 args.extend([os.path.join(root, x) for x in change_info.GetFileNames()]) 1243 args.extend([os.path.join(root, x) for x in change_info.GetFileNames()])
1283 return RunShellWithReturnCode(args, print_output=True)[1] 1244 return RunShellWithReturnCode(args, print_output=True)[1]
1284 1245
1285 1246
1247 def Command(name):
1248 return getattr(sys.modules[__name__], 'CMD' + name, None)
1249
1250
1251 def GenUsage(command):
1252 """Modify an OptParse object with the function's documentation."""
1253 obj = Command(command)
1254 display = command
1255 more = getattr(obj, 'usage', '')
1256 if command == 'help':
1257 display = '<command>'
1258 need_change = ''
1259 if getattr(obj, 'need_change', None):
1260 need_change = ' <change_list>'
1261 options = ' [options]'
1262 if getattr(obj, 'no_args', None):
1263 options = ''
1264 res = 'Usage: gcl %s%s%s %s\n\n' % (display, need_change, options, more)
1265 res += re.sub('\n ', '\n', obj.__doc__)
1266 return res
1267
1268
1269 def CMDhelp(args):
1270 """Prints this help or help for the given command."""
1271 if args and 'CMD' + args[0] in dir(sys.modules[__name__]):
1272 print GenUsage(args[0])
1273
1274 # These commands defer to external tools so give this info too.
1275 if args[0] == 'try':
1276 TryChange(None, ['--help'], swallow_exception=False)
1277 if args[0] == 'upload':
1278 upload.RealMain(['upload.py', '--help'])
1279 return 0
1280
1281 print GenUsage('help')
1282 print sys.modules[__name__].__doc__
1283 print 'version ' + __version__ + '\n'
1284
1285 print('Commands are:\n' + '\n'.join([
1286 ' %-12s %s' % (fn[3:], Command(fn[3:]).__doc__.split('\n')[0].strip())
1287 for fn in dir(sys.modules[__name__]) if fn.startswith('CMD')]))
1288 return 0
1289
1290
1286 def main(argv): 1291 def main(argv):
1287 __pychecker__ = 'maxreturns=0'
1288 try: 1292 try:
1289 # Create the directories where we store information about changelists if it 1293 GetRepositoryRoot()
1290 # doesn't exist.
1291 if not os.path.exists(GetInfoDir()):
1292 os.mkdir(GetInfoDir())
1293 if not os.path.exists(GetChangesDir()):
1294 os.mkdir(GetChangesDir())
1295 if not os.path.exists(GetCacheDir()):
1296 os.mkdir(GetCacheDir())
1297 except gclient_utils.Error: 1294 except gclient_utils.Error:
1298 # Will throw an exception if not run in a svn checkout. 1295 print('To use gcl, you need to be in a subversion checkout.')
1299 pass 1296 return 1
1297
1298 # Create the directories where we store information about changelists if it
1299 # doesn't exist.
1300 if not os.path.exists(GetInfoDir()):
1301 os.mkdir(GetInfoDir())
1302 if not os.path.exists(GetChangesDir()):
1303 os.mkdir(GetChangesDir())
1304 if not os.path.exists(GetCacheDir()):
1305 os.mkdir(GetCacheDir())
1300 1306
1301 if not argv: 1307 if not argv:
1302 argv = ['help'] 1308 argv = ['help']
1303 # Commands that don't require an argument. 1309 command = Command(argv[0])
1304 command = argv[0] 1310 if command:
1305 if command == "opened": 1311 return command(argv[1:])
1306 return CMDopened(argv[1:]) 1312 # Unknown command, try to pass that to svn
1307 if command == "status": 1313 return CMDpassthru(argv)
1308 return CMDstatus(argv[1:])
1309 if command == "nothave":
1310 return CMDnothave(argv[1:])
1311 if command == "changes":
1312 return CMDchanges(argv[1:])
1313 if command == "help":
1314 return CMDhelp(argv[1:])
1315 if command == "diff":
1316 return CMDdiff(argv[1:])
1317 if command == "settings":
1318 return CMDsettings(argv[1:])
1319 if command == "deleteempties":
1320 return CMDdeleteempties(argv[1:])
1321 if command == "rename":
1322 return CMDrename(argv[1:])
1323 elif command == "change":
1324 return CMDchange(argv[1:])
1325 elif command == "description":
1326 return CMDdescription(argv[1:])
1327 elif command == "lint":
1328 return CMDlint(argv[1:])
1329 elif command == "upload":
1330 return CMDupload(argv[1:])
1331 elif command == "presubmit":
1332 return CMDpresubmit(argv[1:])
1333 elif command in ("commit", "submit"):
1334 return CMDcommit(argv[1:])
1335 elif command == "delete":
1336 return CMDdelete(argv[1:])
1337 elif command == "try":
1338 return CMDtry(argv[1:])
1339 else:
1340 return CMDpassthru(argv)
1341 1314
1342 1315
1343 if __name__ == "__main__": 1316 if __name__ == "__main__":
1344 sys.exit(main(sys.argv[1:])) 1317 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « no previous file | tests/gcl_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698