| 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 |