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

Side by Side Diff: git_cl.py

Issue 2066003002: git_cl: convert to print_function (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: fix long line Created 4 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 | no next file » | 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/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 and Gerrit.""" 8 """A git-command for integrating reviews on Rietveld and Gerrit."""
9 9
10 from __future__ import print_function
11
10 from distutils.version import LooseVersion 12 from distutils.version import LooseVersion
11 from multiprocessing.pool import ThreadPool 13 from multiprocessing.pool import ThreadPool
12 import base64 14 import base64
13 import collections 15 import collections
14 import glob 16 import glob
15 import httplib 17 import httplib
16 import json 18 import json
17 import logging 19 import logging
18 import multiprocessing 20 import multiprocessing
19 import optparse 21 import optparse
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 DEFAULT_LINT_IGNORE_REGEX = r"$^" 78 DEFAULT_LINT_IGNORE_REGEX = r"$^"
77 79
78 # Shortcut since it quickly becomes redundant. 80 # Shortcut since it quickly becomes redundant.
79 Fore = colorama.Fore 81 Fore = colorama.Fore
80 82
81 # Initialized in main() 83 # Initialized in main()
82 settings = None 84 settings = None
83 85
84 86
85 def DieWithError(message): 87 def DieWithError(message):
86 print >> sys.stderr, message 88 print(message, file=sys.stderr)
87 sys.exit(1) 89 sys.exit(1)
88 90
89 91
90 def GetNoGitPagerEnv(): 92 def GetNoGitPagerEnv():
91 env = os.environ.copy() 93 env = os.environ.copy()
92 # 'cat' is a magical git string that disables pagers on all platforms. 94 # 'cat' is a magical git string that disables pagers on all platforms.
93 env['GIT_PAGER'] = 'cat' 95 env['GIT_PAGER'] = 'cat'
94 return env 96 return env
95 97
96 98
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
359 _buildbucket_retry( 361 _buildbucket_retry(
360 'triggering tryjobs', 362 'triggering tryjobs',
361 http, 363 http,
362 buildbucket_put_url, 364 buildbucket_put_url,
363 'PUT', 365 'PUT',
364 body=json.dumps(batch_req_body), 366 body=json.dumps(batch_req_body),
365 headers={'Content-Type': 'application/json'} 367 headers={'Content-Type': 'application/json'}
366 ) 368 )
367 print_text.append('To see results here, run: git cl try-results') 369 print_text.append('To see results here, run: git cl try-results')
368 print_text.append('To see results in browser, run: git cl web') 370 print_text.append('To see results in browser, run: git cl web')
369 print '\n'.join(print_text) 371 print('\n'.join(print_text))
370 372
371 373
372 def fetch_try_jobs(auth_config, changelist, options): 374 def fetch_try_jobs(auth_config, changelist, options):
373 """Fetches tryjobs from buildbucket. 375 """Fetches tryjobs from buildbucket.
374 376
375 Returns a map from build id to build info as json dictionary. 377 Returns a map from build id to build info as json dictionary.
376 """ 378 """
377 rietveld_url = settings.GetDefaultServerUrl() 379 rietveld_url = settings.GetDefaultServerUrl()
378 rietveld_host = urlparse.urlparse(rietveld_url).hostname 380 rietveld_host = urlparse.urlparse(rietveld_url).hostname
379 authenticator = auth.get_authenticator_for_host(rietveld_host, auth_config) 381 authenticator = auth.get_authenticator_for_host(rietveld_host, auth_config)
380 if authenticator.has_cached_credentials(): 382 if authenticator.has_cached_credentials():
381 http = authenticator.authorize(httplib2.Http()) 383 http = authenticator.authorize(httplib2.Http())
382 else: 384 else:
383 print ('Warning: Some results might be missing because %s' % 385 print('Warning: Some results might be missing because %s' %
384 # Get the message on how to login. 386 # Get the message on how to login.
385 auth.LoginRequiredError(rietveld_host).message) 387 (auth.LoginRequiredError(rietveld_host).message,))
386 http = httplib2.Http() 388 http = httplib2.Http()
387 389
388 http.force_exception_to_status_code = True 390 http.force_exception_to_status_code = True
389 391
390 buildset = 'patch/rietveld/{hostname}/{issue}/{patch}'.format( 392 buildset = 'patch/rietveld/{hostname}/{issue}/{patch}'.format(
391 hostname=rietveld_host, 393 hostname=rietveld_host,
392 issue=changelist.GetIssue(), 394 issue=changelist.GetIssue(),
393 patch=options.patchset) 395 patch=options.patchset)
394 params = {'tag': 'buildset:%s' % buildset} 396 params = {'tag': 'buildset:%s' % buildset}
395 397
396 builds = {} 398 builds = {}
397 while True: 399 while True:
398 url = 'https://{hostname}/_ah/api/buildbucket/v1/search?{params}'.format( 400 url = 'https://{hostname}/_ah/api/buildbucket/v1/search?{params}'.format(
399 hostname=options.buildbucket_host, 401 hostname=options.buildbucket_host,
400 params=urllib.urlencode(params)) 402 params=urllib.urlencode(params))
401 content = _buildbucket_retry('fetching tryjobs', http, url, 'GET') 403 content = _buildbucket_retry('fetching tryjobs', http, url, 'GET')
402 for build in content.get('builds', []): 404 for build in content.get('builds', []):
403 builds[build['id']] = build 405 builds[build['id']] = build
404 if 'next_cursor' in content: 406 if 'next_cursor' in content:
405 params['start_cursor'] = content['next_cursor'] 407 params['start_cursor'] = content['next_cursor']
406 else: 408 else:
407 break 409 break
408 return builds 410 return builds
409 411
410 412
411 def print_tryjobs(options, builds): 413 def print_tryjobs(options, builds):
412 """Prints nicely result of fetch_try_jobs.""" 414 """Prints nicely result of fetch_try_jobs."""
413 if not builds: 415 if not builds:
414 print 'No tryjobs scheduled' 416 print('No tryjobs scheduled')
415 return 417 return
416 418
417 # Make a copy, because we'll be modifying builds dictionary. 419 # Make a copy, because we'll be modifying builds dictionary.
418 builds = builds.copy() 420 builds = builds.copy()
419 builder_names_cache = {} 421 builder_names_cache = {}
420 422
421 def get_builder(b): 423 def get_builder(b):
422 try: 424 try:
423 return builder_names_cache[b['id']] 425 return builder_names_cache[b['id']]
424 except KeyError: 426 except KeyError:
425 try: 427 try:
426 parameters = json.loads(b['parameters_json']) 428 parameters = json.loads(b['parameters_json'])
427 name = parameters['builder_name'] 429 name = parameters['builder_name']
428 except (ValueError, KeyError) as error: 430 except (ValueError, KeyError) as error:
429 print 'WARNING: failed to get builder name for build %s: %s' % ( 431 print('WARNING: failed to get builder name for build %s: %s' % (
430 b['id'], error) 432 b['id'], error))
431 name = None 433 name = None
432 builder_names_cache[b['id']] = name 434 builder_names_cache[b['id']] = name
433 return name 435 return name
434 436
435 def get_bucket(b): 437 def get_bucket(b):
436 bucket = b['bucket'] 438 bucket = b['bucket']
437 if bucket.startswith('master.'): 439 if bucket.startswith('master.'):
438 return bucket[len('master.'):] 440 return bucket[len('master.'):]
439 return bucket 441 return bucket
440 442
(...skipping 19 matching lines...) Expand all
460 colorize = str 462 colorize = str
461 else: 463 else:
462 colorize = lambda x: '%s%s%s' % (color, x, Fore.RESET) 464 colorize = lambda x: '%s%s%s' % (color, x, Fore.RESET)
463 465
464 result = [] 466 result = []
465 for b in builds.values(): 467 for b in builds.values():
466 if all(b.get(k) == v for k, v in kwargs.iteritems()): 468 if all(b.get(k) == v for k, v in kwargs.iteritems()):
467 builds.pop(b['id']) 469 builds.pop(b['id'])
468 result.append(b) 470 result.append(b)
469 if result: 471 if result:
470 print colorize(title) 472 print(colorize(title))
471 for b in sorted(result, key=sort_key): 473 for b in sorted(result, key=sort_key):
472 print ' ', colorize('\t'.join(map(str, f(b)))) 474 print(' ', colorize('\t'.join(map(str, f(b)))))
473 475
474 total = len(builds) 476 total = len(builds)
475 pop(status='COMPLETED', result='SUCCESS', 477 pop(status='COMPLETED', result='SUCCESS',
476 title='Successes:', color=Fore.GREEN, 478 title='Successes:', color=Fore.GREEN,
477 f=lambda b: (get_name(b), b.get('url'))) 479 f=lambda b: (get_name(b), b.get('url')))
478 pop(status='COMPLETED', result='FAILURE', failure_reason='INFRA_FAILURE', 480 pop(status='COMPLETED', result='FAILURE', failure_reason='INFRA_FAILURE',
479 title='Infra Failures:', color=Fore.MAGENTA, 481 title='Infra Failures:', color=Fore.MAGENTA,
480 f=lambda b: (get_name(b), b.get('url'))) 482 f=lambda b: (get_name(b), b.get('url')))
481 pop(status='COMPLETED', result='FAILURE', failure_reason='BUILD_FAILURE', 483 pop(status='COMPLETED', result='FAILURE', failure_reason='BUILD_FAILURE',
482 title='Failures:', color=Fore.RED, 484 title='Failures:', color=Fore.RED,
(...skipping 14 matching lines...) Expand all
497 pop(status='STARTED', 499 pop(status='STARTED',
498 title='Started:', color=Fore.YELLOW, 500 title='Started:', color=Fore.YELLOW,
499 f=lambda b: (get_name(b), b.get('url'))) 501 f=lambda b: (get_name(b), b.get('url')))
500 pop(status='SCHEDULED', 502 pop(status='SCHEDULED',
501 title='Scheduled:', 503 title='Scheduled:',
502 f=lambda b: (get_name(b), 'id=%s' % b['id'])) 504 f=lambda b: (get_name(b), 'id=%s' % b['id']))
503 # The last section is just in case buildbucket API changes OR there is a bug. 505 # The last section is just in case buildbucket API changes OR there is a bug.
504 pop(title='Other:', 506 pop(title='Other:',
505 f=lambda b: (get_name(b), 'id=%s' % b['id'])) 507 f=lambda b: (get_name(b), 'id=%s' % b['id']))
506 assert len(builds) == 0 508 assert len(builds) == 0
507 print 'Total: %d tryjobs' % total 509 print('Total: %d tryjobs' % total)
508 510
509 511
510 def MatchSvnGlob(url, base_url, glob_spec, allow_wildcards): 512 def MatchSvnGlob(url, base_url, glob_spec, allow_wildcards):
511 """Return the corresponding git ref if |base_url| together with |glob_spec| 513 """Return the corresponding git ref if |base_url| together with |glob_spec|
512 matches the full |url|. 514 matches the full |url|.
513 515
514 If |allow_wildcards| is true, |glob_spec| can contain wildcards (see below). 516 If |allow_wildcards| is true, |glob_spec| can contain wildcards (see below).
515 """ 517 """
516 fetch_suburl, as_ref = glob_spec.split(':') 518 fetch_suburl, as_ref = glob_spec.split(':')
517 if allow_wildcards: 519 if allow_wildcards:
(...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after
1114 self._remote = (remote, branch.replace('refs/', 'refs/remotes/')) 1116 self._remote = (remote, branch.replace('refs/', 'refs/remotes/'))
1115 else: 1117 else:
1116 self._remote = (remote, 'refs/remotes/%s/%s' % (remote, branch)) 1118 self._remote = (remote, 'refs/remotes/%s/%s' % (remote, branch))
1117 return self._remote 1119 return self._remote
1118 1120
1119 def GitSanityChecks(self, upstream_git_obj): 1121 def GitSanityChecks(self, upstream_git_obj):
1120 """Checks git repo status and ensures diff is from local commits.""" 1122 """Checks git repo status and ensures diff is from local commits."""
1121 1123
1122 if upstream_git_obj is None: 1124 if upstream_git_obj is None:
1123 if self.GetBranch() is None: 1125 if self.GetBranch() is None:
1124 print >> sys.stderr, ( 1126 print('ERROR: unable to determine current branch (detached HEAD?)',
1125 'ERROR: unable to determine current branch (detached HEAD?)') 1127 file=sys.stderr)
1126 else: 1128 else:
1127 print >> sys.stderr, ( 1129 print('ERROR: no upstream branch', file=sys.stderr)
1128 'ERROR: no upstream branch')
1129 return False 1130 return False
1130 1131
1131 # Verify the commit we're diffing against is in our current branch. 1132 # Verify the commit we're diffing against is in our current branch.
1132 upstream_sha = RunGit(['rev-parse', '--verify', upstream_git_obj]).strip() 1133 upstream_sha = RunGit(['rev-parse', '--verify', upstream_git_obj]).strip()
1133 common_ancestor = RunGit(['merge-base', upstream_sha, 'HEAD']).strip() 1134 common_ancestor = RunGit(['merge-base', upstream_sha, 'HEAD']).strip()
1134 if upstream_sha != common_ancestor: 1135 if upstream_sha != common_ancestor:
1135 print >> sys.stderr, ( 1136 print('ERROR: %s is not in the current branch. You may need to rebase '
1136 'ERROR: %s is not in the current branch. You may need to rebase ' 1137 'your tracking branch' % upstream_sha, file=sys.stderr)
1137 'your tracking branch' % upstream_sha)
1138 return False 1138 return False
1139 1139
1140 # List the commits inside the diff, and verify they are all local. 1140 # List the commits inside the diff, and verify they are all local.
1141 commits_in_diff = RunGit( 1141 commits_in_diff = RunGit(
1142 ['rev-list', '^%s' % upstream_sha, 'HEAD']).splitlines() 1142 ['rev-list', '^%s' % upstream_sha, 'HEAD']).splitlines()
1143 code, remote_branch = RunGitWithCode(['config', 'gitcl.remotebranch']) 1143 code, remote_branch = RunGitWithCode(['config', 'gitcl.remotebranch'])
1144 remote_branch = remote_branch.strip() 1144 remote_branch = remote_branch.strip()
1145 if code != 0: 1145 if code != 0:
1146 _, remote_branch = self.GetRemoteBranch() 1146 _, remote_branch = self.GetRemoteBranch()
1147 1147
1148 commits_in_remote = RunGit( 1148 commits_in_remote = RunGit(
1149 ['rev-list', '^%s' % upstream_sha, remote_branch]).splitlines() 1149 ['rev-list', '^%s' % upstream_sha, remote_branch]).splitlines()
1150 1150
1151 common_commits = set(commits_in_diff) & set(commits_in_remote) 1151 common_commits = set(commits_in_diff) & set(commits_in_remote)
1152 if common_commits: 1152 if common_commits:
1153 print >> sys.stderr, ( 1153 print('ERROR: Your diff contains %d commits already in %s.\n'
1154 'ERROR: Your diff contains %d commits already in %s.\n' 1154 'Run "git log --oneline %s..HEAD" to get a list of commits in '
1155 'Run "git log --oneline %s..HEAD" to get a list of commits in ' 1155 'the diff. If you are using a custom git flow, you can override'
1156 'the diff. If you are using a custom git flow, you can override' 1156 ' the reference used for this check with "git config '
1157 ' the reference used for this check with "git config ' 1157 'gitcl.remotebranch <git-ref>".' % (
1158 'gitcl.remotebranch <git-ref>".' % ( 1158 len(common_commits), remote_branch, upstream_git_obj),
1159 len(common_commits), remote_branch, upstream_git_obj)) 1159 file=sys.stderr)
1160 return False 1160 return False
1161 return True 1161 return True
1162 1162
1163 def GetGitBaseUrlFromConfig(self): 1163 def GetGitBaseUrlFromConfig(self):
1164 """Return the configured base URL from branch.<branchname>.baseurl. 1164 """Return the configured base URL from branch.<branchname>.baseurl.
1165 1165
1166 Returns None if it is not set. 1166 Returns None if it is not set.
1167 """ 1167 """
1168 return RunGit(['config', 'branch.%s.base-url' % self.GetBranch()], 1168 return RunGit(['config', 'branch.%s.base-url' % self.GetBranch()],
1169 error_ok=True).strip() 1169 error_ok=True).strip()
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
1382 if not hook_results.should_continue(): 1382 if not hook_results.should_continue():
1383 return 1 1383 return 1
1384 if not options.reviewers and hook_results.reviewers: 1384 if not options.reviewers and hook_results.reviewers:
1385 options.reviewers = hook_results.reviewers.split(',') 1385 options.reviewers = hook_results.reviewers.split(',')
1386 1386
1387 if self.GetIssue(): 1387 if self.GetIssue():
1388 latest_patchset = self.GetMostRecentPatchset() 1388 latest_patchset = self.GetMostRecentPatchset()
1389 local_patchset = self.GetPatchset() 1389 local_patchset = self.GetPatchset()
1390 if (latest_patchset and local_patchset and 1390 if (latest_patchset and local_patchset and
1391 local_patchset != latest_patchset): 1391 local_patchset != latest_patchset):
1392 print ('The last upload made from this repository was patchset #%d but ' 1392 print('The last upload made from this repository was patchset #%d but '
1393 'the most recent patchset on the server is #%d.' 1393 'the most recent patchset on the server is #%d.'
1394 % (local_patchset, latest_patchset)) 1394 % (local_patchset, latest_patchset))
1395 print ('Uploading will still work, but if you\'ve uploaded to this ' 1395 print('Uploading will still work, but if you\'ve uploaded to this '
1396 'issue from another machine or branch the patch you\'re ' 1396 'issue from another machine or branch the patch you\'re '
1397 'uploading now might not include those changes.') 1397 'uploading now might not include those changes.')
1398 ask_for_data('About to upload; enter to confirm.') 1398 ask_for_data('About to upload; enter to confirm.')
1399 1399
1400 print_stats(options.similarity, options.find_copies, git_diff_args) 1400 print_stats(options.similarity, options.find_copies, git_diff_args)
1401 ret = self.CMDUploadChange(options, git_diff_args, change) 1401 ret = self.CMDUploadChange(options, git_diff_args, change)
1402 if not ret: 1402 if not ret:
1403 git_set_branch_value('last-upload-hash', 1403 git_set_branch_value('last-upload-hash',
1404 RunGit(['rev-parse', 'HEAD']).strip()) 1404 RunGit(['rev-parse', 'HEAD']).strip())
1405 # Run post upload hooks, if specified. 1405 # Run post upload hooks, if specified.
1406 if settings.GetRunPostUploadHook(): 1406 if settings.GetRunPostUploadHook():
1407 presubmit_support.DoPostUploadExecuter( 1407 presubmit_support.DoPostUploadExecuter(
1408 change, 1408 change,
1409 self, 1409 self,
1410 settings.GetRoot(), 1410 settings.GetRoot(),
1411 options.verbose, 1411 options.verbose,
1412 sys.stdout) 1412 sys.stdout)
1413 1413
1414 # Upload all dependencies if specified. 1414 # Upload all dependencies if specified.
1415 if options.dependencies: 1415 if options.dependencies:
1416 print 1416 print()
1417 print '--dependencies has been specified.' 1417 print('--dependencies has been specified.')
1418 print 'All dependent local branches will be re-uploaded.' 1418 print('All dependent local branches will be re-uploaded.')
1419 print 1419 print()
1420 # Remove the dependencies flag from args so that we do not end up in a 1420 # Remove the dependencies flag from args so that we do not end up in a
1421 # loop. 1421 # loop.
1422 orig_args.remove('--dependencies') 1422 orig_args.remove('--dependencies')
1423 ret = upload_branch_deps(self, orig_args) 1423 ret = upload_branch_deps(self, orig_args)
1424 return ret 1424 return ret
1425 1425
1426 def SetCQState(self, new_state): 1426 def SetCQState(self, new_state):
1427 """Update the CQ state for latest patchset. 1427 """Update the CQ state for latest patchset.
1428 1428
1429 Issue must have been already uploaded and known. 1429 Issue must have been already uploaded and known.
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
1618 'error. It is likely that you deleted this ' 1618 'error. It is likely that you deleted this '
1619 'issue on the server. If this is the\n' 1619 'issue on the server. If this is the\n'
1620 'case, please run\n\n' 1620 'case, please run\n\n'
1621 ' git cl issue 0\n\n' 1621 ' git cl issue 0\n\n'
1622 'to clear the association with the deleted issue. Then run ' 1622 'to clear the association with the deleted issue. Then run '
1623 'this command again.') % issue) 1623 'this command again.') % issue)
1624 else: 1624 else:
1625 DieWithError( 1625 DieWithError(
1626 '\nFailed to fetch issue description. HTTP error %d' % e.code) 1626 '\nFailed to fetch issue description. HTTP error %d' % e.code)
1627 except urllib2.URLError as e: 1627 except urllib2.URLError as e:
1628 print >> sys.stderr, ( 1628 print('Warning: Failed to retrieve CL description due to network '
1629 'Warning: Failed to retrieve CL description due to network ' 1629 'failure.', file=sys.stderr)
1630 'failure.')
1631 return '' 1630 return ''
1632 1631
1633 def GetMostRecentPatchset(self): 1632 def GetMostRecentPatchset(self):
1634 return self.GetIssueProperties()['patchsets'][-1] 1633 return self.GetIssueProperties()['patchsets'][-1]
1635 1634
1636 def GetPatchSetDiff(self, issue, patchset): 1635 def GetPatchSetDiff(self, issue, patchset):
1637 return self.RpcServer().get( 1636 return self.RpcServer().get(
1638 '/download/issue%s_%s.diff' % (issue, patchset)) 1637 '/download/issue%s_%s.diff' % (issue, patchset))
1639 1638
1640 def GetIssueProperties(self): 1639 def GetIssueProperties(self):
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
1812 if directory: 1811 if directory:
1813 cmd.extend(('--directory', directory)) 1812 cmd.extend(('--directory', directory))
1814 if reject: 1813 if reject:
1815 cmd.append('--reject') 1814 cmd.append('--reject')
1816 elif IsGitVersionAtLeast('1.7.12'): 1815 elif IsGitVersionAtLeast('1.7.12'):
1817 cmd.append('--3way') 1816 cmd.append('--3way')
1818 try: 1817 try:
1819 subprocess2.check_call(cmd, env=GetNoGitPagerEnv(), 1818 subprocess2.check_call(cmd, env=GetNoGitPagerEnv(),
1820 stdin=patch_data, stdout=subprocess2.VOID) 1819 stdin=patch_data, stdout=subprocess2.VOID)
1821 except subprocess2.CalledProcessError: 1820 except subprocess2.CalledProcessError:
1822 print 'Failed to apply the patch' 1821 print('Failed to apply the patch')
1823 return 1 1822 return 1
1824 1823
1825 # If we had an issue, commit the current state and register the issue. 1824 # If we had an issue, commit the current state and register the issue.
1826 if not nocommit: 1825 if not nocommit:
1827 RunGit(['commit', '-m', (self.GetDescription() + '\n\n' + 1826 RunGit(['commit', '-m', (self.GetDescription() + '\n\n' +
1828 'patch from issue %(i)s at patchset ' 1827 'patch from issue %(i)s at patchset '
1829 '%(p)s (http://crrev.com/%(i)s#ps%(p)s)' 1828 '%(p)s (http://crrev.com/%(i)s#ps%(p)s)'
1830 % {'i': self.GetIssue(), 'p': patchset})]) 1829 % {'i': self.GetIssue(), 'p': patchset})])
1831 self.SetIssue(self.GetIssue()) 1830 self.SetIssue(self.GetIssue())
1832 self.SetPatchset(patchset) 1831 self.SetPatchset(patchset)
1833 print "Committed patch locally." 1832 print('Committed patch locally.')
1834 else: 1833 else:
1835 print "Patch applied to index." 1834 print('Patch applied to index.')
1836 return 0 1835 return 0
1837 1836
1838 @staticmethod 1837 @staticmethod
1839 def ParseIssueURL(parsed_url): 1838 def ParseIssueURL(parsed_url):
1840 if not parsed_url.scheme or not parsed_url.scheme.startswith('http'): 1839 if not parsed_url.scheme or not parsed_url.scheme.startswith('http'):
1841 return None 1840 return None
1842 # Typical url: https://domain/<issue_number>[/[other]] 1841 # Typical url: https://domain/<issue_number>[/[other]]
1843 match = re.match('/(\d+)(/.*)?$', parsed_url.path) 1842 match = re.match('/(\d+)(/.*)?$', parsed_url.path)
1844 if match: 1843 if match:
1845 return _RietveldParsedIssueNumberArgument( 1844 return _RietveldParsedIssueNumberArgument(
(...skipping 21 matching lines...) Expand all
1867 1866
1868 if options.email is not None: 1867 if options.email is not None:
1869 upload_args.extend(['--email', options.email]) 1868 upload_args.extend(['--email', options.email])
1870 1869
1871 if self.GetIssue(): 1870 if self.GetIssue():
1872 if options.title: 1871 if options.title:
1873 upload_args.extend(['--title', options.title]) 1872 upload_args.extend(['--title', options.title])
1874 if options.message: 1873 if options.message:
1875 upload_args.extend(['--message', options.message]) 1874 upload_args.extend(['--message', options.message])
1876 upload_args.extend(['--issue', str(self.GetIssue())]) 1875 upload_args.extend(['--issue', str(self.GetIssue())])
1877 print ('This branch is associated with issue %s. ' 1876 print('This branch is associated with issue %s. '
1878 'Adding patch to that issue.' % self.GetIssue()) 1877 'Adding patch to that issue.' % self.GetIssue())
1879 else: 1878 else:
1880 if options.title: 1879 if options.title:
1881 upload_args.extend(['--title', options.title]) 1880 upload_args.extend(['--title', options.title])
1882 message = (options.title or options.message or 1881 message = (options.title or options.message or
1883 CreateDescriptionFromLog(args)) 1882 CreateDescriptionFromLog(args))
1884 change_desc = ChangeDescription(message) 1883 change_desc = ChangeDescription(message)
1885 if options.reviewers or options.tbr_owners: 1884 if options.reviewers or options.tbr_owners:
1886 change_desc.update_reviewers(options.reviewers, 1885 change_desc.update_reviewers(options.reviewers,
1887 options.tbr_owners, 1886 options.tbr_owners,
1888 change) 1887 change)
1889 if not options.force: 1888 if not options.force:
1890 change_desc.prompt() 1889 change_desc.prompt()
1891 1890
1892 if not change_desc.description: 1891 if not change_desc.description:
1893 print "Description is empty; aborting." 1892 print('Description is empty; aborting.')
1894 return 1 1893 return 1
1895 1894
1896 upload_args.extend(['--message', change_desc.description]) 1895 upload_args.extend(['--message', change_desc.description])
1897 if change_desc.get_reviewers(): 1896 if change_desc.get_reviewers():
1898 upload_args.append('--reviewers=%s' % ','.join( 1897 upload_args.append('--reviewers=%s' % ','.join(
1899 change_desc.get_reviewers())) 1898 change_desc.get_reviewers()))
1900 if options.send_mail: 1899 if options.send_mail:
1901 if not change_desc.get_reviewers(): 1900 if not change_desc.get_reviewers():
1902 DieWithError("Must specify reviewers to send email.") 1901 DieWithError("Must specify reviewers to send email.")
1903 upload_args.append('--send_mail') 1902 upload_args.append('--send_mail')
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1941 if target_ref: 1940 if target_ref:
1942 upload_args.extend(['--target_ref', target_ref]) 1941 upload_args.extend(['--target_ref', target_ref])
1943 1942
1944 # Look for dependent patchsets. See crbug.com/480453 for more details. 1943 # Look for dependent patchsets. See crbug.com/480453 for more details.
1945 remote, upstream_branch = self.FetchUpstreamTuple(self.GetBranch()) 1944 remote, upstream_branch = self.FetchUpstreamTuple(self.GetBranch())
1946 upstream_branch = ShortBranchName(upstream_branch) 1945 upstream_branch = ShortBranchName(upstream_branch)
1947 if remote is '.': 1946 if remote is '.':
1948 # A local branch is being tracked. 1947 # A local branch is being tracked.
1949 local_branch = upstream_branch 1948 local_branch = upstream_branch
1950 if settings.GetIsSkipDependencyUpload(local_branch): 1949 if settings.GetIsSkipDependencyUpload(local_branch):
1951 print 1950 print()
1952 print ('Skipping dependency patchset upload because git config ' 1951 print('Skipping dependency patchset upload because git config '
1953 'branch.%s.skip-deps-uploads is set to True.' % local_branch) 1952 'branch.%s.skip-deps-uploads is set to True.' % local_branch)
1954 print 1953 print()
1955 else: 1954 else:
1956 auth_config = auth.extract_auth_config_from_options(options) 1955 auth_config = auth.extract_auth_config_from_options(options)
1957 branch_cl = Changelist(branchref='refs/heads/'+local_branch, 1956 branch_cl = Changelist(branchref='refs/heads/'+local_branch,
1958 auth_config=auth_config) 1957 auth_config=auth_config)
1959 branch_cl_issue_url = branch_cl.GetIssueURL() 1958 branch_cl_issue_url = branch_cl.GetIssueURL()
1960 branch_cl_issue = branch_cl.GetIssue() 1959 branch_cl_issue = branch_cl.GetIssue()
1961 branch_cl_patchset = branch_cl.GetPatchset() 1960 branch_cl_patchset = branch_cl.GetPatchset()
1962 if branch_cl_issue_url and branch_cl_issue and branch_cl_patchset: 1961 if branch_cl_issue_url and branch_cl_issue and branch_cl_patchset:
1963 upload_args.extend( 1962 upload_args.extend(
1964 ['--depends_on_patchset', '%s:%s' % ( 1963 ['--depends_on_patchset', '%s:%s' % (
(...skipping 604 matching lines...) Expand 10 before | Expand all | Expand 10 after
2569 2568
2570 def _AddChangeIdToCommitMessage(self, options, args): 2569 def _AddChangeIdToCommitMessage(self, options, args):
2571 """Re-commits using the current message, assumes the commit hook is in 2570 """Re-commits using the current message, assumes the commit hook is in
2572 place. 2571 place.
2573 """ 2572 """
2574 log_desc = options.message or CreateDescriptionFromLog(args) 2573 log_desc = options.message or CreateDescriptionFromLog(args)
2575 git_command = ['commit', '--amend', '-m', log_desc] 2574 git_command = ['commit', '--amend', '-m', log_desc]
2576 RunGit(git_command) 2575 RunGit(git_command)
2577 new_log_desc = CreateDescriptionFromLog(args) 2576 new_log_desc = CreateDescriptionFromLog(args)
2578 if git_footers.get_footer_change_id(new_log_desc): 2577 if git_footers.get_footer_change_id(new_log_desc):
2579 print 'git-cl: Added Change-Id to commit message.' 2578 print('git-cl: Added Change-Id to commit message.')
2580 return new_log_desc 2579 return new_log_desc
2581 else: 2580 else:
2582 DieWithError('ERROR: Gerrit commit-msg hook not installed.') 2581 DieWithError('ERROR: Gerrit commit-msg hook not installed.')
2583 2582
2584 def SetCQState(self, new_state): 2583 def SetCQState(self, new_state):
2585 """Sets the Commit-Queue label assuming canonical CQ config for Gerrit.""" 2584 """Sets the Commit-Queue label assuming canonical CQ config for Gerrit."""
2586 # TODO(tandrii): maybe allow configurability in codereview.settings or by 2585 # TODO(tandrii): maybe allow configurability in codereview.settings or by
2587 # self-discovery of label config for this CL using REST API. 2586 # self-discovery of label config for this CL using REST API.
2588 vote_map = { 2587 vote_map = {
2589 _CQState.NONE: 0, 2588 _CQState.NONE: 0,
(...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after
2973 LoadCodereviewSettingsFromFile(urllib2.urlopen(url)) 2972 LoadCodereviewSettingsFromFile(urllib2.urlopen(url))
2974 return 0 2973 return 0
2975 2974
2976 2975
2977 def CMDbaseurl(parser, args): 2976 def CMDbaseurl(parser, args):
2978 """Gets or sets base-url for this branch.""" 2977 """Gets or sets base-url for this branch."""
2979 branchref = RunGit(['symbolic-ref', 'HEAD']).strip() 2978 branchref = RunGit(['symbolic-ref', 'HEAD']).strip()
2980 branch = ShortBranchName(branchref) 2979 branch = ShortBranchName(branchref)
2981 _, args = parser.parse_args(args) 2980 _, args = parser.parse_args(args)
2982 if not args: 2981 if not args:
2983 print("Current base-url:") 2982 print('Current base-url:')
2984 return RunGit(['config', 'branch.%s.base-url' % branch], 2983 return RunGit(['config', 'branch.%s.base-url' % branch],
2985 error_ok=False).strip() 2984 error_ok=False).strip()
2986 else: 2985 else:
2987 print("Setting base-url to %s" % args[0]) 2986 print('Setting base-url to %s' % args[0])
2988 return RunGit(['config', 'branch.%s.base-url' % branch, args[0]], 2987 return RunGit(['config', 'branch.%s.base-url' % branch, args[0]],
2989 error_ok=False).strip() 2988 error_ok=False).strip()
2990 2989
2991 2990
2992 def color_for_status(status): 2991 def color_for_status(status):
2993 """Maps a Changelist status to color, for CMDstatus and other tools.""" 2992 """Maps a Changelist status to color, for CMDstatus and other tools."""
2994 return { 2993 return {
2995 'unsent': Fore.RED, 2994 'unsent': Fore.RED,
2996 'waiting': Fore.BLUE, 2995 'waiting': Fore.BLUE,
2997 'reply': Fore.YELLOW, 2996 'reply': Fore.YELLOW,
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
3092 3091
3093 # Create a dictionary of all local branches to the branches that are dependent 3092 # Create a dictionary of all local branches to the branches that are dependent
3094 # on it. 3093 # on it.
3095 tracked_to_dependents = collections.defaultdict(list) 3094 tracked_to_dependents = collections.defaultdict(list)
3096 for b in branches.splitlines(): 3095 for b in branches.splitlines():
3097 tokens = b.split() 3096 tokens = b.split()
3098 if len(tokens) == 2: 3097 if len(tokens) == 2:
3099 branch_name, tracked = tokens 3098 branch_name, tracked = tokens
3100 tracked_to_dependents[tracked].append(branch_name) 3099 tracked_to_dependents[tracked].append(branch_name)
3101 3100
3102 print 3101 print()
3103 print 'The dependent local branches of %s are:' % root_branch 3102 print('The dependent local branches of %s are:' % root_branch)
3104 dependents = [] 3103 dependents = []
3105 def traverse_dependents_preorder(branch, padding=''): 3104 def traverse_dependents_preorder(branch, padding=''):
3106 dependents_to_process = tracked_to_dependents.get(branch, []) 3105 dependents_to_process = tracked_to_dependents.get(branch, [])
3107 padding += ' ' 3106 padding += ' '
3108 for dependent in dependents_to_process: 3107 for dependent in dependents_to_process:
3109 print '%s%s' % (padding, dependent) 3108 print('%s%s' % (padding, dependent))
3110 dependents.append(dependent) 3109 dependents.append(dependent)
3111 traverse_dependents_preorder(dependent, padding) 3110 traverse_dependents_preorder(dependent, padding)
3112 traverse_dependents_preorder(root_branch) 3111 traverse_dependents_preorder(root_branch)
3113 print 3112 print()
3114 3113
3115 if not dependents: 3114 if not dependents:
3116 print 'There are no dependent local branches for %s' % root_branch 3115 print('There are no dependent local branches for %s' % root_branch)
3117 return 0 3116 return 0
3118 3117
3119 print ('This command will checkout all dependent branches and run ' 3118 print('This command will checkout all dependent branches and run '
3120 '"git cl upload".') 3119 '"git cl upload".')
3121 ask_for_data('[Press enter to continue or ctrl-C to quit]') 3120 ask_for_data('[Press enter to continue or ctrl-C to quit]')
3122 3121
3123 # Add a default patchset title to all upload calls in Rietveld. 3122 # Add a default patchset title to all upload calls in Rietveld.
3124 if not cl.IsGerrit(): 3123 if not cl.IsGerrit():
3125 args.extend(['-t', 'Updated patchset dependency']) 3124 args.extend(['-t', 'Updated patchset dependency'])
3126 3125
3127 # Record all dependents that failed to upload. 3126 # Record all dependents that failed to upload.
3128 failures = {} 3127 failures = {}
3129 # Go through all dependents, checkout the branch and upload. 3128 # Go through all dependents, checkout the branch and upload.
3130 try: 3129 try:
3131 for dependent_branch in dependents: 3130 for dependent_branch in dependents:
3132 print 3131 print()
3133 print '--------------------------------------' 3132 print('--------------------------------------')
3134 print 'Running "git cl upload" from %s:' % dependent_branch 3133 print('Running "git cl upload" from %s:' % dependent_branch)
3135 RunGit(['checkout', '-q', dependent_branch]) 3134 RunGit(['checkout', '-q', dependent_branch])
3136 print 3135 print()
3137 try: 3136 try:
3138 if CMDupload(OptionParser(), args) != 0: 3137 if CMDupload(OptionParser(), args) != 0:
3139 print 'Upload failed for %s!' % dependent_branch 3138 print('Upload failed for %s!' % dependent_branch)
3140 failures[dependent_branch] = 1 3139 failures[dependent_branch] = 1
3141 except: # pylint: disable=W0702 3140 except: # pylint: disable=W0702
3142 failures[dependent_branch] = 1 3141 failures[dependent_branch] = 1
3143 print 3142 print()
3144 finally: 3143 finally:
3145 # Swap back to the original root branch. 3144 # Swap back to the original root branch.
3146 RunGit(['checkout', '-q', root_branch]) 3145 RunGit(['checkout', '-q', root_branch])
3147 3146
3148 print 3147 print()
3149 print 'Upload complete for dependent branches!' 3148 print('Upload complete for dependent branches!')
3150 for dependent_branch in dependents: 3149 for dependent_branch in dependents:
3151 upload_status = 'failed' if failures.get(dependent_branch) else 'succeeded' 3150 upload_status = 'failed' if failures.get(dependent_branch) else 'succeeded'
3152 print ' %s : %s' % (dependent_branch, upload_status) 3151 print(' %s : %s' % (dependent_branch, upload_status))
3153 print 3152 print()
3154 3153
3155 return 0 3154 return 0
3156 3155
3157 3156
3158 def CMDarchive(parser, args): 3157 def CMDarchive(parser, args):
3159 """Archives and deletes branches associated with closed changelists.""" 3158 """Archives and deletes branches associated with closed changelists."""
3160 parser.add_option( 3159 parser.add_option(
3161 '-j', '--maxjobs', action='store', type=int, 3160 '-j', '--maxjobs', action='store', type=int,
3162 help='The maximum number of jobs to use when retrieving review status') 3161 help='The maximum number of jobs to use when retrieving review status')
3163 parser.add_option( 3162 parser.add_option(
3164 '-f', '--force', action='store_true', 3163 '-f', '--force', action='store_true',
3165 help='Bypasses the confirmation prompt.') 3164 help='Bypasses the confirmation prompt.')
3166 3165
3167 auth.add_auth_options(parser) 3166 auth.add_auth_options(parser)
3168 options, args = parser.parse_args(args) 3167 options, args = parser.parse_args(args)
3169 if args: 3168 if args:
3170 parser.error('Unsupported args: %s' % ' '.join(args)) 3169 parser.error('Unsupported args: %s' % ' '.join(args))
3171 auth_config = auth.extract_auth_config_from_options(options) 3170 auth_config = auth.extract_auth_config_from_options(options)
3172 3171
3173 branches = RunGit(['for-each-ref', '--format=%(refname)', 'refs/heads']) 3172 branches = RunGit(['for-each-ref', '--format=%(refname)', 'refs/heads'])
3174 if not branches: 3173 if not branches:
3175 return 0 3174 return 0
3176 3175
3177 print 'Finding all branches associated with closed issues...' 3176 print('Finding all branches associated with closed issues...')
3178 changes = [Changelist(branchref=b, auth_config=auth_config) 3177 changes = [Changelist(branchref=b, auth_config=auth_config)
3179 for b in branches.splitlines()] 3178 for b in branches.splitlines()]
3180 alignment = max(5, max(len(c.GetBranch()) for c in changes)) 3179 alignment = max(5, max(len(c.GetBranch()) for c in changes))
3181 statuses = get_cl_statuses(changes, 3180 statuses = get_cl_statuses(changes,
3182 fine_grained=True, 3181 fine_grained=True,
3183 max_processes=options.maxjobs) 3182 max_processes=options.maxjobs)
3184 proposal = [(cl.GetBranch(), 3183 proposal = [(cl.GetBranch(),
3185 'git-cl-archived-%s-%s' % (cl.GetIssue(), cl.GetBranch())) 3184 'git-cl-archived-%s-%s' % (cl.GetIssue(), cl.GetBranch()))
3186 for cl, status in statuses 3185 for cl, status in statuses
3187 if status == 'closed'] 3186 if status == 'closed']
3188 proposal.sort() 3187 proposal.sort()
3189 3188
3190 if not proposal: 3189 if not proposal:
3191 print 'No branches with closed codereview issues found.' 3190 print('No branches with closed codereview issues found.')
3192 return 0 3191 return 0
3193 3192
3194 current_branch = GetCurrentBranch() 3193 current_branch = GetCurrentBranch()
3195 3194
3196 print '\nBranches with closed issues that will be archived:\n' 3195 print('\nBranches with closed issues that will be archived:\n')
3197 print '%*s | %s' % (alignment, 'Branch name', 'Archival tag name') 3196 print('%*s | %s' % (alignment, 'Branch name', 'Archival tag name'))
3198 for next_item in proposal: 3197 for next_item in proposal:
3199 print '%*s %s' % (alignment, next_item[0], next_item[1]) 3198 print('%*s %s' % (alignment, next_item[0], next_item[1]))
3200 3199
3201 if any(branch == current_branch for branch, _ in proposal): 3200 if any(branch == current_branch for branch, _ in proposal):
3202 print('You are currently on a branch \'%s\' which is associated with a ' 3201 print('You are currently on a branch \'%s\' which is associated with a '
3203 'closed codereview issue, so archive cannot proceed. Please ' 3202 'closed codereview issue, so archive cannot proceed. Please '
3204 'checkout another branch and run this command again.' % 3203 'checkout another branch and run this command again.' %
3205 current_branch) 3204 current_branch)
3206 return 1 3205 return 1
3207 3206
3208 if not options.force: 3207 if not options.force:
3209 if ask_for_data('\nProceed with deletion (Y/N)? ').lower() != 'y': 3208 if ask_for_data('\nProceed with deletion (Y/N)? ').lower() != 'y':
3210 print 'Aborted.' 3209 print('Aborted.')
3211 return 1 3210 return 1
3212 3211
3213 for branch, tagname in proposal: 3212 for branch, tagname in proposal:
3214 RunGit(['tag', tagname, branch]) 3213 RunGit(['tag', tagname, branch])
3215 RunGit(['branch', '-D', branch]) 3214 RunGit(['branch', '-D', branch])
3216 print '\nJob\'s done!' 3215 print('\nJob\'s done!')
3217 3216
3218 return 0 3217 return 0
3219 3218
3220 3219
3221 def CMDstatus(parser, args): 3220 def CMDstatus(parser, args):
3222 """Show status of changelists. 3221 """Show status of changelists.
3223 3222
3224 Colors are used to tell the state of the CL unless --fast is used: 3223 Colors are used to tell the state of the CL unless --fast is used:
3225 - Red not sent for review or broken 3224 - Red not sent for review or broken
3226 - Blue waiting for review 3225 - Blue waiting for review
(...skipping 14 matching lines...) Expand all
3241 3240
3242 auth.add_auth_options(parser) 3241 auth.add_auth_options(parser)
3243 options, args = parser.parse_args(args) 3242 options, args = parser.parse_args(args)
3244 if args: 3243 if args:
3245 parser.error('Unsupported args: %s' % args) 3244 parser.error('Unsupported args: %s' % args)
3246 auth_config = auth.extract_auth_config_from_options(options) 3245 auth_config = auth.extract_auth_config_from_options(options)
3247 3246
3248 if options.field: 3247 if options.field:
3249 cl = Changelist(auth_config=auth_config) 3248 cl = Changelist(auth_config=auth_config)
3250 if options.field.startswith('desc'): 3249 if options.field.startswith('desc'):
3251 print cl.GetDescription() 3250 print(cl.GetDescription())
3252 elif options.field == 'id': 3251 elif options.field == 'id':
3253 issueid = cl.GetIssue() 3252 issueid = cl.GetIssue()
3254 if issueid: 3253 if issueid:
3255 print issueid 3254 print(issueid)
3256 elif options.field == 'patch': 3255 elif options.field == 'patch':
3257 patchset = cl.GetPatchset() 3256 patchset = cl.GetPatchset()
3258 if patchset: 3257 if patchset:
3259 print patchset 3258 print(patchset)
3260 elif options.field == 'url': 3259 elif options.field == 'url':
3261 url = cl.GetIssueURL() 3260 url = cl.GetIssueURL()
3262 if url: 3261 if url:
3263 print url 3262 print(url)
3264 return 0 3263 return 0
3265 3264
3266 branches = RunGit(['for-each-ref', '--format=%(refname)', 'refs/heads']) 3265 branches = RunGit(['for-each-ref', '--format=%(refname)', 'refs/heads'])
3267 if not branches: 3266 if not branches:
3268 print('No local branch found.') 3267 print('No local branch found.')
3269 return 0 3268 return 0
3270 3269
3271 changes = [ 3270 changes = [
3272 Changelist(branchref=b, auth_config=auth_config) 3271 Changelist(branchref=b, auth_config=auth_config)
3273 for b in branches.splitlines()] 3272 for b in branches.splitlines()]
3274 print 'Branches associated with reviews:' 3273 print('Branches associated with reviews:')
3275 output = get_cl_statuses(changes, 3274 output = get_cl_statuses(changes,
3276 fine_grained=not options.fast, 3275 fine_grained=not options.fast,
3277 max_processes=options.maxjobs) 3276 max_processes=options.maxjobs)
3278 3277
3279 branch_statuses = {} 3278 branch_statuses = {}
3280 alignment = max(5, max(len(ShortBranchName(c.GetBranch())) for c in changes)) 3279 alignment = max(5, max(len(ShortBranchName(c.GetBranch())) for c in changes))
3281 for cl in sorted(changes, key=lambda c: c.GetBranch()): 3280 for cl in sorted(changes, key=lambda c: c.GetBranch()):
3282 branch = cl.GetBranch() 3281 branch = cl.GetBranch()
3283 while branch not in branch_statuses: 3282 while branch not in branch_statuses:
3284 c, status = output.next() 3283 c, status = output.next()
3285 branch_statuses[c.GetBranch()] = status 3284 branch_statuses[c.GetBranch()] = status
3286 status = branch_statuses.pop(branch) 3285 status = branch_statuses.pop(branch)
3287 url = cl.GetIssueURL() 3286 url = cl.GetIssueURL()
3288 if url and (not status or status == 'error'): 3287 if url and (not status or status == 'error'):
3289 # The issue probably doesn't exist anymore. 3288 # The issue probably doesn't exist anymore.
3290 url += ' (broken)' 3289 url += ' (broken)'
3291 3290
3292 color = color_for_status(status) 3291 color = color_for_status(status)
3293 reset = Fore.RESET 3292 reset = Fore.RESET
3294 if not setup_color.IS_TTY: 3293 if not setup_color.IS_TTY:
3295 color = '' 3294 color = ''
3296 reset = '' 3295 reset = ''
3297 status_str = '(%s)' % status if status else '' 3296 status_str = '(%s)' % status if status else ''
3298 print ' %*s : %s%s %s%s' % ( 3297 print(' %*s : %s%s %s%s' % (
3299 alignment, ShortBranchName(branch), color, url, 3298 alignment, ShortBranchName(branch), color, url,
3300 status_str, reset) 3299 status_str, reset))
3301 3300
3302 cl = Changelist(auth_config=auth_config) 3301 cl = Changelist(auth_config=auth_config)
3303 print 3302 print()
3304 print 'Current branch:', 3303 print('Current branch:',)
3305 print cl.GetBranch() 3304 print(cl.GetBranch())
3306 if not cl.GetIssue(): 3305 if not cl.GetIssue():
3307 print 'No issue assigned.' 3306 print('No issue assigned.')
3308 return 0 3307 return 0
3309 print 'Issue number: %s (%s)' % (cl.GetIssue(), cl.GetIssueURL()) 3308 print('Issue number: %s (%s)' % (cl.GetIssue(), cl.GetIssueURL()))
3310 if not options.fast: 3309 if not options.fast:
3311 print 'Issue description:' 3310 print('Issue description:')
3312 print cl.GetDescription(pretty=True) 3311 print(cl.GetDescription(pretty=True))
3313 return 0 3312 return 0
3314 3313
3315 3314
3316 def colorize_CMDstatus_doc(): 3315 def colorize_CMDstatus_doc():
3317 """To be called once in main() to add colors to git cl status help.""" 3316 """To be called once in main() to add colors to git cl status help."""
3318 colors = [i for i in dir(Fore) if i[0].isupper()] 3317 colors = [i for i in dir(Fore) if i[0].isupper()]
3319 3318
3320 def colorize_line(line): 3319 def colorize_line(line):
3321 for color in colors: 3320 for color in colors:
3322 if color in line.upper(): 3321 if color in line.upper():
(...skipping 27 matching lines...) Expand all
3350 # Reverse issue lookup. 3349 # Reverse issue lookup.
3351 issue_branch_map = {} 3350 issue_branch_map = {}
3352 for branch in branches: 3351 for branch in branches:
3353 cl = Changelist(branchref=branch) 3352 cl = Changelist(branchref=branch)
3354 issue_branch_map.setdefault(cl.GetIssue(), []).append(branch) 3353 issue_branch_map.setdefault(cl.GetIssue(), []).append(branch)
3355 if not args: 3354 if not args:
3356 args = sorted(issue_branch_map.iterkeys()) 3355 args = sorted(issue_branch_map.iterkeys())
3357 for issue in args: 3356 for issue in args:
3358 if not issue: 3357 if not issue:
3359 continue 3358 continue
3360 print 'Branch for issue number %s: %s' % ( 3359 print('Branch for issue number %s: %s' % (
3361 issue, ', '.join(issue_branch_map.get(int(issue)) or ('None',))) 3360 issue, ', '.join(issue_branch_map.get(int(issue)) or ('None',))))
3362 else: 3361 else:
3363 cl = Changelist(codereview=options.forced_codereview) 3362 cl = Changelist(codereview=options.forced_codereview)
3364 if len(args) > 0: 3363 if len(args) > 0:
3365 try: 3364 try:
3366 issue = int(args[0]) 3365 issue = int(args[0])
3367 except ValueError: 3366 except ValueError:
3368 DieWithError('Pass a number to set the issue or none to list it.\n' 3367 DieWithError('Pass a number to set the issue or none to list it.\n'
3369 'Maybe you want to run git cl status?') 3368 'Maybe you want to run git cl status?')
3370 cl.SetIssue(issue) 3369 cl.SetIssue(issue)
3371 print 'Issue number: %s (%s)' % (cl.GetIssue(), cl.GetIssueURL()) 3370 print('Issue number: %s (%s)' % (cl.GetIssue(), cl.GetIssueURL()))
3372 return 0 3371 return 0
3373 3372
3374 3373
3375 def CMDcomments(parser, args): 3374 def CMDcomments(parser, args):
3376 """Shows or posts review comments for any changelist.""" 3375 """Shows or posts review comments for any changelist."""
3377 parser.add_option('-a', '--add-comment', dest='comment', 3376 parser.add_option('-a', '--add-comment', dest='comment',
3378 help='comment to add to an issue') 3377 help='comment to add to an issue')
3379 parser.add_option('-i', dest='issue', 3378 parser.add_option('-i', dest='issue',
3380 help="review issue id (defaults to current issue)") 3379 help="review issue id (defaults to current issue)")
3381 parser.add_option('-j', '--json-file', 3380 parser.add_option('-j', '--json-file',
(...skipping 28 matching lines...) Expand all
3410 if message['disapproval']: 3409 if message['disapproval']:
3411 color = Fore.RED 3410 color = Fore.RED
3412 summary[-1]['not lgtm'] = True 3411 summary[-1]['not lgtm'] = True
3413 elif message['approval']: 3412 elif message['approval']:
3414 color = Fore.GREEN 3413 color = Fore.GREEN
3415 summary[-1]['lgtm'] = True 3414 summary[-1]['lgtm'] = True
3416 elif message['sender'] == data['owner_email']: 3415 elif message['sender'] == data['owner_email']:
3417 color = Fore.MAGENTA 3416 color = Fore.MAGENTA
3418 else: 3417 else:
3419 color = Fore.BLUE 3418 color = Fore.BLUE
3420 print '\n%s%s %s%s' % ( 3419 print('\n%s%s %s%s' % (
3421 color, message['date'].split('.', 1)[0], message['sender'], 3420 color, message['date'].split('.', 1)[0], message['sender'],
3422 Fore.RESET) 3421 Fore.RESET))
3423 if message['text'].strip(): 3422 if message['text'].strip():
3424 print '\n'.join(' ' + l for l in message['text'].splitlines()) 3423 print('\n'.join(' ' + l for l in message['text'].splitlines()))
3425 if options.json_file: 3424 if options.json_file:
3426 with open(options.json_file, 'wb') as f: 3425 with open(options.json_file, 'wb') as f:
3427 json.dump(summary, f) 3426 json.dump(summary, f)
3428 return 0 3427 return 0
3429 3428
3430 3429
3431 @subcommand.usage('[codereview url or issue id]') 3430 @subcommand.usage('[codereview url or issue id]')
3432 def CMDdescription(parser, args): 3431 def CMDdescription(parser, args):
3433 """Brings up the editor for the current CL's description.""" 3432 """Brings up the editor for the current CL's description."""
3434 parser.add_option('-d', '--display', action='store_true', 3433 parser.add_option('-d', '--display', action='store_true',
(...skipping 18 matching lines...) Expand all
3453 3452
3454 cl = Changelist( 3453 cl = Changelist(
3455 auth_config=auth_config, issue=target_issue, 3454 auth_config=auth_config, issue=target_issue,
3456 codereview=options.forced_codereview) 3455 codereview=options.forced_codereview)
3457 3456
3458 if not cl.GetIssue(): 3457 if not cl.GetIssue():
3459 DieWithError('This branch has no associated changelist.') 3458 DieWithError('This branch has no associated changelist.')
3460 description = ChangeDescription(cl.GetDescription()) 3459 description = ChangeDescription(cl.GetDescription())
3461 3460
3462 if options.display: 3461 if options.display:
3463 print description.description 3462 print(description.description)
3464 return 0 3463 return 0
3465 3464
3466 if options.new_description: 3465 if options.new_description:
3467 text = options.new_description 3466 text = options.new_description
3468 if text == '-': 3467 if text == '-':
3469 text = '\n'.join(l.rstrip() for l in sys.stdin) 3468 text = '\n'.join(l.rstrip() for l in sys.stdin)
3470 3469
3471 description.set_description(text) 3470 description.set_description(text)
3472 else: 3471 else:
3473 description.prompt() 3472 description.prompt()
(...skipping 24 matching lines...) Expand all
3498 auth.add_auth_options(parser) 3497 auth.add_auth_options(parser)
3499 options, args = parser.parse_args(args) 3498 options, args = parser.parse_args(args)
3500 auth_config = auth.extract_auth_config_from_options(options) 3499 auth_config = auth.extract_auth_config_from_options(options)
3501 3500
3502 # Access to a protected member _XX of a client class 3501 # Access to a protected member _XX of a client class
3503 # pylint: disable=W0212 3502 # pylint: disable=W0212
3504 try: 3503 try:
3505 import cpplint 3504 import cpplint
3506 import cpplint_chromium 3505 import cpplint_chromium
3507 except ImportError: 3506 except ImportError:
3508 print "Your depot_tools is missing cpplint.py and/or cpplint_chromium.py." 3507 print('Your depot_tools is missing cpplint.py and/or cpplint_chromium.py.')
3509 return 1 3508 return 1
3510 3509
3511 # Change the current working directory before calling lint so that it 3510 # Change the current working directory before calling lint so that it
3512 # shows the correct base. 3511 # shows the correct base.
3513 previous_cwd = os.getcwd() 3512 previous_cwd = os.getcwd()
3514 os.chdir(settings.GetRoot()) 3513 os.chdir(settings.GetRoot())
3515 try: 3514 try:
3516 cl = Changelist(auth_config=auth_config) 3515 cl = Changelist(auth_config=auth_config)
3517 change = cl.GetChange(cl.GetCommonAncestorWithUpstream(), None) 3516 change = cl.GetChange(cl.GetCommonAncestorWithUpstream(), None)
3518 files = [f.LocalPath() for f in change.AffectedFiles()] 3517 files = [f.LocalPath() for f in change.AffectedFiles()]
3519 if not files: 3518 if not files:
3520 print "Cannot lint an empty CL" 3519 print('Cannot lint an empty CL')
3521 return 1 3520 return 1
3522 3521
3523 # Process cpplints arguments if any. 3522 # Process cpplints arguments if any.
3524 command = args + files 3523 command = args + files
3525 if options.filter: 3524 if options.filter:
3526 command = ['--filter=' + ','.join(options.filter)] + command 3525 command = ['--filter=' + ','.join(options.filter)] + command
3527 filenames = cpplint.ParseArguments(command) 3526 filenames = cpplint.ParseArguments(command)
3528 3527
3529 white_regex = re.compile(settings.GetLintRegex()) 3528 white_regex = re.compile(settings.GetLintRegex())
3530 black_regex = re.compile(settings.GetLintIgnoreRegex()) 3529 black_regex = re.compile(settings.GetLintIgnoreRegex())
3531 extra_check_functions = [cpplint_chromium.CheckPointerDeclarationWhitespace] 3530 extra_check_functions = [cpplint_chromium.CheckPointerDeclarationWhitespace]
3532 for filename in filenames: 3531 for filename in filenames:
3533 if white_regex.match(filename): 3532 if white_regex.match(filename):
3534 if black_regex.match(filename): 3533 if black_regex.match(filename):
3535 print "Ignoring file %s" % filename 3534 print('Ignoring file %s' % filename)
3536 else: 3535 else:
3537 cpplint.ProcessFile(filename, cpplint._cpplint_state.verbose_level, 3536 cpplint.ProcessFile(filename, cpplint._cpplint_state.verbose_level,
3538 extra_check_functions) 3537 extra_check_functions)
3539 else: 3538 else:
3540 print "Skipping file %s" % filename 3539 print('Skipping file %s' % filename)
3541 finally: 3540 finally:
3542 os.chdir(previous_cwd) 3541 os.chdir(previous_cwd)
3543 print "Total errors found: %d\n" % cpplint._cpplint_state.error_count 3542 print('Total errors found: %d\n' % cpplint._cpplint_state.error_count)
3544 if cpplint._cpplint_state.error_count != 0: 3543 if cpplint._cpplint_state.error_count != 0:
3545 return 1 3544 return 1
3546 return 0 3545 return 0
3547 3546
3548 3547
3549 def CMDpresubmit(parser, args): 3548 def CMDpresubmit(parser, args):
3550 """Runs presubmit tests on the current changelist.""" 3549 """Runs presubmit tests on the current changelist."""
3551 parser.add_option('-u', '--upload', action='store_true', 3550 parser.add_option('-u', '--upload', action='store_true',
3552 help='Run upload hook instead of the push/dcommit hook') 3551 help='Run upload hook instead of the push/dcommit hook')
3553 parser.add_option('-f', '--force', action='store_true', 3552 parser.add_option('-f', '--force', action='store_true',
3554 help='Run checks even if tree is dirty') 3553 help='Run checks even if tree is dirty')
3555 auth.add_auth_options(parser) 3554 auth.add_auth_options(parser)
3556 options, args = parser.parse_args(args) 3555 options, args = parser.parse_args(args)
3557 auth_config = auth.extract_auth_config_from_options(options) 3556 auth_config = auth.extract_auth_config_from_options(options)
3558 3557
3559 if not options.force and git_common.is_dirty_git_tree('presubmit'): 3558 if not options.force and git_common.is_dirty_git_tree('presubmit'):
3560 print 'use --force to check even if tree is dirty.' 3559 print('use --force to check even if tree is dirty.')
3561 return 1 3560 return 1
3562 3561
3563 cl = Changelist(auth_config=auth_config) 3562 cl = Changelist(auth_config=auth_config)
3564 if args: 3563 if args:
3565 base_branch = args[0] 3564 base_branch = args[0]
3566 else: 3565 else:
3567 # Default to diffing against the common ancestor of the upstream branch. 3566 # Default to diffing against the common ancestor of the upstream branch.
3568 base_branch = cl.GetCommonAncestorWithUpstream() 3567 base_branch = cl.GetCommonAncestorWithUpstream()
3569 3568
3570 cl.RunHook( 3569 cl.RunHook(
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after
3802 'Before uploading a commit to Gerrit, ensure it\'s author field is ' 3801 'Before uploading a commit to Gerrit, ensure it\'s author field is '
3803 'the contributor\'s "name <email>". If you can\'t upload such a ' 3802 'the contributor\'s "name <email>". If you can\'t upload such a '
3804 'commit for review, contact your repository admin and request' 3803 'commit for review, contact your repository admin and request'
3805 '"Forge-Author" permission.') 3804 '"Forge-Author" permission.')
3806 return cl._codereview_impl.CMDLand(options.force, options.bypass_hooks, 3805 return cl._codereview_impl.CMDLand(options.force, options.bypass_hooks,
3807 options.verbose) 3806 options.verbose)
3808 3807
3809 current = cl.GetBranch() 3808 current = cl.GetBranch()
3810 remote, upstream_branch = cl.FetchUpstreamTuple(cl.GetBranch()) 3809 remote, upstream_branch = cl.FetchUpstreamTuple(cl.GetBranch())
3811 if not settings.GetIsGitSvn() and remote == '.': 3810 if not settings.GetIsGitSvn() and remote == '.':
3812 print 3811 print()
3813 print 'Attempting to push branch %r into another local branch!' % current 3812 print('Attempting to push branch %r into another local branch!' % current)
3814 print 3813 print()
3815 print 'Either reparent this branch on top of origin/master:' 3814 print('Either reparent this branch on top of origin/master:')
3816 print ' git reparent-branch --root' 3815 print(' git reparent-branch --root')
3817 print 3816 print()
3818 print 'OR run `git rebase-update` if you think the parent branch is already' 3817 print('OR run `git rebase-update` if you think the parent branch is ')
3819 print 'committed.' 3818 print('already committed.')
3820 print 3819 print()
3821 print ' Current parent: %r' % upstream_branch 3820 print(' Current parent: %r' % upstream_branch)
3822 return 1 3821 return 1
3823 3822
3824 if not args or cmd == 'land': 3823 if not args or cmd == 'land':
3825 # Default to merging against our best guess of the upstream branch. 3824 # Default to merging against our best guess of the upstream branch.
3826 args = [cl.GetUpstreamBranch()] 3825 args = [cl.GetUpstreamBranch()]
3827 3826
3828 if options.contributor: 3827 if options.contributor:
3829 if not re.match('^.*\s<\S+@\S+>$', options.contributor): 3828 if not re.match('^.*\s<\S+@\S+>$', options.contributor):
3830 print "Please provide contibutor as 'First Last <email@example.com>'" 3829 print("Please provide contibutor as 'First Last <email@example.com>'")
3831 return 1 3830 return 1
3832 3831
3833 base_branch = args[0] 3832 base_branch = args[0]
3834 base_has_submodules = IsSubmoduleMergeCommit(base_branch) 3833 base_has_submodules = IsSubmoduleMergeCommit(base_branch)
3835 3834
3836 if git_common.is_dirty_git_tree(cmd): 3835 if git_common.is_dirty_git_tree(cmd):
3837 return 1 3836 return 1
3838 3837
3839 # This rev-list syntax means "show all commits not in my branch that 3838 # This rev-list syntax means "show all commits not in my branch that
3840 # are in base_branch". 3839 # are in base_branch".
3841 upstream_commits = RunGit(['rev-list', '^' + cl.GetBranchRef(), 3840 upstream_commits = RunGit(['rev-list', '^' + cl.GetBranchRef(),
3842 base_branch]).splitlines() 3841 base_branch]).splitlines()
3843 if upstream_commits: 3842 if upstream_commits:
3844 print ('Base branch "%s" has %d commits ' 3843 print('Base branch "%s" has %d commits '
3845 'not in this branch.' % (base_branch, len(upstream_commits))) 3844 'not in this branch.' % (base_branch, len(upstream_commits)))
3846 print 'Run "git merge %s" before attempting to %s.' % (base_branch, cmd) 3845 print('Run "git merge %s" before attempting to %s.' % (base_branch, cmd))
3847 return 1 3846 return 1
3848 3847
3849 # This is the revision `svn dcommit` will commit on top of. 3848 # This is the revision `svn dcommit` will commit on top of.
3850 svn_head = None 3849 svn_head = None
3851 if cmd == 'dcommit' or base_has_submodules: 3850 if cmd == 'dcommit' or base_has_submodules:
3852 svn_head = RunGit(['log', '--grep=^git-svn-id:', '-1', 3851 svn_head = RunGit(['log', '--grep=^git-svn-id:', '-1',
3853 '--pretty=format:%H']) 3852 '--pretty=format:%H'])
3854 3853
3855 if cmd == 'dcommit': 3854 if cmd == 'dcommit':
3856 # If the base_head is a submodule merge commit, the first parent of the 3855 # If the base_head is a submodule merge commit, the first parent of the
3857 # base_head should be a git-svn commit, which is what we're interested in. 3856 # base_head should be a git-svn commit, which is what we're interested in.
3858 base_svn_head = base_branch 3857 base_svn_head = base_branch
3859 if base_has_submodules: 3858 if base_has_submodules:
3860 base_svn_head += '^1' 3859 base_svn_head += '^1'
3861 3860
3862 extra_commits = RunGit(['rev-list', '^' + svn_head, base_svn_head]) 3861 extra_commits = RunGit(['rev-list', '^' + svn_head, base_svn_head])
3863 if extra_commits: 3862 if extra_commits:
3864 print ('This branch has %d additional commits not upstreamed yet.' 3863 print('This branch has %d additional commits not upstreamed yet.'
3865 % len(extra_commits.splitlines())) 3864 % len(extra_commits.splitlines()))
3866 print ('Upstream "%s" or rebase this branch on top of the upstream trunk ' 3865 print('Upstream "%s" or rebase this branch on top of the upstream trunk '
3867 'before attempting to %s.' % (base_branch, cmd)) 3866 'before attempting to %s.' % (base_branch, cmd))
3868 return 1 3867 return 1
3869 3868
3870 merge_base = RunGit(['merge-base', base_branch, 'HEAD']).strip() 3869 merge_base = RunGit(['merge-base', base_branch, 'HEAD']).strip()
3871 if not options.bypass_hooks: 3870 if not options.bypass_hooks:
3872 author = None 3871 author = None
3873 if options.contributor: 3872 if options.contributor:
3874 author = re.search(r'\<(.*)\>', options.contributor).group(1) 3873 author = re.search(r'\<(.*)\>', options.contributor).group(1)
3875 hook_results = cl.RunHook( 3874 hook_results = cl.RunHook(
3876 committing=True, 3875 committing=True,
3877 may_prompt=not options.force, 3876 may_prompt=not options.force,
(...skipping 14 matching lines...) Expand all
3892 return 1 3891 return 1
3893 3892
3894 change_desc = ChangeDescription(options.message) 3893 change_desc = ChangeDescription(options.message)
3895 if not change_desc.description and cl.GetIssue(): 3894 if not change_desc.description and cl.GetIssue():
3896 change_desc = ChangeDescription(cl.GetDescription()) 3895 change_desc = ChangeDescription(cl.GetDescription())
3897 3896
3898 if not change_desc.description: 3897 if not change_desc.description:
3899 if not cl.GetIssue() and options.bypass_hooks: 3898 if not cl.GetIssue() and options.bypass_hooks:
3900 change_desc = ChangeDescription(CreateDescriptionFromLog([merge_base])) 3899 change_desc = ChangeDescription(CreateDescriptionFromLog([merge_base]))
3901 else: 3900 else:
3902 print 'No description set.' 3901 print('No description set.')
3903 print 'Visit %s/edit to set it.' % (cl.GetIssueURL()) 3902 print('Visit %s/edit to set it.' % (cl.GetIssueURL()))
3904 return 1 3903 return 1
3905 3904
3906 # Keep a separate copy for the commit message, because the commit message 3905 # Keep a separate copy for the commit message, because the commit message
3907 # contains the link to the Rietveld issue, while the Rietveld message contains 3906 # contains the link to the Rietveld issue, while the Rietveld message contains
3908 # the commit viewvc url. 3907 # the commit viewvc url.
3909 # Keep a separate copy for the commit message. 3908 # Keep a separate copy for the commit message.
3910 if cl.GetIssue(): 3909 if cl.GetIssue():
3911 change_desc.update_reviewers(cl.GetApprovingReviewers()) 3910 change_desc.update_reviewers(cl.GetApprovingReviewers())
3912 3911
3913 commit_desc = ChangeDescription(change_desc.description) 3912 commit_desc = ChangeDescription(change_desc.description)
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
4011 '.*?\nCommitted r(\\d+)', output, re.DOTALL).group(1) 4010 '.*?\nCommitted r(\\d+)', output, re.DOTALL).group(1)
4012 logging.debug(output) 4011 logging.debug(output)
4013 finally: 4012 finally:
4014 # And then swap back to the original branch and clean up. 4013 # And then swap back to the original branch and clean up.
4015 RunGit(['checkout', '-q', cl.GetBranch()]) 4014 RunGit(['checkout', '-q', cl.GetBranch()])
4016 RunGit(['branch', '-D', MERGE_BRANCH]) 4015 RunGit(['branch', '-D', MERGE_BRANCH])
4017 if base_has_submodules: 4016 if base_has_submodules:
4018 RunGit(['branch', '-D', CHERRY_PICK_BRANCH]) 4017 RunGit(['branch', '-D', CHERRY_PICK_BRANCH])
4019 4018
4020 if not revision: 4019 if not revision:
4021 print 'Failed to push. If this persists, please file a bug.' 4020 print('Failed to push. If this persists, please file a bug.')
4022 return 1 4021 return 1
4023 4022
4024 killed = False 4023 killed = False
4025 if pushed_to_pending: 4024 if pushed_to_pending:
4026 try: 4025 try:
4027 revision = WaitForRealCommit(remote, revision, base_branch, branch) 4026 revision = WaitForRealCommit(remote, revision, base_branch, branch)
4028 # We set pushed_to_pending to False, since it made it all the way to the 4027 # We set pushed_to_pending to False, since it made it all the way to the
4029 # real ref. 4028 # real ref.
4030 pushed_to_pending = False 4029 pushed_to_pending = False
4031 except KeyboardInterrupt: 4030 except KeyboardInterrupt:
4032 killed = True 4031 killed = True
4033 4032
4034 if cl.GetIssue(): 4033 if cl.GetIssue():
4035 to_pending = ' to pending queue' if pushed_to_pending else '' 4034 to_pending = ' to pending queue' if pushed_to_pending else ''
4036 viewvc_url = settings.GetViewVCUrl() 4035 viewvc_url = settings.GetViewVCUrl()
4037 if not to_pending: 4036 if not to_pending:
4038 if viewvc_url and revision: 4037 if viewvc_url and revision:
4039 change_desc.append_footer( 4038 change_desc.append_footer(
4040 'Committed: %s%s' % (viewvc_url, revision)) 4039 'Committed: %s%s' % (viewvc_url, revision))
4041 elif revision: 4040 elif revision:
4042 change_desc.append_footer('Committed: %s' % (revision,)) 4041 change_desc.append_footer('Committed: %s' % (revision,))
4043 print ('Closing issue ' 4042 print('Closing issue '
4044 '(you may be prompted for your codereview password)...') 4043 '(you may be prompted for your codereview password)...')
4045 cl.UpdateDescription(change_desc.description) 4044 cl.UpdateDescription(change_desc.description)
4046 cl.CloseIssue() 4045 cl.CloseIssue()
4047 props = cl.GetIssueProperties() 4046 props = cl.GetIssueProperties()
4048 patch_num = len(props['patchsets']) 4047 patch_num = len(props['patchsets'])
4049 comment = "Committed patchset #%d (id:%d)%s manually as %s" % ( 4048 comment = "Committed patchset #%d (id:%d)%s manually as %s" % (
4050 patch_num, props['patchsets'][-1], to_pending, revision) 4049 patch_num, props['patchsets'][-1], to_pending, revision)
4051 if options.bypass_hooks: 4050 if options.bypass_hooks:
4052 comment += ' (tree was closed).' if GetTreeStatus() == 'closed' else '.' 4051 comment += ' (tree was closed).' if GetTreeStatus() == 'closed' else '.'
4053 else: 4052 else:
4054 comment += ' (presubmit successful).' 4053 comment += ' (presubmit successful).'
4055 cl.RpcServer().add_comment(cl.GetIssue(), comment) 4054 cl.RpcServer().add_comment(cl.GetIssue(), comment)
4056 cl.SetIssue(None) 4055 cl.SetIssue(None)
4057 4056
4058 if pushed_to_pending: 4057 if pushed_to_pending:
4059 _, branch = cl.FetchUpstreamTuple(cl.GetBranch()) 4058 _, branch = cl.FetchUpstreamTuple(cl.GetBranch())
4060 print 'The commit is in the pending queue (%s).' % pending_ref 4059 print('The commit is in the pending queue (%s).' % pending_ref)
4061 print ( 4060 print('It will show up on %s in ~1 min, once it gets a Cr-Commit-Position '
4062 'It will show up on %s in ~1 min, once it gets a Cr-Commit-Position ' 4061 'footer.' % branch)
4063 'footer.' % branch)
4064 4062
4065 hook = POSTUPSTREAM_HOOK_PATTERN % cmd 4063 hook = POSTUPSTREAM_HOOK_PATTERN % cmd
4066 if os.path.isfile(hook): 4064 if os.path.isfile(hook):
4067 RunCommand([hook, merge_base], error_ok=True) 4065 RunCommand([hook, merge_base], error_ok=True)
4068 4066
4069 return 1 if killed else 0 4067 return 1 if killed else 0
4070 4068
4071 4069
4072 def WaitForRealCommit(remote, pushed_commit, local_base_ref, real_ref): 4070 def WaitForRealCommit(remote, pushed_commit, local_base_ref, real_ref):
4073 print 4071 print()
4074 print 'Waiting for commit to be landed on %s...' % real_ref 4072 print('Waiting for commit to be landed on %s...' % real_ref)
4075 print '(If you are impatient, you may Ctrl-C once without harm)' 4073 print('(If you are impatient, you may Ctrl-C once without harm)')
4076 target_tree = RunGit(['rev-parse', '%s:' % pushed_commit]).strip() 4074 target_tree = RunGit(['rev-parse', '%s:' % pushed_commit]).strip()
4077 current_rev = RunGit(['rev-parse', local_base_ref]).strip() 4075 current_rev = RunGit(['rev-parse', local_base_ref]).strip()
4078 mirror = settings.GetGitMirror(remote) 4076 mirror = settings.GetGitMirror(remote)
4079 4077
4080 loop = 0 4078 loop = 0
4081 while True: 4079 while True:
4082 sys.stdout.write('fetching (%d)... \r' % loop) 4080 sys.stdout.write('fetching (%d)... \r' % loop)
4083 sys.stdout.flush() 4081 sys.stdout.flush()
4084 loop += 1 4082 loop += 1
4085 4083
4086 if mirror: 4084 if mirror:
4087 mirror.populate() 4085 mirror.populate()
4088 RunGit(['retry', 'fetch', remote, real_ref], stderr=subprocess2.VOID) 4086 RunGit(['retry', 'fetch', remote, real_ref], stderr=subprocess2.VOID)
4089 to_rev = RunGit(['rev-parse', 'FETCH_HEAD']).strip() 4087 to_rev = RunGit(['rev-parse', 'FETCH_HEAD']).strip()
4090 commits = RunGit(['rev-list', '%s..%s' % (current_rev, to_rev)]) 4088 commits = RunGit(['rev-list', '%s..%s' % (current_rev, to_rev)])
4091 for commit in commits.splitlines(): 4089 for commit in commits.splitlines():
4092 if RunGit(['rev-parse', '%s:' % commit]).strip() == target_tree: 4090 if RunGit(['rev-parse', '%s:' % commit]).strip() == target_tree:
4093 print 'Found commit on %s' % real_ref 4091 print('Found commit on %s' % real_ref)
4094 return commit 4092 return commit
4095 4093
4096 current_rev = to_rev 4094 current_rev = to_rev
4097 4095
4098 4096
4099 def PushToGitPending(remote, pending_ref, upstream_ref): 4097 def PushToGitPending(remote, pending_ref, upstream_ref):
4100 """Fetches pending_ref, cherry-picks current HEAD on top of it, pushes. 4098 """Fetches pending_ref, cherry-picks current HEAD on top of it, pushes.
4101 4099
4102 Returns: 4100 Returns:
4103 (retcode of last operation, output log of last operation). 4101 (retcode of last operation, output log of last operation).
4104 """ 4102 """
4105 assert pending_ref.startswith('refs/'), pending_ref 4103 assert pending_ref.startswith('refs/'), pending_ref
4106 local_pending_ref = 'refs/git-cl/' + pending_ref[len('refs/'):] 4104 local_pending_ref = 'refs/git-cl/' + pending_ref[len('refs/'):]
4107 cherry = RunGit(['rev-parse', 'HEAD']).strip() 4105 cherry = RunGit(['rev-parse', 'HEAD']).strip()
4108 code = 0 4106 code = 0
4109 out = '' 4107 out = ''
4110 max_attempts = 3 4108 max_attempts = 3
4111 attempts_left = max_attempts 4109 attempts_left = max_attempts
4112 while attempts_left: 4110 while attempts_left:
4113 if attempts_left != max_attempts: 4111 if attempts_left != max_attempts:
4114 print 'Retrying, %d attempts left...' % (attempts_left - 1,) 4112 print('Retrying, %d attempts left...' % (attempts_left - 1,))
4115 attempts_left -= 1 4113 attempts_left -= 1
4116 4114
4117 # Fetch. Retry fetch errors. 4115 # Fetch. Retry fetch errors.
4118 print 'Fetching pending ref %s...' % pending_ref 4116 print('Fetching pending ref %s...' % pending_ref)
4119 code, out = RunGitWithCode( 4117 code, out = RunGitWithCode(
4120 ['retry', 'fetch', remote, '+%s:%s' % (pending_ref, local_pending_ref)]) 4118 ['retry', 'fetch', remote, '+%s:%s' % (pending_ref, local_pending_ref)])
4121 if code: 4119 if code:
4122 print 'Fetch failed with exit code %d.' % code 4120 print('Fetch failed with exit code %d.' % code)
4123 if out.strip(): 4121 if out.strip():
4124 print out.strip() 4122 print(out.strip())
4125 continue 4123 continue
4126 4124
4127 # Try to cherry pick. Abort on merge conflicts. 4125 # Try to cherry pick. Abort on merge conflicts.
4128 print 'Cherry-picking commit on top of pending ref...' 4126 print('Cherry-picking commit on top of pending ref...')
4129 RunGitWithCode(['checkout', local_pending_ref], suppress_stderr=True) 4127 RunGitWithCode(['checkout', local_pending_ref], suppress_stderr=True)
4130 code, out = RunGitWithCode(['cherry-pick', cherry]) 4128 code, out = RunGitWithCode(['cherry-pick', cherry])
4131 if code: 4129 if code:
4132 print ( 4130 print('Your patch doesn\'t apply cleanly to ref \'%s\', '
4133 'Your patch doesn\'t apply cleanly to ref \'%s\', ' 4131 'the following files have merge conflicts:' % pending_ref)
4134 'the following files have merge conflicts:' % pending_ref) 4132 print(RunGit(['diff', '--name-status', '--diff-filter=U']).strip())
4135 print RunGit(['diff', '--name-status', '--diff-filter=U']).strip() 4133 print('Please rebase your patch and try again.')
4136 print 'Please rebase your patch and try again.'
4137 RunGitWithCode(['cherry-pick', '--abort']) 4134 RunGitWithCode(['cherry-pick', '--abort'])
4138 return code, out 4135 return code, out
4139 4136
4140 # Applied cleanly, try to push now. Retry on error (flake or non-ff push). 4137 # Applied cleanly, try to push now. Retry on error (flake or non-ff push).
4141 print 'Pushing commit to %s... It can take a while.' % pending_ref 4138 print('Pushing commit to %s... It can take a while.' % pending_ref)
4142 code, out = RunGitWithCode( 4139 code, out = RunGitWithCode(
4143 ['retry', 'push', '--porcelain', remote, 'HEAD:%s' % pending_ref]) 4140 ['retry', 'push', '--porcelain', remote, 'HEAD:%s' % pending_ref])
4144 if code == 0: 4141 if code == 0:
4145 # Success. 4142 # Success.
4146 print 'Commit pushed to pending ref successfully!' 4143 print('Commit pushed to pending ref successfully!')
4147 return code, out 4144 return code, out
4148 4145
4149 print 'Push failed with exit code %d.' % code 4146 print('Push failed with exit code %d.' % code)
4150 if out.strip(): 4147 if out.strip():
4151 print out.strip() 4148 print(out.strip())
4152 if IsFatalPushFailure(out): 4149 if IsFatalPushFailure(out):
4153 print ( 4150 print('Fatal push error. Make sure your .netrc credentials and git '
4154 'Fatal push error. Make sure your .netrc credentials and git ' 4151 'user.email are correct and you have push access to the repo.')
4155 'user.email are correct and you have push access to the repo.')
4156 return code, out 4152 return code, out
4157 4153
4158 print 'All attempts to push to pending ref failed.' 4154 print('All attempts to push to pending ref failed.')
4159 return code, out 4155 return code, out
4160 4156
4161 4157
4162 def IsFatalPushFailure(push_stdout): 4158 def IsFatalPushFailure(push_stdout):
4163 """True if retrying push won't help.""" 4159 """True if retrying push won't help."""
4164 return '(prohibited by Gerrit)' in push_stdout 4160 return '(prohibited by Gerrit)' in push_stdout
4165 4161
4166 4162
4167 @subcommand.usage('[upstream branch to apply against]') 4163 @subcommand.usage('[upstream branch to apply against]')
4168 def CMDdcommit(parser, args): 4164 def CMDdcommit(parser, args):
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
4350 elif result_master != cur_master: 4346 elif result_master != cur_master:
4351 return None, 'The builders do not belong to the same master.' 4347 return None, 'The builders do not belong to the same master.'
4352 return result_master, None 4348 return result_master, None
4353 4349
4354 4350
4355 def CMDtree(parser, args): 4351 def CMDtree(parser, args):
4356 """Shows the status of the tree.""" 4352 """Shows the status of the tree."""
4357 _, args = parser.parse_args(args) 4353 _, args = parser.parse_args(args)
4358 status = GetTreeStatus() 4354 status = GetTreeStatus()
4359 if 'unset' == status: 4355 if 'unset' == status:
4360 print 'You must configure your tree status URL by running "git cl config".' 4356 print('You must configure your tree status URL by running "git cl config".')
4361 return 2 4357 return 2
4362 4358
4363 print "The tree is %s" % status 4359 print('The tree is %s' % status)
4364 print 4360 print()
4365 print GetTreeStatusReason() 4361 print(GetTreeStatusReason())
4366 if status != 'open': 4362 if status != 'open':
4367 return 1 4363 return 1
4368 return 0 4364 return 0
4369 4365
4370 4366
4371 def CMDtry(parser, args): 4367 def CMDtry(parser, args):
4372 """Triggers try jobs through BuildBucket.""" 4368 """Triggers try jobs through BuildBucket."""
4373 group = optparse.OptionGroup(parser, "Try job options") 4369 group = optparse.OptionGroup(parser, "Try job options")
4374 group.add_option( 4370 group.add_option(
4375 "-b", "--bot", action="append", 4371 "-b", "--bot", action="append",
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
4522 4518
4523 # Return a master map with one master to be backwards compatible. The 4519 # Return a master map with one master to be backwards compatible. The
4524 # master name defaults to an empty string, which will cause the master 4520 # master name defaults to an empty string, which will cause the master
4525 # not to be set on rietveld (deprecated). 4521 # not to be set on rietveld (deprecated).
4526 return {options.master: builders_and_tests} 4522 return {options.master: builders_and_tests}
4527 4523
4528 masters = GetMasterMap() 4524 masters = GetMasterMap()
4529 4525
4530 for builders in masters.itervalues(): 4526 for builders in masters.itervalues():
4531 if any('triggered' in b for b in builders): 4527 if any('triggered' in b for b in builders):
4532 print >> sys.stderr, ( 4528 print('ERROR You are trying to send a job to a triggered bot. This type '
4533 'ERROR You are trying to send a job to a triggered bot. This type of' 4529 'of bot requires an\ninitial job from a parent (usually a builder).'
4534 ' bot requires an\ninitial job from a parent (usually a builder). ' 4530 ' Instead send your job to the parent.\n'
4535 'Instead send your job to the parent.\n' 4531 'Bot list: %s' % builders, file=sys.stderr)
4536 'Bot list: %s' % builders)
4537 return 1 4532 return 1
4538 4533
4539 patchset = cl.GetMostRecentPatchset() 4534 patchset = cl.GetMostRecentPatchset()
4540 if patchset and patchset != cl.GetPatchset(): 4535 if patchset and patchset != cl.GetPatchset():
4541 print( 4536 print(
4542 '\nWARNING Mismatch between local config and server. Did a previous ' 4537 '\nWARNING Mismatch between local config and server. Did a previous '
4543 'upload fail?\ngit-cl try always uses latest patchset from rietveld. ' 4538 'upload fail?\ngit-cl try always uses latest patchset from rietveld. '
4544 'Continuing using\npatchset %s.\n' % patchset) 4539 'Continuing using\npatchset %s.\n' % patchset)
4545 if options.luci: 4540 if options.luci:
4546 trigger_luci_job(cl, masters, options) 4541 trigger_luci_job(cl, masters, options)
4547 elif not options.use_rietveld: 4542 elif not options.use_rietveld:
4548 try: 4543 try:
4549 trigger_try_jobs(auth_config, cl, options, masters, 'git_cl_try') 4544 trigger_try_jobs(auth_config, cl, options, masters, 'git_cl_try')
4550 except BuildbucketResponseException as ex: 4545 except BuildbucketResponseException as ex:
4551 print 'ERROR: %s' % ex 4546 print('ERROR: %s' % ex)
4552 return 1 4547 return 1
4553 except Exception as e: 4548 except Exception as e:
4554 stacktrace = (''.join(traceback.format_stack()) + traceback.format_exc()) 4549 stacktrace = (''.join(traceback.format_stack()) + traceback.format_exc())
4555 print 'ERROR: Exception when trying to trigger tryjobs: %s\n%s' % ( 4550 print('ERROR: Exception when trying to trigger tryjobs: %s\n%s' %
4556 e, stacktrace) 4551 (e, stacktrace))
4557 return 1 4552 return 1
4558 else: 4553 else:
4559 try: 4554 try:
4560 cl.RpcServer().trigger_distributed_try_jobs( 4555 cl.RpcServer().trigger_distributed_try_jobs(
4561 cl.GetIssue(), patchset, options.name, options.clobber, 4556 cl.GetIssue(), patchset, options.name, options.clobber,
4562 options.revision, masters) 4557 options.revision, masters)
4563 except urllib2.HTTPError as e: 4558 except urllib2.HTTPError as e:
4564 if e.code == 404: 4559 if e.code == 404:
4565 print('404 from rietveld; ' 4560 print('404 from rietveld; '
4566 'did you mean to use "git try" instead of "git cl try"?') 4561 'did you mean to use "git try" instead of "git cl try"?')
4567 return 1 4562 return 1
4568 print('Tried jobs on:') 4563 print('Tried jobs on:')
4569 4564
4570 for (master, builders) in sorted(masters.iteritems()): 4565 for (master, builders) in sorted(masters.iteritems()):
4571 if master: 4566 if master:
4572 print 'Master: %s' % master 4567 print('Master: %s' % master)
4573 length = max(len(builder) for builder in builders) 4568 length = max(len(builder) for builder in builders)
4574 for builder in sorted(builders): 4569 for builder in sorted(builders):
4575 print ' %*s: %s' % (length, builder, ','.join(builders[builder])) 4570 print(' %*s: %s' % (length, builder, ','.join(builders[builder])))
4576 return 0 4571 return 0
4577 4572
4578 4573
4579 def CMDtry_results(parser, args): 4574 def CMDtry_results(parser, args):
4580 group = optparse.OptionGroup(parser, "Try job results options") 4575 group = optparse.OptionGroup(parser, "Try job results options")
4581 group.add_option( 4576 group.add_option(
4582 "-p", "--patchset", type=int, help="patchset number if not current.") 4577 "-p", "--patchset", type=int, help="patchset number if not current.")
4583 group.add_option( 4578 group.add_option(
4584 "--print-master", action='store_true', help="print master name as well.") 4579 "--print-master", action='store_true', help="print master name as well.")
4585 group.add_option( 4580 group.add_option(
(...skipping 16 matching lines...) Expand all
4602 if not options.patchset: 4597 if not options.patchset:
4603 options.patchset = cl.GetMostRecentPatchset() 4598 options.patchset = cl.GetMostRecentPatchset()
4604 if options.patchset and options.patchset != cl.GetPatchset(): 4599 if options.patchset and options.patchset != cl.GetPatchset():
4605 print( 4600 print(
4606 '\nWARNING Mismatch between local config and server. Did a previous ' 4601 '\nWARNING Mismatch between local config and server. Did a previous '
4607 'upload fail?\ngit-cl try always uses latest patchset from rietveld. ' 4602 'upload fail?\ngit-cl try always uses latest patchset from rietveld. '
4608 'Continuing using\npatchset %s.\n' % options.patchset) 4603 'Continuing using\npatchset %s.\n' % options.patchset)
4609 try: 4604 try:
4610 jobs = fetch_try_jobs(auth_config, cl, options) 4605 jobs = fetch_try_jobs(auth_config, cl, options)
4611 except BuildbucketResponseException as ex: 4606 except BuildbucketResponseException as ex:
4612 print 'Buildbucket error: %s' % ex 4607 print('Buildbucket error: %s' % ex)
4613 return 1 4608 return 1
4614 except Exception as e: 4609 except Exception as e:
4615 stacktrace = (''.join(traceback.format_stack()) + traceback.format_exc()) 4610 stacktrace = (''.join(traceback.format_stack()) + traceback.format_exc())
4616 print 'ERROR: Exception when trying to fetch tryjobs: %s\n%s' % ( 4611 print('ERROR: Exception when trying to fetch tryjobs: %s\n%s' %
4617 e, stacktrace) 4612 (e, stacktrace))
4618 return 1 4613 return 1
4619 print_tryjobs(options, jobs) 4614 print_tryjobs(options, jobs)
4620 return 0 4615 return 0
4621 4616
4622 4617
4623 @subcommand.usage('[new upstream branch]') 4618 @subcommand.usage('[new upstream branch]')
4624 def CMDupstream(parser, args): 4619 def CMDupstream(parser, args):
4625 """Prints or sets the name of the upstream branch, if any.""" 4620 """Prints or sets the name of the upstream branch, if any."""
4626 _, args = parser.parse_args(args) 4621 _, args = parser.parse_args(args)
4627 if len(args) > 1: 4622 if len(args) > 1:
4628 parser.error('Unrecognized args: %s' % ' '.join(args)) 4623 parser.error('Unrecognized args: %s' % ' '.join(args))
4629 4624
4630 cl = Changelist() 4625 cl = Changelist()
4631 if args: 4626 if args:
4632 # One arg means set upstream branch. 4627 # One arg means set upstream branch.
4633 branch = cl.GetBranch() 4628 branch = cl.GetBranch()
4634 RunGit(['branch', '--set-upstream', branch, args[0]]) 4629 RunGit(['branch', '--set-upstream', branch, args[0]])
4635 cl = Changelist() 4630 cl = Changelist()
4636 print "Upstream branch set to " + cl.GetUpstreamBranch() 4631 print('Upstream branch set to %s' % (cl.GetUpstreamBranch(),))
4637 4632
4638 # Clear configured merge-base, if there is one. 4633 # Clear configured merge-base, if there is one.
4639 git_common.remove_merge_base(branch) 4634 git_common.remove_merge_base(branch)
4640 else: 4635 else:
4641 print cl.GetUpstreamBranch() 4636 print(cl.GetUpstreamBranch())
4642 return 0 4637 return 0
4643 4638
4644 4639
4645 def CMDweb(parser, args): 4640 def CMDweb(parser, args):
4646 """Opens the current CL in the web browser.""" 4641 """Opens the current CL in the web browser."""
4647 _, args = parser.parse_args(args) 4642 _, args = parser.parse_args(args)
4648 if args: 4643 if args:
4649 parser.error('Unrecognized args: %s' % ' '.join(args)) 4644 parser.error('Unrecognized args: %s' % ' '.join(args))
4650 4645
4651 issue_url = Changelist().GetIssueURL() 4646 issue_url = Changelist().GetIssueURL()
4652 if not issue_url: 4647 if not issue_url:
4653 print >> sys.stderr, 'ERROR No issue to open' 4648 print('ERROR No issue to open', file=sys.stderr)
4654 return 1 4649 return 1
4655 4650
4656 webbrowser.open(issue_url) 4651 webbrowser.open(issue_url)
4657 return 0 4652 return 0
4658 4653
4659 4654
4660 def CMDset_commit(parser, args): 4655 def CMDset_commit(parser, args):
4661 """Sets the commit bit to trigger the Commit Queue.""" 4656 """Sets the commit bit to trigger the Commit Queue."""
4662 parser.add_option('-d', '--dry-run', action='store_true', 4657 parser.add_option('-d', '--dry-run', action='store_true',
4663 help='trigger in dry run mode') 4658 help='trigger in dry run mode')
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
4909 try: 4904 try:
4910 command = [dart_format.FindDartFmtToolInChromiumTree()] 4905 command = [dart_format.FindDartFmtToolInChromiumTree()]
4911 if not opts.dry_run and not opts.diff: 4906 if not opts.dry_run and not opts.diff:
4912 command.append('-w') 4907 command.append('-w')
4913 command.extend(dart_diff_files) 4908 command.extend(dart_diff_files)
4914 4909
4915 stdout = RunCommand(command, cwd=top_dir) 4910 stdout = RunCommand(command, cwd=top_dir)
4916 if opts.dry_run and stdout: 4911 if opts.dry_run and stdout:
4917 return_value = 2 4912 return_value = 2
4918 except dart_format.NotFoundError as e: 4913 except dart_format.NotFoundError as e:
4919 print ('Warning: Unable to check Dart code formatting. Dart SDK not ' + 4914 print('Warning: Unable to check Dart code formatting. Dart SDK not '
4920 'found in this checkout. Files in other languages are still ' + 4915 'found in this checkout. Files in other languages are still '
4921 'formatted.') 4916 'formatted.')
4922 4917
4923 # Format GN build files. Always run on full build files for canonical form. 4918 # Format GN build files. Always run on full build files for canonical form.
4924 if gn_diff_files: 4919 if gn_diff_files:
4925 cmd = ['gn', 'format'] 4920 cmd = ['gn', 'format']
4926 if not opts.dry_run and not opts.diff: 4921 if not opts.dry_run and not opts.diff:
4927 cmd.append('--in-place') 4922 cmd.append('--in-place')
4928 for gn_diff_file in gn_diff_files: 4923 for gn_diff_file in gn_diff_files:
4929 stdout = RunCommand(cmd + [gn_diff_file], 4924 stdout = RunCommand(cmd + [gn_diff_file],
4930 shell=sys.platform == 'win32', 4925 shell=sys.platform == 'win32',
4931 cwd=top_dir) 4926 cwd=top_dir)
(...skipping 23 matching lines...) Expand all
4955 r'branch\..*\.%s' % issueprefix], 4950 r'branch\..*\.%s' % issueprefix],
4956 error_ok=True) 4951 error_ok=True)
4957 for key, issue in [x.split() for x in output.splitlines()]: 4952 for key, issue in [x.split() for x in output.splitlines()]:
4958 if issue == target_issue: 4953 if issue == target_issue:
4959 yield re.sub(r'branch\.(.*)\.%s' % issueprefix, r'\1', key) 4954 yield re.sub(r'branch\.(.*)\.%s' % issueprefix, r'\1', key)
4960 4955
4961 branches = [] 4956 branches = []
4962 for cls in _CODEREVIEW_IMPLEMENTATIONS.values(): 4957 for cls in _CODEREVIEW_IMPLEMENTATIONS.values():
4963 branches.extend(find_issues(cls.IssueSettingSuffix())) 4958 branches.extend(find_issues(cls.IssueSettingSuffix()))
4964 if len(branches) == 0: 4959 if len(branches) == 0:
4965 print 'No branch found for issue %s.' % target_issue 4960 print('No branch found for issue %s.' % target_issue)
4966 return 1 4961 return 1
4967 if len(branches) == 1: 4962 if len(branches) == 1:
4968 RunGit(['checkout', branches[0]]) 4963 RunGit(['checkout', branches[0]])
4969 else: 4964 else:
4970 print 'Multiple branches match issue %s:' % target_issue 4965 print('Multiple branches match issue %s:' % target_issue)
4971 for i in range(len(branches)): 4966 for i in range(len(branches)):
4972 print '%d: %s' % (i, branches[i]) 4967 print('%d: %s' % (i, branches[i]))
4973 which = raw_input('Choose by index: ') 4968 which = raw_input('Choose by index: ')
4974 try: 4969 try:
4975 RunGit(['checkout', branches[int(which)]]) 4970 RunGit(['checkout', branches[int(which)]])
4976 except (IndexError, ValueError): 4971 except (IndexError, ValueError):
4977 print 'Invalid selection, not checking out any branch.' 4972 print('Invalid selection, not checking out any branch.')
4978 return 1 4973 return 1
4979 4974
4980 return 0 4975 return 0
4981 4976
4982 4977
4983 def CMDlol(parser, args): 4978 def CMDlol(parser, args):
4984 # This command is intentionally undocumented. 4979 # This command is intentionally undocumented.
4985 print zlib.decompress(base64.b64decode( 4980 print(zlib.decompress(base64.b64decode(
4986 'eNptkLEOwyAMRHe+wupCIqW57v0Vq84WqWtXyrcXnCBsmgMJ+/SSAxMZgRB6NzE' 4981 'eNptkLEOwyAMRHe+wupCIqW57v0Vq84WqWtXyrcXnCBsmgMJ+/SSAxMZgRB6NzE'
4987 'E2ObgCKJooYdu4uAQVffUEoE1sRQLxAcqzd7uK2gmStrll1ucV3uZyaY5sXyDd9' 4982 'E2ObgCKJooYdu4uAQVffUEoE1sRQLxAcqzd7uK2gmStrll1ucV3uZyaY5sXyDd9'
4988 'JAnN+lAXsOMJ90GANAi43mq5/VeeacylKVgi8o6F1SC63FxnagHfJUTfUYdCR/W' 4983 'JAnN+lAXsOMJ90GANAi43mq5/VeeacylKVgi8o6F1SC63FxnagHfJUTfUYdCR/W'
4989 'Ofe+0dHL7PicpytKP750Fh1q2qnLVof4w8OZWNY')) 4984 'Ofe+0dHL7PicpytKP750Fh1q2qnLVof4w8OZWNY')))
4990 return 0 4985 return 0
4991 4986
4992 4987
4993 class OptionParser(optparse.OptionParser): 4988 class OptionParser(optparse.OptionParser):
4994 """Creates the option parse and add --verbose support.""" 4989 """Creates the option parse and add --verbose support."""
4995 def __init__(self, *args, **kwargs): 4990 def __init__(self, *args, **kwargs):
4996 optparse.OptionParser.__init__( 4991 optparse.OptionParser.__init__(
4997 self, *args, prog='git cl', version=__version__, **kwargs) 4992 self, *args, prog='git cl', version=__version__, **kwargs)
4998 self.add_option( 4993 self.add_option(
4999 '-v', '--verbose', action='count', default=0, 4994 '-v', '--verbose', action='count', default=0,
5000 help='Use 2 times for more debugging info') 4995 help='Use 2 times for more debugging info')
5001 4996
5002 def parse_args(self, args=None, values=None): 4997 def parse_args(self, args=None, values=None):
5003 options, args = optparse.OptionParser.parse_args(self, args, values) 4998 options, args = optparse.OptionParser.parse_args(self, args, values)
5004 levels = [logging.WARNING, logging.INFO, logging.DEBUG] 4999 levels = [logging.WARNING, logging.INFO, logging.DEBUG]
5005 logging.basicConfig(level=levels[min(options.verbose, len(levels) - 1)]) 5000 logging.basicConfig(level=levels[min(options.verbose, len(levels) - 1)])
5006 return options, args 5001 return options, args
5007 5002
5008 5003
5009 def main(argv): 5004 def main(argv):
5010 if sys.hexversion < 0x02060000: 5005 if sys.hexversion < 0x02060000:
5011 print >> sys.stderr, ( 5006 print('\nYour python version %s is unsupported, please upgrade.\n' %
5012 '\nYour python version %s is unsupported, please upgrade.\n' % 5007 (sys.version.split(' ', 1)[0],), file=sys.stderr)
5013 sys.version.split(' ', 1)[0])
5014 return 2 5008 return 2
5015 5009
5016 # Reload settings. 5010 # Reload settings.
5017 global settings 5011 global settings
5018 settings = Settings() 5012 settings = Settings()
5019 5013
5020 colorize_CMDstatus_doc() 5014 colorize_CMDstatus_doc()
5021 dispatcher = subcommand.CommandDispatcher(__name__) 5015 dispatcher = subcommand.CommandDispatcher(__name__)
5022 try: 5016 try:
5023 return dispatcher.execute(OptionParser(), argv) 5017 return dispatcher.execute(OptionParser(), argv)
(...skipping 11 matching lines...) Expand all
5035 if __name__ == '__main__': 5029 if __name__ == '__main__':
5036 # These affect sys.stdout so do it outside of main() to simplify mocks in 5030 # These affect sys.stdout so do it outside of main() to simplify mocks in
5037 # unit testing. 5031 # unit testing.
5038 fix_encoding.fix_encoding() 5032 fix_encoding.fix_encoding()
5039 setup_color.init() 5033 setup_color.init()
5040 try: 5034 try:
5041 sys.exit(main(sys.argv[1:])) 5035 sys.exit(main(sys.argv[1:]))
5042 except KeyboardInterrupt: 5036 except KeyboardInterrupt:
5043 sys.stderr.write('interrupted\n') 5037 sys.stderr.write('interrupted\n')
5044 sys.exit(1) 5038 sys.exit(1)
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698