OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # git-cl -- a git-command for integrating reviews on Rietveld | 2 # git-cl -- a git-command for integrating reviews on Rietveld |
3 # Copyright (C) 2008 Evan Martin <martine@danga.com> | 3 # Copyright (C) 2008 Evan Martin <martine@danga.com> |
4 | 4 |
5 import errno | 5 import errno |
6 import logging | 6 import logging |
7 import optparse | 7 import optparse |
8 import os | 8 import os |
9 import re | 9 import re |
10 import subprocess | 10 import subprocess |
(...skipping 24 matching lines...) Expand all Loading... |
35 import presubmit_support | 35 import presubmit_support |
36 import scm | 36 import scm |
37 import watchlists | 37 import watchlists |
38 | 38 |
39 | 39 |
40 | 40 |
41 DEFAULT_SERVER = 'http://codereview.appspot.com' | 41 DEFAULT_SERVER = 'http://codereview.appspot.com' |
42 POSTUPSTREAM_HOOK_PATTERN = '.git/hooks/post-cl-%s' | 42 POSTUPSTREAM_HOOK_PATTERN = '.git/hooks/post-cl-%s' |
43 DESCRIPTION_BACKUP_FILE = '~/.git_cl_description_backup' | 43 DESCRIPTION_BACKUP_FILE = '~/.git_cl_description_backup' |
44 | 44 |
| 45 |
45 def DieWithError(message): | 46 def DieWithError(message): |
46 print >> sys.stderr, message | 47 print >> sys.stderr, message |
47 sys.exit(1) | 48 sys.exit(1) |
48 | 49 |
49 | 50 |
50 def Popen(cmd, **kwargs): | 51 def Popen(cmd, **kwargs): |
51 """Wrapper for subprocess.Popen() that logs and watch for cygwin issues""" | 52 """Wrapper for subprocess.Popen() that logs and watch for cygwin issues""" |
52 logging.info('Popen: ' + ' '.join(cmd)) | 53 logging.info('Popen: ' + ' '.join(cmd)) |
53 try: | 54 try: |
54 return subprocess.Popen(cmd, **kwargs) | 55 return subprocess.Popen(cmd, **kwargs) |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
90 return proc.returncode, output | 91 return proc.returncode, output |
91 | 92 |
92 | 93 |
93 def usage(more): | 94 def usage(more): |
94 def hook(fn): | 95 def hook(fn): |
95 fn.usage_more = more | 96 fn.usage_more = more |
96 return fn | 97 return fn |
97 return hook | 98 return hook |
98 | 99 |
99 | 100 |
| 101 def ask_for_data(prompt): |
| 102 try: |
| 103 return raw_input(prompt) |
| 104 except KeyboardInterrupt: |
| 105 # Hide the exception. |
| 106 sys.exit(1) |
| 107 |
| 108 |
100 def FixUrl(server): | 109 def FixUrl(server): |
101 """Fix a server url to defaults protocol to http:// if none is specified.""" | 110 """Fix a server url to defaults protocol to http:// if none is specified.""" |
102 if not server: | 111 if not server: |
103 return server | 112 return server |
104 if not re.match(r'[a-z]+\://.*', server): | 113 if not re.match(r'[a-z]+\://.*', server): |
105 return 'http://' + server | 114 return 'http://' + server |
106 return server | 115 return server |
107 | 116 |
108 | 117 |
109 def MatchSvnGlob(url, base_url, glob_spec, allow_wildcards): | 118 def MatchSvnGlob(url, base_url, glob_spec, allow_wildcards): |
(...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
518 def _RietveldServer(self): | 527 def _RietveldServer(self): |
519 """Returns the git setting that stores this change's rietveld server.""" | 528 """Returns the git setting that stores this change's rietveld server.""" |
520 return 'branch.%s.rietveldserver' % self.GetBranch() | 529 return 'branch.%s.rietveldserver' % self.GetBranch() |
521 | 530 |
522 | 531 |
523 def GetCodereviewSettingsInteractively(): | 532 def GetCodereviewSettingsInteractively(): |
524 """Prompt the user for settings.""" | 533 """Prompt the user for settings.""" |
525 server = settings.GetDefaultServerUrl(error_ok=True) | 534 server = settings.GetDefaultServerUrl(error_ok=True) |
526 prompt = 'Rietveld server (host[:port])' | 535 prompt = 'Rietveld server (host[:port])' |
527 prompt += ' [%s]' % (server or DEFAULT_SERVER) | 536 prompt += ' [%s]' % (server or DEFAULT_SERVER) |
528 newserver = raw_input(prompt + ': ') | 537 newserver = ask_for_data(prompt + ':') |
529 if not server and not newserver: | 538 if not server and not newserver: |
530 newserver = DEFAULT_SERVER | 539 newserver = DEFAULT_SERVER |
531 if newserver and newserver != server: | 540 if newserver and newserver != server: |
532 RunGit(['config', 'rietveld.server', newserver]) | 541 RunGit(['config', 'rietveld.server', newserver]) |
533 | 542 |
534 def SetProperty(initial, caption, name): | 543 def SetProperty(initial, caption, name): |
535 prompt = caption | 544 prompt = caption |
536 if initial: | 545 if initial: |
537 prompt += ' ("x" to clear) [%s]' % initial | 546 prompt += ' ("x" to clear) [%s]' % initial |
538 new_val = raw_input(prompt + ': ') | 547 new_val = ask_for_data(prompt + ':') |
539 if new_val == 'x': | 548 if new_val == 'x': |
540 RunGit(['config', '--unset-all', 'rietveld.' + name], error_ok=True) | 549 RunGit(['config', '--unset-all', 'rietveld.' + name], error_ok=True) |
541 elif new_val and new_val != initial: | 550 elif new_val and new_val != initial: |
542 RunGit(['config', 'rietveld.' + name, new_val]) | 551 RunGit(['config', 'rietveld.' + name, new_val]) |
543 | 552 |
544 SetProperty(settings.GetCCList(), 'CC list', 'cc') | 553 SetProperty(settings.GetCCList(), 'CC list', 'cc') |
545 SetProperty(settings.GetTreeStatusUrl(error_ok=True), 'Tree status URL', | 554 SetProperty(settings.GetTreeStatusUrl(error_ok=True), 'Tree status URL', |
546 'tree-status-url') | 555 'tree-status-url') |
547 SetProperty(settings.GetViewVCUrl(), 'ViewVC URL', 'viewvc-url') | 556 SetProperty(settings.GetViewVCUrl(), 'ViewVC URL', 'viewvc-url') |
548 | 557 |
(...skipping 556 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1105 if options.contributor: | 1114 if options.contributor: |
1106 if not re.match('^.*\s<\S+@\S+>$', options.contributor): | 1115 if not re.match('^.*\s<\S+@\S+>$', options.contributor): |
1107 print "Please provide contibutor as 'First Last <email@example.com>'" | 1116 print "Please provide contibutor as 'First Last <email@example.com>'" |
1108 return 1 | 1117 return 1 |
1109 description += "\nPatch from %s." % options.contributor | 1118 description += "\nPatch from %s." % options.contributor |
1110 print 'Description:', repr(description) | 1119 print 'Description:', repr(description) |
1111 | 1120 |
1112 branches = [base_branch, cl.GetBranchRef()] | 1121 branches = [base_branch, cl.GetBranchRef()] |
1113 if not options.force: | 1122 if not options.force: |
1114 subprocess.call(['git', 'diff', '--stat'] + branches) | 1123 subprocess.call(['git', 'diff', '--stat'] + branches) |
1115 raw_input("About to commit; enter to confirm.") | 1124 ask_for_data('About to commit; enter to confirm.') |
1116 | 1125 |
1117 # We want to squash all this branch's commits into one commit with the | 1126 # We want to squash all this branch's commits into one commit with the |
1118 # proper description. | 1127 # proper description. |
1119 # We do this by doing a "reset --soft" to the base branch (which keeps | 1128 # We do this by doing a "reset --soft" to the base branch (which keeps |
1120 # the working copy the same), then dcommitting that. | 1129 # the working copy the same), then dcommitting that. |
1121 MERGE_BRANCH = 'git-cl-commit' | 1130 MERGE_BRANCH = 'git-cl-commit' |
1122 # Delete the merge branch if it already exists. | 1131 # Delete the merge branch if it already exists. |
1123 if RunGitWithCode(['show-ref', '--quiet', '--verify', | 1132 if RunGitWithCode(['show-ref', '--quiet', '--verify', |
1124 'refs/heads/' + MERGE_BRANCH])[0] == 0: | 1133 'refs/heads/' + MERGE_BRANCH])[0] == 0: |
1125 RunGit(['branch', '-D', MERGE_BRANCH]) | 1134 RunGit(['branch', '-D', MERGE_BRANCH]) |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1190 """commit the current changelist via git-svn""" | 1199 """commit the current changelist via git-svn""" |
1191 if not settings.GetIsGitSvn(): | 1200 if not settings.GetIsGitSvn(): |
1192 message = """This doesn't appear to be an SVN repository. | 1201 message = """This doesn't appear to be an SVN repository. |
1193 If your project has a git mirror with an upstream SVN master, you probably need | 1202 If your project has a git mirror with an upstream SVN master, you probably need |
1194 to run 'git svn init', see your project's git mirror documentation. | 1203 to run 'git svn init', see your project's git mirror documentation. |
1195 If your project has a true writeable upstream repository, you probably want | 1204 If your project has a true writeable upstream repository, you probably want |
1196 to run 'git cl push' instead. | 1205 to run 'git cl push' instead. |
1197 Choose wisely, if you get this wrong, your commit might appear to succeed but | 1206 Choose wisely, if you get this wrong, your commit might appear to succeed but |
1198 will instead be silently ignored.""" | 1207 will instead be silently ignored.""" |
1199 print(message) | 1208 print(message) |
1200 raw_input('[Press enter to dcommit or ctrl-C to quit]') | 1209 ask_for_data('[Press enter to dcommit or ctrl-C to quit]') |
1201 return SendUpstream(parser, args, 'dcommit') | 1210 return SendUpstream(parser, args, 'dcommit') |
1202 | 1211 |
1203 | 1212 |
1204 @usage('[upstream branch to apply against]') | 1213 @usage('[upstream branch to apply against]') |
1205 def CMDpush(parser, args): | 1214 def CMDpush(parser, args): |
1206 """commit the current changelist via git""" | 1215 """commit the current changelist via git""" |
1207 if settings.GetIsGitSvn(): | 1216 if settings.GetIsGitSvn(): |
1208 print('This appears to be an SVN repository.') | 1217 print('This appears to be an SVN repository.') |
1209 print('Are you sure you didn\'t mean \'git cl dcommit\'?') | 1218 print('Are you sure you didn\'t mean \'git cl dcommit\'?') |
1210 raw_input('[Press enter to push or ctrl-C to quit]') | 1219 ask_for_data('[Press enter to push or ctrl-C to quit]') |
1211 return SendUpstream(parser, args, 'push') | 1220 return SendUpstream(parser, args, 'push') |
1212 | 1221 |
1213 | 1222 |
1214 @usage('<patch url or issue id>') | 1223 @usage('<patch url or issue id>') |
1215 def CMDpatch(parser, args): | 1224 def CMDpatch(parser, args): |
1216 """patch in a code review""" | 1225 """patch in a code review""" |
1217 parser.add_option('-b', dest='newbranch', | 1226 parser.add_option('-b', dest='newbranch', |
1218 help='create a new branch off trunk for the patch') | 1227 help='create a new branch off trunk for the patch') |
1219 parser.add_option('-f', action='store_true', dest='force', | 1228 parser.add_option('-f', action='store_true', dest='force', |
1220 help='with -b, clobber any existing branch') | 1229 help='with -b, clobber any existing branch') |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1406 ('AppEngine is misbehaving and returned HTTP %d, again. Keep faith ' | 1415 ('AppEngine is misbehaving and returned HTTP %d, again. Keep faith ' |
1407 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) | 1416 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) |
1408 | 1417 |
1409 # Not a known command. Default to help. | 1418 # Not a known command. Default to help. |
1410 GenUsage(parser, 'help') | 1419 GenUsage(parser, 'help') |
1411 return CMDhelp(parser, argv) | 1420 return CMDhelp(parser, argv) |
1412 | 1421 |
1413 | 1422 |
1414 if __name__ == '__main__': | 1423 if __name__ == '__main__': |
1415 sys.exit(main(sys.argv[1:])) | 1424 sys.exit(main(sys.argv[1:])) |
OLD | NEW |