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 # Copyright (C) 2008 Evan Martin <martine@danga.com> | 6 # Copyright (C) 2008 Evan Martin <martine@danga.com> |
7 | 7 |
8 """A git-command for integrating reviews on Rietveld.""" | 8 """A git-command for integrating reviews on Rietveld.""" |
9 | 9 |
10 import json | 10 import json |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
47 | 47 |
48 | 48 |
49 def DieWithError(message): | 49 def DieWithError(message): |
50 print >> sys.stderr, message | 50 print >> sys.stderr, message |
51 sys.exit(1) | 51 sys.exit(1) |
52 | 52 |
53 | 53 |
54 def RunCommand(args, error_ok=False, error_message=None, **kwargs): | 54 def RunCommand(args, error_ok=False, error_message=None, **kwargs): |
55 try: | 55 try: |
56 return subprocess2.check_output(args, shell=False, **kwargs) | 56 return subprocess2.check_output(args, shell=False, **kwargs) |
57 except subprocess2.CalledProcessError, e: | 57 except subprocess2.CalledProcessError as e: |
58 logging.debug('Failed running %s', args) | |
58 if not error_ok: | 59 if not error_ok: |
59 DieWithError( | 60 DieWithError( |
60 'Command "%s" failed.\n%s' % ( | 61 'Command "%s" failed.\n%s' % ( |
61 ' '.join(args), error_message or e.stdout or '')) | 62 ' '.join(args), error_message or e.stdout or '')) |
62 return e.stdout | 63 return e.stdout |
63 | 64 |
64 | 65 |
65 def RunGit(args, **kwargs): | 66 def RunGit(args, **kwargs): |
66 """Returns stdout.""" | 67 """Returns stdout.""" |
67 return RunCommand(['git'] + args, **kwargs) | 68 return RunCommand(['git'] + args, **kwargs) |
(...skipping 722 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
790 SetProperty(settings.GetTreeStatusUrl(error_ok=True), 'Tree status URL', | 791 SetProperty(settings.GetTreeStatusUrl(error_ok=True), 'Tree status URL', |
791 'tree-status-url', False) | 792 'tree-status-url', False) |
792 SetProperty(settings.GetViewVCUrl(), 'ViewVC URL', 'viewvc-url', True) | 793 SetProperty(settings.GetViewVCUrl(), 'ViewVC URL', 'viewvc-url', True) |
793 | 794 |
794 # TODO: configure a default branch to diff against, rather than this | 795 # TODO: configure a default branch to diff against, rather than this |
795 # svn-based hackery. | 796 # svn-based hackery. |
796 | 797 |
797 | 798 |
798 class ChangeDescription(object): | 799 class ChangeDescription(object): |
799 """Contains a parsed form of the change description.""" | 800 """Contains a parsed form of the change description.""" |
800 def __init__(self, log_desc, reviewers): | 801 R_LINE = r'^\s*(TBR|R)\s*=\s*(.+)\s*$' |
801 self.log_desc = log_desc | |
802 self.reviewers = reviewers | |
803 self.description = self.log_desc | |
804 | 802 |
805 def Prompt(self): | 803 def __init__(self, description): |
806 content = """# Enter a description of the change. | 804 self._description = (description or '').strip() |
807 # This will displayed on the codereview site. | 805 |
808 # The first line will also be used as the subject of the review. | 806 @property |
809 """ | 807 def description(self): |
810 content += self.description | 808 return self._description |
811 if ('\nR=' not in self.description and | 809 |
812 '\nTBR=' not in self.description and | 810 def update_reviewers(self, reviewers): |
iannucci
2013/04/08 22:49:40
Can we make reviewers a list of reviewers instead
Dirk Pranke
2013/04/09 00:07:52
I don't think we can easily do this without pushin
M-A Ruel
2013/04/11 00:01:38
So reviewers is now a list all the time.
| |
813 self.reviewers): | 811 """Rewrites the R=/TBR= line(s) as a single line.""" |
814 content += '\nR=' + self.reviewers | 812 if not reviewers: |
813 return | |
814 regexp = re.compile(self.R_LINE, re.MULTILINE) | |
815 matches = list(regexp.finditer(self.description)) | |
816 is_tbr = any(m.group(1) == 'TBR' for m in matches) | |
817 if len(matches) > 1: | |
818 # Erase all except the first one. | |
819 for i in xrange(len(matches) - 1, 0, -1): | |
820 self._description = ( | |
821 self.description[:matches[i].start()] + | |
822 self.description[matches[i].end()+1:]) | |
Dirk Pranke
2013/04/09 00:07:52
switching back and forth between self._description
M-A Ruel
2013/04/11 00:01:38
Done.
| |
823 | |
824 if is_tbr: | |
825 new_r_line = 'TBR=' + reviewers | |
826 else: | |
827 new_r_line = 'R=' + reviewers | |
828 | |
829 if matches: | |
830 self._description = ( | |
831 self.description[:matches[0].start()] + new_r_line + | |
832 self.description[matches[0].end()+1:]) | |
833 else: | |
834 self.append_line(new_r_line) | |
835 | |
836 def prompt(self): | |
837 """Asks the user to update the description.""" | |
838 self._description = ( | |
839 '# Enter a description of the change.\n' | |
840 '# This will displayed on the codereview site.\n' | |
841 '# The first line will also be used as the subject of the review.\n' | |
842 ) + self.description | |
843 | |
815 if '\nBUG=' not in self.description: | 844 if '\nBUG=' not in self.description: |
816 content += '\nBUG=' | 845 self.append_line('BUG=') |
817 content = content.rstrip('\n') + '\n' | 846 content = gclient_utils.RunEditor(self.description, True) |
818 content = gclient_utils.RunEditor(content, True) | |
819 if not content: | 847 if not content: |
820 DieWithError('Running editor failed') | 848 DieWithError('Running editor failed') |
849 | |
850 # Strip off comments. | |
821 content = re.compile(r'^#.*$', re.MULTILINE).sub('', content).strip() | 851 content = re.compile(r'^#.*$', re.MULTILINE).sub('', content).strip() |
822 if not content.strip(): | 852 if not content: |
823 DieWithError('No CL description, aborting') | 853 DieWithError('No CL description, aborting') |
824 self.description = content | 854 self._description = content |
825 | 855 |
826 def ParseDescription(self): | 856 def append_line(self, line): |
Dirk Pranke
2013/04/09 00:07:52
I would probably call this something like add_keyw
| |
827 """Updates the list of reviewers and subject from the description.""" | 857 # Adds a LF if the last line did not have 'FOO=BAR' or if the new one isn't. |
828 self.description = self.description.strip('\n') + '\n' | 858 if self.description: |
829 # Retrieves all reviewer lines | 859 if '\n' not in self.description: |
830 regexp = re.compile(r'^\s*(TBR|R)=(.+)$', re.MULTILINE) | 860 self._description += '\n' |
831 reviewers = ','.join( | 861 else: |
832 i.group(2).strip() for i in regexp.finditer(self.description)) | 862 last_line = self.description.rsplit('\n', 1)[1] |
833 if reviewers: | 863 if (not presubmit_support.Change.TAG_LINE_RE.match(last_line) or |
834 self.reviewers = reviewers | 864 not presubmit_support.Change.TAG_LINE_RE.match(line)): |
865 self._description += '\n' | |
866 self._description += '\n' + line | |
835 | 867 |
836 def IsEmpty(self): | 868 def get_reviewers(self): |
837 return not self.description | 869 """Retrieves the list of reviewers.""" |
870 regexp = re.compile(self.R_LINE, re.MULTILINE) | |
871 reviewers = sum( | |
872 (i.group(2).split(',') for i in regexp.finditer(self.description)), | |
873 []) | |
874 reviewers = (i.strip() for i in reviewers) | |
875 return sorted(i for i in reviewers if i) | |
838 | 876 |
839 | 877 |
840 def FindCodereviewSettingsFile(filename='codereview.settings'): | 878 def FindCodereviewSettingsFile(filename='codereview.settings'): |
841 """Finds the given file starting in the cwd and going up. | 879 """Finds the given file starting in the cwd and going up. |
842 | 880 |
843 Only looks up to the top of the repository unless an | 881 Only looks up to the top of the repository unless an |
844 'inherit-review-settings-ok' file exists in the root of the repository. | 882 'inherit-review-settings-ok' file exists in the root of the repository. |
845 """ | 883 """ |
846 inherit_ok_file = 'inherit-review-settings-ok' | 884 inherit_ok_file = 'inherit-review-settings-ok' |
847 cwd = os.getcwd() | 885 cwd = os.getcwd() |
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1095 | 1133 |
1096 def GerritUpload(options, args, cl): | 1134 def GerritUpload(options, args, cl): |
1097 """upload the current branch to gerrit.""" | 1135 """upload the current branch to gerrit.""" |
1098 # We assume the remote called "origin" is the one we want. | 1136 # We assume the remote called "origin" is the one we want. |
1099 # It is probably not worthwhile to support different workflows. | 1137 # It is probably not worthwhile to support different workflows. |
1100 remote = 'origin' | 1138 remote = 'origin' |
1101 branch = 'master' | 1139 branch = 'master' |
1102 if options.target_branch: | 1140 if options.target_branch: |
1103 branch = options.target_branch | 1141 branch = options.target_branch |
1104 | 1142 |
1105 log_desc = options.message or CreateDescriptionFromLog(args) | 1143 change_desc = ChangeDescription( |
1106 if CHANGE_ID not in log_desc: | 1144 options.message or CreateDescriptionFromLog(args)) |
1145 if not change_desc.description: | |
1146 print "Description is empty; aborting." | |
1147 return 1 | |
1148 if CHANGE_ID not in change_desc.description: | |
Dirk Pranke
2013/04/09 00:07:52
I wonder if we should restructure this so that we
M-A Ruel
2013/04/11 00:01:38
I prefer to keep this out of this CL since it invo
| |
1107 AddChangeIdToCommitMessage(options, args) | 1149 AddChangeIdToCommitMessage(options, args) |
1108 if options.reviewers: | 1150 if options.reviewers: |
1109 log_desc += '\nR=' + options.reviewers | 1151 change_desc.update_reviewers(options.reviewers) |
1110 change_desc = ChangeDescription(log_desc, options.reviewers) | |
1111 change_desc.ParseDescription() | |
1112 if change_desc.IsEmpty(): | |
1113 print "Description is empty; aborting." | |
1114 return 1 | |
1115 | 1152 |
1116 receive_options = [] | 1153 receive_options = [] |
1117 cc = cl.GetCCList().split(',') | 1154 cc = cl.GetCCList().split(',') |
1118 if options.cc: | 1155 if options.cc: |
1119 cc += options.cc.split(',') | 1156 cc += options.cc.split(',') |
1120 cc = filter(None, cc) | 1157 cc = filter(None, cc) |
1121 if cc: | 1158 if cc: |
1122 receive_options += ['--cc=' + email for email in cc] | 1159 receive_options += ['--cc=' + email for email in cc] |
1123 if change_desc.reviewers: | 1160 if change_desc.get_reviewers(): |
1124 reviewers = filter(None, change_desc.reviewers.split(',')) | 1161 receive_options.extend( |
1125 if reviewers: | 1162 '--reviewer=' + email for email in change_desc.get_reviewers()) |
1126 receive_options += ['--reviewer=' + email for email in reviewers] | |
1127 | 1163 |
1128 git_command = ['push'] | 1164 git_command = ['push'] |
1129 if receive_options: | 1165 if receive_options: |
1130 git_command.append('--receive-pack=git receive-pack %s' % | 1166 git_command.append('--receive-pack=git receive-pack %s' % |
1131 ' '.join(receive_options)) | 1167 ' '.join(receive_options)) |
1132 git_command += [remote, 'HEAD:refs/for/' + branch] | 1168 git_command += [remote, 'HEAD:refs/for/' + branch] |
1133 RunGit(git_command) | 1169 RunGit(git_command) |
1134 # TODO(ukai): parse Change-Id: and set issue number? | 1170 # TODO(ukai): parse Change-Id: and set issue number? |
1135 return 0 | 1171 return 0 |
1136 | 1172 |
(...skipping 15 matching lines...) Expand all Loading... | |
1152 # for upload.py. Soon this will be changed to set the --message option. | 1188 # for upload.py. Soon this will be changed to set the --message option. |
1153 # Will wait until people are used to typing -t instead of -m. | 1189 # Will wait until people are used to typing -t instead of -m. |
1154 upload_args.extend(['--title', options.message]) | 1190 upload_args.extend(['--title', options.message]) |
1155 upload_args.extend(['--issue', str(cl.GetIssue())]) | 1191 upload_args.extend(['--issue', str(cl.GetIssue())]) |
1156 print ("This branch is associated with issue %s. " | 1192 print ("This branch is associated with issue %s. " |
1157 "Adding patch to that issue." % cl.GetIssue()) | 1193 "Adding patch to that issue." % cl.GetIssue()) |
1158 else: | 1194 else: |
1159 if options.title: | 1195 if options.title: |
1160 upload_args.extend(['--title', options.title]) | 1196 upload_args.extend(['--title', options.title]) |
1161 message = options.title or options.message or CreateDescriptionFromLog(args) | 1197 message = options.title or options.message or CreateDescriptionFromLog(args) |
1162 change_desc = ChangeDescription(message, options.reviewers) | 1198 change_desc = ChangeDescription(message) |
1199 if options.reviewers: | |
1200 change_desc.update_reviewers(options.reviewers) | |
1163 if not options.force: | 1201 if not options.force: |
1164 change_desc.Prompt() | 1202 change_desc.prompt() |
1165 change_desc.ParseDescription() | |
1166 | 1203 |
1167 if change_desc.IsEmpty(): | 1204 if not change_desc.description: |
1168 print "Description is empty; aborting." | 1205 print "Description is empty; aborting." |
1169 return 1 | 1206 return 1 |
1170 | 1207 |
1171 upload_args.extend(['--message', change_desc.description]) | 1208 upload_args.extend(['--message', change_desc.description]) |
1172 if change_desc.reviewers: | 1209 if change_desc.get_reviewers(): |
1173 upload_args.extend(['--reviewers', change_desc.reviewers]) | 1210 upload_args.append('--reviewers=' + ','.join(change_desc.get_reviewers())) |
1174 if options.send_mail: | 1211 if options.send_mail: |
1175 if not change_desc.reviewers: | 1212 if not change_desc.get_reviewers(): |
1176 DieWithError("Must specify reviewers to send email.") | 1213 DieWithError("Must specify reviewers to send email.") |
1177 upload_args.append('--send_mail') | 1214 upload_args.append('--send_mail') |
1178 cc = ','.join(filter(None, (cl.GetCCList(), options.cc))) | 1215 cc = ','.join(filter(None, (cl.GetCCList(), options.cc))) |
1179 if cc: | 1216 if cc: |
1180 upload_args.extend(['--cc', cc]) | 1217 upload_args.extend(['--cc', cc]) |
1181 | 1218 |
1182 upload_args.extend(['--git_similarity', str(options.similarity)]) | 1219 upload_args.extend(['--git_similarity', str(options.similarity)]) |
1183 if not options.find_copies: | 1220 if not options.find_copies: |
1184 upload_args.extend(['--git_no_find_copies']) | 1221 upload_args.extend(['--git_no_find_copies']) |
1185 | 1222 |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1409 elif 'unknown' == status: | 1446 elif 'unknown' == status: |
1410 print('Unable to determine tree status. Please verify manually and ' | 1447 print('Unable to determine tree status. Please verify manually and ' |
1411 'use "git cl dcommit --bypass-hooks" to commit on a closed tree.') | 1448 'use "git cl dcommit --bypass-hooks" to commit on a closed tree.') |
1412 else: | 1449 else: |
1413 breakpad.SendStack( | 1450 breakpad.SendStack( |
1414 'GitClHooksBypassedCommit', | 1451 'GitClHooksBypassedCommit', |
1415 'Issue %s/%s bypassed hook when committing' % | 1452 'Issue %s/%s bypassed hook when committing' % |
1416 (cl.GetRietveldServer(), cl.GetIssue()), | 1453 (cl.GetRietveldServer(), cl.GetIssue()), |
1417 verbose=False) | 1454 verbose=False) |
1418 | 1455 |
1419 description = options.message | 1456 change_desc = ChangeDescription(options.message) |
1420 if not description and cl.GetIssue(): | 1457 if not change_desc.description and cl.GetIssue(): |
1421 description = cl.GetDescription() | 1458 change_desc = ChangeDescription(cl.GetDescription()) |
1422 | 1459 |
1423 if not description: | 1460 if not change_desc.description: |
1424 if not cl.GetIssue() and options.bypass_hooks: | 1461 if not cl.GetIssue() and options.bypass_hooks: |
1425 description = CreateDescriptionFromLog([base_branch]) | 1462 change_desc = ChangeDescription(CreateDescriptionFromLog([base_branch])) |
1426 else: | 1463 else: |
1427 print 'No description set.' | 1464 print 'No description set.' |
1428 print 'Visit %s/edit to set it.' % (cl.GetIssueURL()) | 1465 print 'Visit %s/edit to set it.' % (cl.GetIssueURL()) |
1429 return 1 | 1466 return 1 |
1430 | 1467 |
1468 # Keep a separate copy for the commit message. | |
Dirk Pranke
2013/04/09 00:07:52
Can you clarify *why* we need a separate copy here
M-A Ruel
2013/04/11 00:01:38
Done.
| |
1469 commit_desc = ChangeDescription(change_desc.description) | |
1431 if cl.GetIssue(): | 1470 if cl.GetIssue(): |
1432 description += "\n\nReview URL: %s" % cl.GetIssueURL() | 1471 commit_desc.append_line('Review URL: %s' % cl.GetIssueURL()) |
1472 if options.contributor: | |
1473 commit_desc.append_line('Patch from %s.' % options.contributor) | |
1433 | 1474 |
1434 if options.contributor: | 1475 print 'Description:', repr(commit_desc.description) |
1435 description += "\nPatch from %s." % options.contributor | |
1436 print 'Description:', repr(description) | |
1437 | 1476 |
1438 branches = [base_branch, cl.GetBranchRef()] | 1477 branches = [base_branch, cl.GetBranchRef()] |
1439 if not options.force: | 1478 if not options.force: |
1440 print_stats(options.similarity, options.find_copies, branches) | 1479 print_stats(options.similarity, options.find_copies, branches) |
1441 ask_for_data('About to commit; enter to confirm.') | 1480 ask_for_data('About to commit; enter to confirm.') |
1442 | 1481 |
1443 # We want to squash all this branch's commits into one commit with the proper | 1482 # We want to squash all this branch's commits into one commit with the proper |
1444 # description. We do this by doing a "reset --soft" to the base branch (which | 1483 # description. We do this by doing a "reset --soft" to the base branch (which |
1445 # keeps the working copy the same), then dcommitting that. If origin/master | 1484 # keeps the working copy the same), then dcommitting that. If origin/master |
1446 # has a submodule merge commit, we'll also need to cherry-pick the squashed | 1485 # has a submodule merge commit, we'll also need to cherry-pick the squashed |
(...skipping 15 matching lines...) Expand all Loading... | |
1462 os.chdir(rel_base_path) | 1501 os.chdir(rel_base_path) |
1463 | 1502 |
1464 # Stuff our change into the merge branch. | 1503 # Stuff our change into the merge branch. |
1465 # We wrap in a try...finally block so if anything goes wrong, | 1504 # We wrap in a try...finally block so if anything goes wrong, |
1466 # we clean up the branches. | 1505 # we clean up the branches. |
1467 retcode = -1 | 1506 retcode = -1 |
1468 try: | 1507 try: |
1469 RunGit(['checkout', '-q', '-b', MERGE_BRANCH]) | 1508 RunGit(['checkout', '-q', '-b', MERGE_BRANCH]) |
1470 RunGit(['reset', '--soft', base_branch]) | 1509 RunGit(['reset', '--soft', base_branch]) |
1471 if options.contributor: | 1510 if options.contributor: |
1472 RunGit(['commit', '--author', options.contributor, '-m', description]) | 1511 RunGit( |
1512 [ | |
1513 'commit', '--author', options.contributor, | |
1514 '-m', commit_desc.description, | |
1515 ]) | |
1473 else: | 1516 else: |
1474 RunGit(['commit', '-m', description]) | 1517 RunGit(['commit', '-m', commit_desc.description]) |
1475 if base_has_submodules: | 1518 if base_has_submodules: |
1476 cherry_pick_commit = RunGit(['rev-list', 'HEAD^!']).rstrip() | 1519 cherry_pick_commit = RunGit(['rev-list', 'HEAD^!']).rstrip() |
1477 RunGit(['branch', CHERRY_PICK_BRANCH, svn_head]) | 1520 RunGit(['branch', CHERRY_PICK_BRANCH, svn_head]) |
1478 RunGit(['checkout', CHERRY_PICK_BRANCH]) | 1521 RunGit(['checkout', CHERRY_PICK_BRANCH]) |
1479 RunGit(['cherry-pick', cherry_pick_commit]) | 1522 RunGit(['cherry-pick', cherry_pick_commit]) |
1480 if cmd == 'push': | 1523 if cmd == 'push': |
1481 # push the merge branch. | 1524 # push the merge branch. |
1482 remote, branch = cl.FetchUpstreamTuple(cl.GetBranch()) | 1525 remote, branch = cl.FetchUpstreamTuple(cl.GetBranch()) |
1483 retcode, output = RunGitWithCode( | 1526 retcode, output = RunGitWithCode( |
1484 ['push', '--porcelain', remote, 'HEAD:%s' % branch]) | 1527 ['push', '--porcelain', remote, 'HEAD:%s' % branch]) |
(...skipping 18 matching lines...) Expand all Loading... | |
1503 for l in output.splitlines(False)) | 1546 for l in output.splitlines(False)) |
1504 match = filter(None, match) | 1547 match = filter(None, match) |
1505 if len(match) != 1: | 1548 if len(match) != 1: |
1506 DieWithError("Couldn't parse ouput to extract the committed hash:\n%s" % | 1549 DieWithError("Couldn't parse ouput to extract the committed hash:\n%s" % |
1507 output) | 1550 output) |
1508 revision = match[0].group(2) | 1551 revision = match[0].group(2) |
1509 else: | 1552 else: |
1510 return 1 | 1553 return 1 |
1511 viewvc_url = settings.GetViewVCUrl() | 1554 viewvc_url = settings.GetViewVCUrl() |
1512 if viewvc_url and revision: | 1555 if viewvc_url and revision: |
1513 cl.description += ('\n\nCommitted: ' + viewvc_url + revision) | 1556 change_desc.append_line('Committed: ' + viewvc_url + revision) |
1514 elif revision: | 1557 elif revision: |
1515 cl.description += ('\n\nCommitted: ' + revision) | 1558 change_desc.append_line('Committed: ' + revision) |
1516 print ('Closing issue ' | 1559 print ('Closing issue ' |
1517 '(you may be prompted for your codereview password)...') | 1560 '(you may be prompted for your codereview password)...') |
1518 cl.UpdateDescription(cl.description) | 1561 cl.UpdateDescription(change_desc.description) |
1519 cl.CloseIssue() | 1562 cl.CloseIssue() |
1520 props = cl.RpcServer().get_issue_properties(cl.GetIssue(), False) | 1563 props = cl.RpcServer().get_issue_properties(cl.GetIssue(), False) |
1521 patch_num = len(props['patchsets']) | 1564 patch_num = len(props['patchsets']) |
1522 comment = "Committed patchset #%d manually as r%s" % (patch_num, revision) | 1565 comment = "Committed patchset #%d manually as r%s" % (patch_num, revision) |
1523 comment += ' (presubmit successful).' if not options.bypass_hooks else '.' | 1566 comment += ' (presubmit successful).' if not options.bypass_hooks else '.' |
1524 cl.RpcServer().add_comment(cl.GetIssue(), comment) | 1567 cl.RpcServer().add_comment(cl.GetIssue(), comment) |
1525 cl.SetIssue(0) | 1568 cl.SetIssue(0) |
1526 | 1569 |
1527 if retcode == 0: | 1570 if retcode == 0: |
1528 hook = POSTUPSTREAM_HOOK_PATTERN % cmd | 1571 hook = POSTUPSTREAM_HOOK_PATTERN % cmd |
(...skipping 376 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1905 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) | 1948 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) |
1906 | 1949 |
1907 # Not a known command. Default to help. | 1950 # Not a known command. Default to help. |
1908 GenUsage(parser, 'help') | 1951 GenUsage(parser, 'help') |
1909 return CMDhelp(parser, argv) | 1952 return CMDhelp(parser, argv) |
1910 | 1953 |
1911 | 1954 |
1912 if __name__ == '__main__': | 1955 if __name__ == '__main__': |
1913 fix_encoding.fix_encoding() | 1956 fix_encoding.fix_encoding() |
1914 sys.exit(main(sys.argv[1:])) | 1957 sys.exit(main(sys.argv[1:])) |
OLD | NEW |