Chromium Code Reviews| 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 StringIO | 10 import StringIO |
| 11 import subprocess | 11 import subprocess |
| 12 import sys | 12 import sys |
| 13 import tempfile | 13 import tempfile |
| 14 import textwrap | 14 import textwrap |
| 15 import upload | |
| 16 import urlparse | 15 import urlparse |
| 17 import urllib2 | 16 import urllib2 |
| 18 | 17 |
| 19 try: | 18 try: |
| 20 import readline | 19 import readline # pylint: disable=W0611 |
| 21 except ImportError: | 20 except ImportError: |
| 22 pass | 21 pass |
| 23 | 22 |
| 23 # TODO(dpranke): don't use relative import. | |
| 24 import upload # pylint: disable=W0403 | |
| 24 try: | 25 try: |
| 25 # TODO(dpranke): We wrap this in a try block for a limited form of | 26 # TODO(dpranke): We wrap this in a try block for a limited form of |
| 26 # backwards-compatibility with older versions of git-cl that weren't | 27 # backwards-compatibility with older versions of git-cl that weren't |
| 27 # dependent on depot_tools. This version should still work outside of | 28 # dependent on depot_tools. This version should still work outside of |
| 28 # depot_tools as long as --bypass-hooks is used. We should remove this | 29 # depot_tools as long as --bypass-hooks is used. We should remove this |
| 29 # once this has baked for a while and things seem safe. | 30 # once this has baked for a while and things seem safe. |
| 30 depot_tools_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | 31 depot_tools_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
| 31 sys.path.append(depot_tools_path) | 32 sys.path.append(depot_tools_path) |
| 32 import breakpad | 33 import breakpad # pylint: disable=W0611 |
| 33 except ImportError: | 34 except ImportError: |
| 34 pass | 35 pass |
| 35 | 36 |
| 36 DEFAULT_SERVER = 'http://codereview.appspot.com' | 37 DEFAULT_SERVER = 'http://codereview.appspot.com' |
| 37 POSTUPSTREAM_HOOK_PATTERN = '.git/hooks/post-cl-%s' | 38 POSTUPSTREAM_HOOK_PATTERN = '.git/hooks/post-cl-%s' |
| 38 DESCRIPTION_BACKUP_FILE = '~/.git_cl_description_backup' | 39 DESCRIPTION_BACKUP_FILE = '~/.git_cl_description_backup' |
| 39 | 40 |
| 40 def DieWithError(message): | 41 def DieWithError(message): |
| 41 print >> sys.stderr, message | 42 print >> sys.stderr, message |
| 42 sys.exit(1) | 43 sys.exit(1) |
| (...skipping 557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 600 #PUSH_URL_CONFIG: url.ssh://gitrw.chromium.org.pushinsteadof | 601 #PUSH_URL_CONFIG: url.ssh://gitrw.chromium.org.pushinsteadof |
| 601 #ORIGIN_URL_CONFIG: http://src.chromium.org/git | 602 #ORIGIN_URL_CONFIG: http://src.chromium.org/git |
| 602 RunGit(['config', keyvals['PUSH_URL_CONFIG'], | 603 RunGit(['config', keyvals['PUSH_URL_CONFIG'], |
| 603 keyvals['ORIGIN_URL_CONFIG']]) | 604 keyvals['ORIGIN_URL_CONFIG']]) |
| 604 | 605 |
| 605 | 606 |
| 606 @usage('[repo root containing codereview.settings]') | 607 @usage('[repo root containing codereview.settings]') |
| 607 def CMDconfig(parser, args): | 608 def CMDconfig(parser, args): |
| 608 """edit configuration for this tree""" | 609 """edit configuration for this tree""" |
| 609 | 610 |
| 610 (options, args) = parser.parse_args(args) | 611 _, args = parser.parse_args(args) |
| 611 if len(args) == 0: | 612 if len(args) == 0: |
| 612 GetCodereviewSettingsInteractively() | 613 GetCodereviewSettingsInteractively() |
| 613 return 0 | 614 return 0 |
| 614 | 615 |
| 615 url = args[0] | 616 url = args[0] |
| 616 if not url.endswith('codereview.settings'): | 617 if not url.endswith('codereview.settings'): |
| 617 url = os.path.join(url, 'codereview.settings') | 618 url = os.path.join(url, 'codereview.settings') |
| 618 | 619 |
| 619 # Load code review settings and download hooks (if available). | 620 # Load code review settings and download hooks (if available). |
| 620 LoadCodereviewSettingsFromFile(urllib2.urlopen(url)) | 621 LoadCodereviewSettingsFromFile(urllib2.urlopen(url)) |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 666 print cl.GetDescription(pretty=True) | 667 print cl.GetDescription(pretty=True) |
| 667 return 0 | 668 return 0 |
| 668 | 669 |
| 669 | 670 |
| 670 @usage('[issue_number]') | 671 @usage('[issue_number]') |
| 671 def CMDissue(parser, args): | 672 def CMDissue(parser, args): |
| 672 """Set or display the current code review issue number. | 673 """Set or display the current code review issue number. |
| 673 | 674 |
| 674 Pass issue number 0 to clear the current issue. | 675 Pass issue number 0 to clear the current issue. |
| 675 """ | 676 """ |
| 676 (options, args) = parser.parse_args(args) | 677 _, args = parser.parse_args(args) |
| 677 | 678 |
| 678 cl = Changelist() | 679 cl = Changelist() |
| 679 if len(args) > 0: | 680 if len(args) > 0: |
| 680 try: | 681 try: |
| 681 issue = int(args[0]) | 682 issue = int(args[0]) |
| 682 except ValueError: | 683 except ValueError: |
| 683 DieWithError('Pass a number to set the issue or none to list it.\n' | 684 DieWithError('Pass a number to set the issue or none to list it.\n' |
| 684 'Maybe you want to run git cl status?') | 685 'Maybe you want to run git cl status?') |
| 685 cl.SetIssue(issue) | 686 cl.SetIssue(issue) |
| 686 print 'Issue number:', cl.GetIssue(), '(%s)' % cl.GetIssueURL() | 687 print 'Issue number:', cl.GetIssue(), '(%s)' % cl.GetIssueURL() |
| (...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1198 parser.add_option('-f', action='store_true', dest='force', | 1199 parser.add_option('-f', action='store_true', dest='force', |
| 1199 help='with -b, clobber any existing branch') | 1200 help='with -b, clobber any existing branch') |
| 1200 parser.add_option('--reject', action='store_true', dest='reject', | 1201 parser.add_option('--reject', action='store_true', dest='reject', |
| 1201 help='allow failed patches and spew .rej files') | 1202 help='allow failed patches and spew .rej files') |
| 1202 parser.add_option('-n', '--no-commit', action='store_true', dest='nocommit', | 1203 parser.add_option('-n', '--no-commit', action='store_true', dest='nocommit', |
| 1203 help="don't commit after patch applies") | 1204 help="don't commit after patch applies") |
| 1204 (options, args) = parser.parse_args(args) | 1205 (options, args) = parser.parse_args(args) |
| 1205 if len(args) != 1: | 1206 if len(args) != 1: |
| 1206 parser.print_help() | 1207 parser.print_help() |
| 1207 return 1 | 1208 return 1 |
| 1208 input = args[0] | 1209 issue_arg = args[0] |
| 1209 | 1210 |
| 1210 if re.match(r'\d+', input): | 1211 if re.match(r'\d+', input): |
| 1211 # Input is an issue id. Figure out the URL. | 1212 # Input is an issue id. Figure out the URL. |
| 1212 issue = input | 1213 issue = issue_arg |
| 1213 server = settings.GetDefaultServerUrl() | 1214 server = settings.GetDefaultServerUrl() |
| 1214 fetch = urllib2.urlopen('%s/%s' % (server, issue)).read() | 1215 fetch = urllib2.urlopen('%s/%s' % (server, issue)).read() |
| 1215 m = re.search(r'/download/issue[0-9]+_[0-9]+.diff', fetch) | 1216 m = re.search(r'/download/issue[0-9]+_[0-9]+.diff', fetch) |
| 1216 if not m: | 1217 if not m: |
| 1217 DieWithError('Must pass an issue ID or full URL for ' | 1218 DieWithError('Must pass an issue ID or full URL for ' |
| 1218 '\'Download raw patch set\'') | 1219 '\'Download raw patch set\'') |
| 1219 url = '%s%s' % (server, m.group(0).strip()) | 1220 url = '%s%s' % (server, m.group(0).strip()) |
| 1220 else: | 1221 else: |
| 1221 # Assume it's a URL to the patch. Default to http. | 1222 # Assume it's a URL to the patch. Default to http. |
| 1222 input = FixUrl(input) | 1223 issue_url = FixUrl(issue_arg) |
| 1223 match = re.match(r'.*?/issue(\d+)_\d+.diff', input) | 1224 match = re.match(r'.*?/issue(\d+)_\d+.diff', issue_url) |
| 1224 if match: | 1225 if match: |
| 1225 issue = match.group(1) | 1226 issue = match.group(1) |
| 1226 url = input | 1227 url = input |
| 1227 else: | 1228 else: |
| 1228 DieWithError('Must pass an issue ID or full URL for ' | 1229 DieWithError('Must pass an issue ID or full URL for ' |
| 1229 '\'Download raw patch set\'') | 1230 '\'Download raw patch set\'') |
| 1230 | 1231 |
| 1231 if options.newbranch: | 1232 if options.newbranch: |
| 1232 if options.force: | 1233 if options.force: |
| 1233 RunGit(['branch', '-D', options.newbranch], | 1234 RunGit(['branch', '-D', options.newbranch], |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1298 return 'unset' | 1299 return 'unset' |
| 1299 | 1300 |
| 1300 | 1301 |
| 1301 def GetTreeStatusReason(): | 1302 def GetTreeStatusReason(): |
| 1302 """Fetches the tree status from a json url and returns the message | 1303 """Fetches the tree status from a json url and returns the message |
| 1303 with the reason for the tree to be opened or closed.""" | 1304 with the reason for the tree to be opened or closed.""" |
| 1304 # Don't import it at file level since simplejson is not installed by default | 1305 # Don't import it at file level since simplejson is not installed by default |
| 1305 # on python 2.5 and it is only used for git-cl tree which isn't often used, | 1306 # on python 2.5 and it is only used for git-cl tree which isn't often used, |
| 1306 # forcing everyone to install simplejson isn't efficient. | 1307 # forcing everyone to install simplejson isn't efficient. |
| 1307 try: | 1308 try: |
| 1308 import simplejson as json | 1309 import simplejson as json # pylint: disable=F0401 |
| 1309 except ImportError: | 1310 except ImportError: |
| 1310 try: | 1311 try: |
| 1311 import json | 1312 import json |
| 1312 # Some versions of python2.5 have an incomplete json module. Check to make | 1313 except (ImportError): |
|
M-A Ruel
2011/03/17 02:09:09
except ImportError:
| |
| 1313 # sure loads exists. | |
| 1314 json.loads | |
| 1315 except (ImportError, AttributeError): | |
| 1316 print >> sys.stderr, 'Please install simplejson' | 1314 print >> sys.stderr, 'Please install simplejson' |
| 1317 sys.exit(1) | 1315 sys.exit(1) |
| 1318 | 1316 |
| 1319 url = settings.GetTreeStatusUrl() | 1317 url = settings.GetTreeStatusUrl() |
| 1320 json_url = urlparse.urljoin(url, '/current?format=json') | 1318 json_url = urlparse.urljoin(url, '/current?format=json') |
| 1321 connection = urllib2.urlopen(json_url) | 1319 connection = urllib2.urlopen(json_url) |
| 1322 status = json.loads(connection.read()) | 1320 status = json.loads(connection.read()) |
| 1323 connection.close() | 1321 connection.close() |
| 1324 return status['message'] | 1322 return status['message'] |
| 1325 | 1323 |
| 1326 | 1324 |
| 1327 def CMDtree(parser, args): | 1325 def CMDtree(parser, args): |
| 1328 """show the status of the tree""" | 1326 """show the status of the tree""" |
| 1329 (options, args) = parser.parse_args(args) | 1327 _, args = parser.parse_args(args) |
| 1330 status = GetTreeStatus() | 1328 status = GetTreeStatus() |
| 1331 if 'unset' == status: | 1329 if 'unset' == status: |
| 1332 print 'You must configure your tree status URL by running "git cl config".' | 1330 print 'You must configure your tree status URL by running "git cl config".' |
| 1333 return 2 | 1331 return 2 |
| 1334 | 1332 |
| 1335 print "The tree is %s" % status | 1333 print "The tree is %s" % status |
| 1336 print | 1334 print |
| 1337 print GetTreeStatusReason() | 1335 print GetTreeStatusReason() |
| 1338 if status != 'open': | 1336 if status != 'open': |
| 1339 return 1 | 1337 return 1 |
| 1340 return 0 | 1338 return 0 |
| 1341 | 1339 |
| 1342 | 1340 |
| 1343 def CMDupstream(parser, args): | 1341 def CMDupstream(parser, args): |
| 1344 """print the name of the upstream branch, if any""" | 1342 """print the name of the upstream branch, if any""" |
| 1345 (options, args) = parser.parse_args(args) | 1343 _, args = parser.parse_args(args) |
| 1346 cl = Changelist() | 1344 cl = Changelist() |
| 1347 print cl.GetUpstreamBranch() | 1345 print cl.GetUpstreamBranch() |
| 1348 return 0 | 1346 return 0 |
| 1349 | 1347 |
| 1350 | 1348 |
| 1351 def Command(name): | 1349 def Command(name): |
| 1352 return getattr(sys.modules[__name__], 'CMD' + name, None) | 1350 return getattr(sys.modules[__name__], 'CMD' + name, None) |
| 1353 | 1351 |
| 1354 | 1352 |
| 1355 def CMDhelp(parser, args): | 1353 def CMDhelp(parser, args): |
| 1356 """print list of commands or help for a specific command""" | 1354 """print list of commands or help for a specific command""" |
| 1357 (options, args) = parser.parse_args(args) | 1355 _, args = parser.parse_args(args) |
| 1358 if len(args) == 1: | 1356 if len(args) == 1: |
| 1359 return main(args + ['--help']) | 1357 return main(args + ['--help']) |
| 1360 parser.print_help() | 1358 parser.print_help() |
| 1361 return 0 | 1359 return 0 |
| 1362 | 1360 |
| 1363 | 1361 |
| 1364 def GenUsage(parser, command): | 1362 def GenUsage(parser, command): |
| 1365 """Modify an OptParse object with the function's documentation.""" | 1363 """Modify an OptParse object with the function's documentation.""" |
| 1366 obj = Command(command) | 1364 obj = Command(command) |
| 1367 more = getattr(obj, 'usage_more', '') | 1365 more = getattr(obj, 'usage_more', '') |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1408 ('AppEngine is misbehaving and returned HTTP %d, again. Keep faith ' | 1406 ('AppEngine is misbehaving and returned HTTP %d, again. Keep faith ' |
| 1409 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) | 1407 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) |
| 1410 | 1408 |
| 1411 # Not a known command. Default to help. | 1409 # Not a known command. Default to help. |
| 1412 GenUsage(parser, 'help') | 1410 GenUsage(parser, 'help') |
| 1413 return CMDhelp(parser, argv) | 1411 return CMDhelp(parser, argv) |
| 1414 | 1412 |
| 1415 | 1413 |
| 1416 if __name__ == '__main__': | 1414 if __name__ == '__main__': |
| 1417 sys.exit(main(sys.argv[1:])) | 1415 sys.exit(main(sys.argv[1:])) |
| OLD | NEW |