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

Side by Side Diff: git_cl.py

Issue 157913005: Cleanup: Merge a bunch of redundent env['GIT_PAGER'] = 'cat' statements. (Closed) Base URL: svn://chrome-svn/chrome/trunk/tools/depot_tools/
Patch Set: clean more stuff Created 6 years, 10 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/git_cl_test.py » ('j') | 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.""" 8 """A git-command for integrating reviews on Rietveld."""
9 9
10 from distutils.version import LooseVersion 10 from distutils.version import LooseVersion
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
56 56
57 # Initialized in main() 57 # Initialized in main()
58 settings = None 58 settings = None
59 59
60 60
61 def DieWithError(message): 61 def DieWithError(message):
62 print >> sys.stderr, message 62 print >> sys.stderr, message
63 sys.exit(1) 63 sys.exit(1)
64 64
65 65
66 def GetNoGitPagerEnv():
67 env = os.environ.copy()
68 # 'cat' is a magical git string that disables pagers on all platforms.
69 env['GIT_PAGER'] = 'cat'
70 return env
71
66 def RunCommand(args, error_ok=False, error_message=None, **kwargs): 72 def RunCommand(args, error_ok=False, error_message=None, **kwargs):
67 try: 73 try:
68 return subprocess2.check_output(args, shell=False, **kwargs) 74 return subprocess2.check_output(args, shell=False, **kwargs)
69 except subprocess2.CalledProcessError as e: 75 except subprocess2.CalledProcessError as e:
70 logging.debug('Failed running %s', args) 76 logging.debug('Failed running %s', args)
71 if not error_ok: 77 if not error_ok:
72 DieWithError( 78 DieWithError(
73 'Command "%s" failed.\n%s' % ( 79 'Command "%s" failed.\n%s' % (
74 ' '.join(args), error_message or e.stdout or '')) 80 ' '.join(args), error_message or e.stdout or ''))
75 return e.stdout 81 return e.stdout
76 82
77 83
78 def RunGit(args, **kwargs): 84 def RunGit(args, **kwargs):
79 """Returns stdout.""" 85 """Returns stdout."""
80 return RunCommand(['git'] + args, **kwargs) 86 return RunCommand(['git'] + args, **kwargs)
81 87
82 88
83 def RunGitWithCode(args, suppress_stderr=False): 89 def RunGitWithCode(args, suppress_stderr=False):
84 """Returns return code and stdout.""" 90 """Returns return code and stdout."""
85 try: 91 try:
86 env = os.environ.copy()
87 # 'cat' is a magical git string that disables pagers on all platforms.
88 env['GIT_PAGER'] = 'cat'
89 if suppress_stderr: 92 if suppress_stderr:
90 stderr = subprocess2.VOID 93 stderr = subprocess2.VOID
91 else: 94 else:
92 stderr = sys.stderr 95 stderr = sys.stderr
93 out, code = subprocess2.communicate(['git'] + args, 96 out, code = subprocess2.communicate(['git'] + args,
94 env=env, 97 env=GetNoGitPagerEnv(),
95 stdout=subprocess2.PIPE, 98 stdout=subprocess2.PIPE,
96 stderr=stderr) 99 stderr=stderr)
97 return code, out[0] 100 return code, out[0]
98 except ValueError: 101 except ValueError:
99 # When the subprocess fails, it returns None. That triggers a ValueError 102 # When the subprocess fails, it returns None. That triggers a ValueError
100 # when trying to unpack the return value into (out, code). 103 # when trying to unpack the return value into (out, code).
101 return 1, '' 104 return 1, ''
102 105
103 106
104 def IsGitVersionAtLeast(min_version): 107 def IsGitVersionAtLeast(min_version):
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
232 if full_url == url: 235 if full_url == url:
233 return as_ref 236 return as_ref
234 return None 237 return None
235 238
236 239
237 def print_stats(similarity, find_copies, args): 240 def print_stats(similarity, find_copies, args):
238 """Prints statistics about the change to the user.""" 241 """Prints statistics about the change to the user."""
239 # --no-ext-diff is broken in some versions of Git, so try to work around 242 # --no-ext-diff is broken in some versions of Git, so try to work around
240 # this by overriding the environment (but there is still a problem if the 243 # this by overriding the environment (but there is still a problem if the
241 # git config key "diff.external" is used). 244 # git config key "diff.external" is used).
242 env = os.environ.copy() 245 env = GetNoGitPagerEnv()
243 if 'GIT_EXTERNAL_DIFF' in env: 246 if 'GIT_EXTERNAL_DIFF' in env:
244 del env['GIT_EXTERNAL_DIFF'] 247 del env['GIT_EXTERNAL_DIFF']
245 # 'cat' is a magical git string that disables pagers on all platforms.
246 env['GIT_PAGER'] = 'cat'
247 248
248 if find_copies: 249 if find_copies:
249 similarity_options = ['--find-copies-harder', '-l100000', 250 similarity_options = ['--find-copies-harder', '-l100000',
250 '-C%s' % similarity] 251 '-C%s' % similarity]
251 else: 252 else:
252 similarity_options = ['-M%s' % similarity] 253 similarity_options = ['-M%s' % similarity]
253 254
254 return subprocess2.call( 255 return subprocess2.call(
255 ['git', 256 ['git',
256 'diff', '--no-ext-diff', '--stat'] + similarity_options + args, 257 'diff', '--no-ext-diff', '--stat'] + similarity_options + args,
257 env=env) 258 env=env)
258 259
259 260
260 class Settings(object): 261 class Settings(object):
261 def __init__(self): 262 def __init__(self):
262 self.default_server = None 263 self.default_server = None
263 self.cc = None 264 self.cc = None
264 self.root = None 265 self.relative_root = None
265 self.is_git_svn = None 266 self.is_git_svn = None
266 self.svn_branch = None 267 self.svn_branch = None
267 self.tree_status_url = None 268 self.tree_status_url = None
268 self.viewvc_url = None 269 self.viewvc_url = None
269 self.updated = False 270 self.updated = False
270 self.is_gerrit = None 271 self.is_gerrit = None
271 self.git_editor = None 272 self.git_editor = None
272 273
273 def LazyUpdateIfNeeded(self): 274 def LazyUpdateIfNeeded(self):
274 """Updates the settings from a codereview.settings file, if available.""" 275 """Updates the settings from a codereview.settings file, if available."""
(...skipping 10 matching lines...) Expand all
285 # set updated to True to avoid infinite calling loop 286 # set updated to True to avoid infinite calling loop
286 # through DownloadHooks 287 # through DownloadHooks
287 self.updated = True 288 self.updated = True
288 DownloadHooks(False) 289 DownloadHooks(False)
289 self.updated = True 290 self.updated = True
290 291
291 def GetDefaultServerUrl(self, error_ok=False): 292 def GetDefaultServerUrl(self, error_ok=False):
292 if not self.default_server: 293 if not self.default_server:
293 self.LazyUpdateIfNeeded() 294 self.LazyUpdateIfNeeded()
294 self.default_server = gclient_utils.UpgradeToHttps( 295 self.default_server = gclient_utils.UpgradeToHttps(
295 self._GetConfig('rietveld.server', error_ok=True)) 296 self._GetRietveldConfig('server', error_ok=True))
296 if error_ok: 297 if error_ok:
297 return self.default_server 298 return self.default_server
298 if not self.default_server: 299 if not self.default_server:
299 error_message = ('Could not find settings file. You must configure ' 300 error_message = ('Could not find settings file. You must configure '
300 'your review setup by running "git cl config".') 301 'your review setup by running "git cl config".')
301 self.default_server = gclient_utils.UpgradeToHttps( 302 self.default_server = gclient_utils.UpgradeToHttps(
302 self._GetConfig('rietveld.server', error_message=error_message)) 303 self._GetRietveldConfig('server', error_message=error_message))
303 return self.default_server 304 return self.default_server
304 305
306 def GetRelativeRoot(self):
307 if self.relative_root is None:
308 self.relative_root = RunGit(['rev-parse', '--show-cdup']).strip()
309 return self.relative_root
310
305 def GetRoot(self): 311 def GetRoot(self):
306 if not self.root: 312 return os.path.abspath(self.GetRelativeRoot())
307 self.root = os.path.abspath(RunGit(['rev-parse', '--show-cdup']).strip())
308 return self.root
309 313
310 def GetIsGitSvn(self): 314 def GetIsGitSvn(self):
311 """Return true if this repo looks like it's using git-svn.""" 315 """Return true if this repo looks like it's using git-svn."""
312 if self.is_git_svn is None: 316 if self.is_git_svn is None:
313 # If you have any "svn-remote.*" config keys, we think you're using svn. 317 # If you have any "svn-remote.*" config keys, we think you're using svn.
314 self.is_git_svn = RunGitWithCode( 318 self.is_git_svn = RunGitWithCode(
315 ['config', '--local', '--get-regexp', r'^svn-remote\.'])[0] == 0 319 ['config', '--local', '--get-regexp', r'^svn-remote\.'])[0] == 0
316 return self.is_git_svn 320 return self.is_git_svn
317 321
318 def GetSVNBranch(self): 322 def GetSVNBranch(self):
319 if self.svn_branch is None: 323 if self.svn_branch is None:
320 if not self.GetIsGitSvn(): 324 if not self.GetIsGitSvn():
321 DieWithError('Repo doesn\'t appear to be a git-svn repo.') 325 DieWithError('Repo doesn\'t appear to be a git-svn repo.')
322 326
323 # Try to figure out which remote branch we're based on. 327 # Try to figure out which remote branch we're based on.
324 # Strategy: 328 # Strategy:
325 # 1) iterate through our branch history and find the svn URL. 329 # 1) iterate through our branch history and find the svn URL.
326 # 2) find the svn-remote that fetches from the URL. 330 # 2) find the svn-remote that fetches from the URL.
327 331
328 # regexp matching the git-svn line that contains the URL. 332 # regexp matching the git-svn line that contains the URL.
329 git_svn_re = re.compile(r'^\s*git-svn-id: (\S+)@', re.MULTILINE) 333 git_svn_re = re.compile(r'^\s*git-svn-id: (\S+)@', re.MULTILINE)
330 334
331 env = os.environ.copy()
332 # 'cat' is a magical git string that disables pagers on all platforms.
333 env['GIT_PAGER'] = 'cat'
334
335 # We don't want to go through all of history, so read a line from the 335 # We don't want to go through all of history, so read a line from the
336 # pipe at a time. 336 # pipe at a time.
337 # The -100 is an arbitrary limit so we don't search forever. 337 # The -100 is an arbitrary limit so we don't search forever.
338 cmd = ['git', 'log', '-100', '--pretty=medium'] 338 cmd = ['git', 'log', '-100', '--pretty=medium']
339 proc = subprocess2.Popen(cmd, stdout=subprocess2.PIPE, env=env) 339 proc = subprocess2.Popen(cmd, stdout=subprocess2.PIPE,
340 env=GetNoGitPagerEnv())
340 url = None 341 url = None
341 for line in proc.stdout: 342 for line in proc.stdout:
342 match = git_svn_re.match(line) 343 match = git_svn_re.match(line)
343 if match: 344 if match:
344 url = match.group(1) 345 url = match.group(1)
345 proc.stdout.close() # Cut pipe. 346 proc.stdout.close() # Cut pipe.
346 break 347 break
347 348
348 if url: 349 if url:
349 svn_remote_re = re.compile(r'^svn-remote\.([^.]+)\.url (.*)$') 350 svn_remote_re = re.compile(r'^svn-remote\.([^.]+)\.url (.*)$')
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
384 if not self.svn_branch: 385 if not self.svn_branch:
385 DieWithError('Can\'t guess svn branch -- try specifying it on the ' 386 DieWithError('Can\'t guess svn branch -- try specifying it on the '
386 'command line') 387 'command line')
387 388
388 return self.svn_branch 389 return self.svn_branch
389 390
390 def GetTreeStatusUrl(self, error_ok=False): 391 def GetTreeStatusUrl(self, error_ok=False):
391 if not self.tree_status_url: 392 if not self.tree_status_url:
392 error_message = ('You must configure your tree status URL by running ' 393 error_message = ('You must configure your tree status URL by running '
393 '"git cl config".') 394 '"git cl config".')
394 self.tree_status_url = self._GetConfig('rietveld.tree-status-url', 395 self.tree_status_url = self._GetRietveldConfig(
395 error_ok=error_ok, 396 'tree-status-url', error_ok=error_ok, error_message=error_message)
396 error_message=error_message)
397 return self.tree_status_url 397 return self.tree_status_url
398 398
399 def GetViewVCUrl(self): 399 def GetViewVCUrl(self):
400 if not self.viewvc_url: 400 if not self.viewvc_url:
401 self.viewvc_url = self._GetConfig('rietveld.viewvc-url', error_ok=True) 401 self.viewvc_url = self._GetRietveldConfig('viewvc-url', error_ok=True)
402 return self.viewvc_url 402 return self.viewvc_url
403 403
404 def GetBugPrefix(self): 404 def GetBugPrefix(self):
405 return self._GetConfig('rietveld.bug-prefix', error_ok=True) 405 return self._GetRietveldConfig('bug-prefix', error_ok=True)
406 406
407 def GetDefaultCCList(self): 407 def GetDefaultCCList(self):
408 return self._GetConfig('rietveld.cc', error_ok=True) 408 return self._GetRietveldConfig('cc', error_ok=True)
409 409
410 def GetDefaultPrivateFlag(self): 410 def GetDefaultPrivateFlag(self):
411 return self._GetConfig('rietveld.private', error_ok=True) 411 return self._GetRietveldConfig('private', error_ok=True)
412 412
413 def GetIsGerrit(self): 413 def GetIsGerrit(self):
414 """Return true if this repo is assosiated with gerrit code review system.""" 414 """Return true if this repo is assosiated with gerrit code review system."""
415 if self.is_gerrit is None: 415 if self.is_gerrit is None:
416 self.is_gerrit = self._GetConfig('gerrit.host', error_ok=True) 416 self.is_gerrit = self._GetConfig('gerrit.host', error_ok=True)
417 return self.is_gerrit 417 return self.is_gerrit
418 418
419 def GetGitEditor(self): 419 def GetGitEditor(self):
420 """Return the editor specified in the git config, or None if none is.""" 420 """Return the editor specified in the git config, or None if none is."""
421 if self.git_editor is None: 421 if self.git_editor is None:
422 self.git_editor = self._GetConfig('core.editor', error_ok=True) 422 self.git_editor = self._GetConfig('core.editor', error_ok=True)
423 return self.git_editor or None 423 return self.git_editor or None
424 424
425 def _GetRietveldConfig(self, param, **kwargs):
426 return self._GetConfig('rietveld.' + param, **kwargs)
427
425 def _GetConfig(self, param, **kwargs): 428 def _GetConfig(self, param, **kwargs):
426 self.LazyUpdateIfNeeded() 429 self.LazyUpdateIfNeeded()
427 return RunGit(['config', param], **kwargs).strip() 430 return RunGit(['config', param], **kwargs).strip()
428 431
429 432
430 def ShortBranchName(branch): 433 def ShortBranchName(branch):
431 """Convert a name like 'refs/heads/foo' to just 'foo'.""" 434 """Convert a name like 'refs/heads/foo' to just 'foo'."""
432 return branch.replace('refs/heads/', '') 435 return branch.replace('refs/heads/', '')
433 436
434 437
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
527 upstream_branch = 'refs/heads/trunk' 530 upstream_branch = 'refs/heads/trunk'
528 else: 531 else:
529 DieWithError("""Unable to determine default branch to diff against. 532 DieWithError("""Unable to determine default branch to diff against.
530 Either pass complete "git diff"-style arguments, like 533 Either pass complete "git diff"-style arguments, like
531 git cl upload origin/master 534 git cl upload origin/master
532 or verify this branch is set up to track another (via the --track argument to 535 or verify this branch is set up to track another (via the --track argument to
533 "git checkout -b ...").""") 536 "git checkout -b ...").""")
534 537
535 return remote, upstream_branch 538 return remote, upstream_branch
536 539
540 def GetCommonAncestorWithUpstream(self):
541 return RunGit(['merge-base', self.GetUpstreamBranch(), 'HEAD']).strip()
542
537 def GetUpstreamBranch(self): 543 def GetUpstreamBranch(self):
538 if self.upstream_branch is None: 544 if self.upstream_branch is None:
539 remote, upstream_branch = self.FetchUpstreamTuple(self.GetBranch()) 545 remote, upstream_branch = self.FetchUpstreamTuple(self.GetBranch())
540 if remote is not '.': 546 if remote is not '.':
541 upstream_branch = upstream_branch.replace('heads', 'remotes/' + remote) 547 upstream_branch = upstream_branch.replace('heads', 'remotes/' + remote)
542 self.upstream_branch = upstream_branch 548 self.upstream_branch = upstream_branch
543 return self.upstream_branch 549 return self.upstream_branch
544 550
545 def GetRemoteBranch(self): 551 def GetRemoteBranch(self):
546 if not self._remote: 552 if not self._remote:
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
728 current_issue = self.GetIssue() 734 current_issue = self.GetIssue()
729 if current_issue: 735 if current_issue:
730 RunGit(['config', '--unset', self._IssueSetting()]) 736 RunGit(['config', '--unset', self._IssueSetting()])
731 self.issue = None 737 self.issue = None
732 self.SetPatchset(None) 738 self.SetPatchset(None)
733 739
734 def GetChange(self, upstream_branch, author): 740 def GetChange(self, upstream_branch, author):
735 if not self.GitSanityChecks(upstream_branch): 741 if not self.GitSanityChecks(upstream_branch):
736 DieWithError('\nGit sanity check failure') 742 DieWithError('\nGit sanity check failure')
737 743
738 env = os.environ.copy() 744 root = settings.GetRelativeRoot()
739 # 'cat' is a magical git string that disables pagers on all platforms.
740 env['GIT_PAGER'] = 'cat'
741
742 root = RunCommand(['git', 'rev-parse', '--show-cdup'], env=env).strip()
743 if not root: 745 if not root:
744 root = '.' 746 root = '.'
745 absroot = os.path.abspath(root) 747 absroot = os.path.abspath(root)
746 748
747 # We use the sha1 of HEAD as a name of this change. 749 # We use the sha1 of HEAD as a name of this change.
748 name = RunCommand(['git', 'rev-parse', 'HEAD'], env=env).strip() 750 name = RunGitWithCode(['rev-parse', 'HEAD'])[1].strip()
749 # Need to pass a relative path for msysgit. 751 # Need to pass a relative path for msysgit.
750 try: 752 try:
751 files = scm.GIT.CaptureStatus([root], '.', upstream_branch) 753 files = scm.GIT.CaptureStatus([root], '.', upstream_branch)
752 except subprocess2.CalledProcessError: 754 except subprocess2.CalledProcessError:
753 DieWithError( 755 DieWithError(
754 ('\nFailed to diff against upstream branch %s\n\n' 756 ('\nFailed to diff against upstream branch %s\n\n'
755 'This branch probably doesn\'t exist anymore. To reset the\n' 757 'This branch probably doesn\'t exist anymore. To reset the\n'
756 'tracking branch, please run\n' 758 'tracking branch, please run\n'
757 ' git branch --set-upstream %s trunk\n' 759 ' git branch --set-upstream %s trunk\n'
758 'replacing trunk with origin/master or the relevant branch') % 760 'replacing trunk with origin/master or the relevant branch') %
759 (upstream_branch, self.GetBranch())) 761 (upstream_branch, self.GetBranch()))
760 762
761 issue = self.GetIssue() 763 issue = self.GetIssue()
762 patchset = self.GetPatchset() 764 patchset = self.GetPatchset()
763 if issue: 765 if issue:
764 description = self.GetDescription() 766 description = self.GetDescription()
765 else: 767 else:
766 # If the change was never uploaded, use the log messages of all commits 768 # If the change was never uploaded, use the log messages of all commits
767 # up to the branch point, as git cl upload will prefill the description 769 # up to the branch point, as git cl upload will prefill the description
768 # with these log messages. 770 # with these log messages.
769 description = RunCommand(['git', 771 args = ['log', '--pretty=format:%s%n%n%b', '%s...' % (upstream_branch)]
770 'log', '--pretty=format:%s%n%n%b', 772 description = RunGitWithCode(args)[1].strip()
771 '%s...' % (upstream_branch)],
772 env=env).strip()
773 773
774 if not author: 774 if not author:
775 author = RunGit(['config', 'user.email']).strip() or None 775 author = RunGit(['config', 'user.email']).strip() or None
776 return presubmit_support.GitChange( 776 return presubmit_support.GitChange(
777 name, 777 name,
778 description, 778 description,
779 absroot, 779 absroot,
780 files, 780 files,
781 issue, 781 issue,
782 patchset, 782 patchset,
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
1005 1005
1006 1006
1007 def FindCodereviewSettingsFile(filename='codereview.settings'): 1007 def FindCodereviewSettingsFile(filename='codereview.settings'):
1008 """Finds the given file starting in the cwd and going up. 1008 """Finds the given file starting in the cwd and going up.
1009 1009
1010 Only looks up to the top of the repository unless an 1010 Only looks up to the top of the repository unless an
1011 'inherit-review-settings-ok' file exists in the root of the repository. 1011 'inherit-review-settings-ok' file exists in the root of the repository.
1012 """ 1012 """
1013 inherit_ok_file = 'inherit-review-settings-ok' 1013 inherit_ok_file = 'inherit-review-settings-ok'
1014 cwd = os.getcwd() 1014 cwd = os.getcwd()
1015 root = os.path.abspath(RunGit(['rev-parse', '--show-cdup']).strip()) 1015 root = settings.GetRoot()
1016 if os.path.isfile(os.path.join(root, inherit_ok_file)): 1016 if os.path.isfile(os.path.join(root, inherit_ok_file)):
1017 root = '/' 1017 root = '/'
1018 while True: 1018 while True:
1019 if filename in os.listdir(cwd): 1019 if filename in os.listdir(cwd):
1020 if os.path.isfile(os.path.join(cwd, filename)): 1020 if os.path.isfile(os.path.join(cwd, filename)):
1021 return open(os.path.join(cwd, filename)) 1021 return open(os.path.join(cwd, filename))
1022 if cwd == root: 1022 if cwd == root:
1023 break 1023 break
1024 cwd = os.path.dirname(cwd) 1024 cwd = os.path.dirname(cwd)
1025 1025
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after
1375 1375
1376 if not options.force and is_dirty_git_tree('presubmit'): 1376 if not options.force and is_dirty_git_tree('presubmit'):
1377 print 'use --force to check even if tree is dirty.' 1377 print 'use --force to check even if tree is dirty.'
1378 return 1 1378 return 1
1379 1379
1380 cl = Changelist() 1380 cl = Changelist()
1381 if args: 1381 if args:
1382 base_branch = args[0] 1382 base_branch = args[0]
1383 else: 1383 else:
1384 # Default to diffing against the common ancestor of the upstream branch. 1384 # Default to diffing against the common ancestor of the upstream branch.
1385 base_branch = RunGit(['merge-base', cl.GetUpstreamBranch(), 'HEAD']).strip() 1385 base_branch = cl.GetCommonAncestorWithUpstream()
1386 1386
1387 cl.RunHook( 1387 cl.RunHook(
1388 committing=not options.upload, 1388 committing=not options.upload,
1389 may_prompt=False, 1389 may_prompt=False,
1390 verbose=options.verbose, 1390 verbose=options.verbose,
1391 change=cl.GetChange(base_branch, None)) 1391 change=cl.GetChange(base_branch, None))
1392 return 0 1392 return 0
1393 1393
1394 1394
1395 def AddChangeIdToCommitMessage(options, args): 1395 def AddChangeIdToCommitMessage(options, args):
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after
1611 1611
1612 options.reviewers = cleanup_list(options.reviewers) 1612 options.reviewers = cleanup_list(options.reviewers)
1613 options.cc = cleanup_list(options.cc) 1613 options.cc = cleanup_list(options.cc)
1614 1614
1615 cl = Changelist() 1615 cl = Changelist()
1616 if args: 1616 if args:
1617 # TODO(ukai): is it ok for gerrit case? 1617 # TODO(ukai): is it ok for gerrit case?
1618 base_branch = args[0] 1618 base_branch = args[0]
1619 else: 1619 else:
1620 # Default to diffing against common ancestor of upstream branch 1620 # Default to diffing against common ancestor of upstream branch
1621 base_branch = RunGit(['merge-base', cl.GetUpstreamBranch(), 'HEAD']).strip() 1621 base_branch = cl.GetCommonAncestorWithUpstream()
1622 args = [base_branch, 'HEAD'] 1622 args = [base_branch, 'HEAD']
1623 1623
1624 # Apply watchlists on upload. 1624 # Apply watchlists on upload.
1625 change = cl.GetChange(base_branch, None) 1625 change = cl.GetChange(base_branch, None)
1626 watchlist = watchlists.Watchlists(change.RepositoryRoot()) 1626 watchlist = watchlists.Watchlists(change.RepositoryRoot())
1627 files = [f.LocalPath() for f in change.AffectedFiles()] 1627 files = [f.LocalPath() for f in change.AffectedFiles()]
1628 if not options.bypass_watchlists: 1628 if not options.bypass_watchlists:
1629 cl.SetWatchers(watchlist.GetWatchersForPaths(files)) 1629 cl.SetWatchers(watchlist.GetWatchersForPaths(files))
1630 1630
1631 if not options.bypass_hooks: 1631 if not options.bypass_hooks:
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after
1808 # Delete the branches if they exist. 1808 # Delete the branches if they exist.
1809 for branch in [MERGE_BRANCH, CHERRY_PICK_BRANCH]: 1809 for branch in [MERGE_BRANCH, CHERRY_PICK_BRANCH]:
1810 showref_cmd = ['show-ref', '--quiet', '--verify', 'refs/heads/%s' % branch] 1810 showref_cmd = ['show-ref', '--quiet', '--verify', 'refs/heads/%s' % branch]
1811 result = RunGitWithCode(showref_cmd) 1811 result = RunGitWithCode(showref_cmd)
1812 if result[0] == 0: 1812 if result[0] == 0:
1813 RunGit(['branch', '-D', branch]) 1813 RunGit(['branch', '-D', branch])
1814 1814
1815 # We might be in a directory that's present in this branch but not in the 1815 # We might be in a directory that's present in this branch but not in the
1816 # trunk. Move up to the top of the tree so that git commands that expect a 1816 # trunk. Move up to the top of the tree so that git commands that expect a
1817 # valid CWD won't fail after we check out the merge branch. 1817 # valid CWD won't fail after we check out the merge branch.
1818 rel_base_path = RunGit(['rev-parse', '--show-cdup']).strip() 1818 rel_base_path = settings.GetRelativeRoot()
1819 if rel_base_path: 1819 if rel_base_path:
1820 os.chdir(rel_base_path) 1820 os.chdir(rel_base_path)
1821 1821
1822 # Stuff our change into the merge branch. 1822 # Stuff our change into the merge branch.
1823 # We wrap in a try...finally block so if anything goes wrong, 1823 # We wrap in a try...finally block so if anything goes wrong,
1824 # we clean up the branches. 1824 # we clean up the branches.
1825 retcode = -1 1825 retcode = -1
1826 try: 1826 try:
1827 RunGit(['checkout', '-q', '-b', MERGE_BRANCH]) 1827 RunGit(['checkout', '-q', '-b', MERGE_BRANCH])
1828 RunGit(['reset', '--soft', base_branch]) 1828 RunGit(['reset', '--soft', base_branch])
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
1971 match = re.match(r'.*?/issue(\d+)_(\d+).diff', issue_url) 1971 match = re.match(r'.*?/issue(\d+)_(\d+).diff', issue_url)
1972 if not match: 1972 if not match:
1973 DieWithError('Must pass an issue ID or full URL for ' 1973 DieWithError('Must pass an issue ID or full URL for '
1974 '\'Download raw patch set\'') 1974 '\'Download raw patch set\'')
1975 issue = int(match.group(1)) 1975 issue = int(match.group(1))
1976 patchset = int(match.group(2)) 1976 patchset = int(match.group(2))
1977 patch_data = urllib2.urlopen(issue_arg).read() 1977 patch_data = urllib2.urlopen(issue_arg).read()
1978 1978
1979 # Switch up to the top-level directory, if necessary, in preparation for 1979 # Switch up to the top-level directory, if necessary, in preparation for
1980 # applying the patch. 1980 # applying the patch.
1981 top = RunGit(['rev-parse', '--show-cdup']).strip() 1981 top = settings.GetRelativeRoot()
1982 if top: 1982 if top:
1983 os.chdir(top) 1983 os.chdir(top)
1984 1984
1985 # Git patches have a/ at the beginning of source paths. We strip that out 1985 # Git patches have a/ at the beginning of source paths. We strip that out
1986 # with a sed script rather than the -p flag to patch so we can feed either 1986 # with a sed script rather than the -p flag to patch so we can feed either
1987 # Git or svn-style patches into the same apply command. 1987 # Git or svn-style patches into the same apply command.
1988 # re.sub() should be used but flags=re.MULTILINE is only in python 2.7. 1988 # re.sub() should be used but flags=re.MULTILINE is only in python 2.7.
1989 try: 1989 try:
1990 patch_data = subprocess2.check_output( 1990 patch_data = subprocess2.check_output(
1991 ['sed', '-e', 's|^--- a/|--- |; s|^+++ b/|+++ |'], stdin=patch_data) 1991 ['sed', '-e', 's|^--- a/|--- |; s|^+++ b/|+++ |'], stdin=patch_data)
1992 except subprocess2.CalledProcessError: 1992 except subprocess2.CalledProcessError:
1993 DieWithError('Git patch mungling failed.') 1993 DieWithError('Git patch mungling failed.')
1994 logging.info(patch_data) 1994 logging.info(patch_data)
1995 env = os.environ.copy()
1996 # 'cat' is a magical git string that disables pagers on all platforms.
1997 env['GIT_PAGER'] = 'cat'
1998 1995
1999 # We use "git apply" to apply the patch instead of "patch" so that we can 1996 # We use "git apply" to apply the patch instead of "patch" so that we can
2000 # pick up file adds. 1997 # pick up file adds.
2001 # The --index flag means: also insert into the index (so we catch adds). 1998 # The --index flag means: also insert into the index (so we catch adds).
2002 cmd = ['git', 'apply', '--index', '-p0'] 1999 cmd = ['git', 'apply', '--index', '-p0']
2003 if directory: 2000 if directory:
2004 cmd.extend(('--directory', directory)) 2001 cmd.extend(('--directory', directory))
2005 if reject: 2002 if reject:
2006 cmd.append('--reject') 2003 cmd.append('--reject')
2007 elif IsGitVersionAtLeast('1.7.12'): 2004 elif IsGitVersionAtLeast('1.7.12'):
2008 cmd.append('--3way') 2005 cmd.append('--3way')
2009 try: 2006 try:
2010 subprocess2.check_call(cmd, env=env, 2007 subprocess2.check_call(cmd, env=GetNoGitPagerEnv(),
2011 stdin=patch_data, stdout=subprocess2.VOID) 2008 stdin=patch_data, stdout=subprocess2.VOID)
2012 except subprocess2.CalledProcessError: 2009 except subprocess2.CalledProcessError:
2013 DieWithError('Failed to apply the patch') 2010 DieWithError('Failed to apply the patch')
2014 2011
2015 # If we had an issue, commit the current state and register the issue. 2012 # If we had an issue, commit the current state and register the issue.
2016 if not nocommit: 2013 if not nocommit:
2017 RunGit(['commit', '-m', 'patch from issue %s' % issue]) 2014 RunGit(['commit', '-m', 'patch from issue %s' % issue])
2018 cl = Changelist() 2015 cl = Changelist()
2019 cl.SetIssue(issue) 2016 cl.SetIssue(issue)
2020 cl.SetPatchset(patchset) 2017 cl.SetPatchset(patchset)
2021 print "Committed patch locally." 2018 print "Committed patch locally."
2022 else: 2019 else:
2023 print "Patch applied to index." 2020 print "Patch applied to index."
2024 return 0 2021 return 0
2025 2022
2026 2023
2027 def CMDrebase(parser, args): 2024 def CMDrebase(parser, args):
2028 """Rebases current branch on top of svn repo.""" 2025 """Rebases current branch on top of svn repo."""
2029 # Provide a wrapper for git svn rebase to help avoid accidental 2026 # Provide a wrapper for git svn rebase to help avoid accidental
2030 # git svn dcommit. 2027 # git svn dcommit.
2031 # It's the only command that doesn't use parser at all since we just defer 2028 # It's the only command that doesn't use parser at all since we just defer
2032 # execution to git-svn. 2029 # execution to git-svn.
2033 env = os.environ.copy()
2034 # 'cat' is a magical git string that disables pagers on all platforms.
2035 env['GIT_PAGER'] = 'cat'
2036 2030
2037 return subprocess2.call(['git', 'svn', 'rebase'] + args, env=env) 2031 return RunGitWithCode(['svn', 'rebase'] + args)[1]
2038 2032
2039 2033
2040 def GetTreeStatus(url=None): 2034 def GetTreeStatus(url=None):
2041 """Fetches the tree status and returns either 'open', 'closed', 2035 """Fetches the tree status and returns either 'open', 'closed',
2042 'unknown' or 'unset'.""" 2036 'unknown' or 'unset'."""
2043 url = url or settings.GetTreeStatusUrl(error_ok=True) 2037 url = url or settings.GetTreeStatusUrl(error_ok=True)
2044 if url: 2038 if url:
2045 status = urllib2.urlopen(url).read().lower() 2039 status = urllib2.urlopen(url).read().lower()
2046 if status.find('closed') != -1 or status == '0': 2040 if status.find('closed') != -1 or status == '0':
2047 return 'closed' 2041 return 'closed'
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
2118 cl = Changelist() 2112 cl = Changelist()
2119 if not cl.GetIssue(): 2113 if not cl.GetIssue():
2120 parser.error('Need to upload first') 2114 parser.error('Need to upload first')
2121 2115
2122 if not options.name: 2116 if not options.name:
2123 options.name = cl.GetBranch() 2117 options.name = cl.GetBranch()
2124 2118
2125 # Process --bot and --testfilter. 2119 # Process --bot and --testfilter.
2126 if not options.bot: 2120 if not options.bot:
2127 # Get try slaves from PRESUBMIT.py files if not specified. 2121 # Get try slaves from PRESUBMIT.py files if not specified.
2128 change = cl.GetChange( 2122 change = cl.GetChange(cl.GetCommonAncestorWithUpstream(), None)
2129 RunGit(['merge-base', cl.GetUpstreamBranch(), 'HEAD']).strip(),
2130 None)
2131 options.bot = presubmit_support.DoGetTrySlaves( 2123 options.bot = presubmit_support.DoGetTrySlaves(
2132 change, 2124 change,
2133 change.LocalPaths(), 2125 change.LocalPaths(),
2134 settings.GetRoot(), 2126 settings.GetRoot(),
2135 None, 2127 None,
2136 None, 2128 None,
2137 options.verbose, 2129 options.verbose,
2138 sys.stdout) 2130 sys.stdout)
2139 if not options.bot: 2131 if not options.bot:
2140 parser.error('No default try builder to try, use --bot') 2132 parser.error('No default try builder to try, use --bot')
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
2247 2239
2248 2240
2249 def CMDdiff(parser, args): 2241 def CMDdiff(parser, args):
2250 """shows differences between local tree and last upload.""" 2242 """shows differences between local tree and last upload."""
2251 cl = Changelist() 2243 cl = Changelist()
2252 issue = cl.GetIssue() 2244 issue = cl.GetIssue()
2253 branch = cl.GetBranch() 2245 branch = cl.GetBranch()
2254 if not issue: 2246 if not issue:
2255 DieWithError('No issue found for current branch (%s)' % branch) 2247 DieWithError('No issue found for current branch (%s)' % branch)
2256 TMP_BRANCH = 'git-cl-diff' 2248 TMP_BRANCH = 'git-cl-diff'
2257 base_branch = RunGit(['merge-base', cl.GetUpstreamBranch(), 'HEAD']).strip() 2249 base_branch = cl.GetCommonAncestorWithUpstream()
2258 2250
2259 # Create a new branch based on the merge-base 2251 # Create a new branch based on the merge-base
2260 RunGit(['checkout', '-q', '-b', TMP_BRANCH, base_branch]) 2252 RunGit(['checkout', '-q', '-b', TMP_BRANCH, base_branch])
2261 try: 2253 try:
2262 # Patch in the latest changes from rietveld. 2254 # Patch in the latest changes from rietveld.
2263 rtn = PatchIssue(issue, False, False, None) 2255 rtn = PatchIssue(issue, False, False, None)
2264 if rtn != 0: 2256 if rtn != 0:
2265 return rtn 2257 return rtn
2266 2258
2267 # Switch back to starting brand and diff against the temporary 2259 # Switch back to starting brand and diff against the temporary
(...skipping 17 matching lines...) Expand all
2285 author = RunGit(['config', 'user.email']).strip() or None 2277 author = RunGit(['config', 'user.email']).strip() or None
2286 2278
2287 cl = Changelist() 2279 cl = Changelist()
2288 2280
2289 if args: 2281 if args:
2290 if len(args) > 1: 2282 if len(args) > 1:
2291 parser.error('Unknown args') 2283 parser.error('Unknown args')
2292 base_branch = args[0] 2284 base_branch = args[0]
2293 else: 2285 else:
2294 # Default to diffing against the common ancestor of the upstream branch. 2286 # Default to diffing against the common ancestor of the upstream branch.
2295 base_branch = RunGit(['merge-base', cl.GetUpstreamBranch(), 'HEAD']).strip() 2287 base_branch = cl.GetCommonAncestorWithUpstream()
2296 2288
2297 change = cl.GetChange(base_branch, None) 2289 change = cl.GetChange(base_branch, None)
2298 return owners_finder.OwnersFinder( 2290 return owners_finder.OwnersFinder(
2299 [f.LocalPath() for f in 2291 [f.LocalPath() for f in
2300 cl.GetChange(base_branch, None).AffectedFiles()], 2292 cl.GetChange(base_branch, None).AffectedFiles()],
2301 change.RepositoryRoot(), author, 2293 change.RepositoryRoot(), author,
2302 fopen=file, os_path=os.path, glob=glob.glob, 2294 fopen=file, os_path=os.path, glob=glob.glob,
2303 disable_color=options.no_color).run() 2295 disable_color=options.no_color).run()
2304 2296
2305 2297
2306 @subcommand.usage('[files or directories to diff]') 2298 @subcommand.usage('[files or directories to diff]')
2307 def CMDformat(parser, args): 2299 def CMDformat(parser, args):
2308 """Runs clang-format on the diff.""" 2300 """Runs clang-format on the diff."""
2309 CLANG_EXTS = ['.cc', '.cpp', '.h', '.mm'] 2301 CLANG_EXTS = ['.cc', '.cpp', '.h', '.mm']
2310 parser.add_option('--full', action='store_true', 2302 parser.add_option('--full', action='store_true',
2311 help='Reformat the full content of all touched files') 2303 help='Reformat the full content of all touched files')
2312 parser.add_option('--dry-run', action='store_true', 2304 parser.add_option('--dry-run', action='store_true',
2313 help='Don\'t modify any file on disk.') 2305 help='Don\'t modify any file on disk.')
2314 opts, args = parser.parse_args(args) 2306 opts, args = parser.parse_args(args)
2315 2307
2316 # git diff generates paths against the root of the repository. Change 2308 # git diff generates paths against the root of the repository. Change
2317 # to that directory so clang-format can find files even within subdirs. 2309 # to that directory so clang-format can find files even within subdirs.
2318 rel_base_path = RunGit(['rev-parse', '--show-cdup']).strip() 2310 rel_base_path = settings.GetRelativeRoot()
2319 if rel_base_path: 2311 if rel_base_path:
2320 os.chdir(rel_base_path) 2312 os.chdir(rel_base_path)
2321 2313
2322 # Generate diff for the current branch's changes. 2314 # Generate diff for the current branch's changes.
2323 diff_cmd = ['diff', '--no-ext-diff', '--no-prefix'] 2315 diff_cmd = ['diff', '--no-ext-diff', '--no-prefix']
2324 if opts.full: 2316 if opts.full:
2325 # Only list the names of modified files. 2317 # Only list the names of modified files.
2326 diff_cmd.append('--name-only') 2318 diff_cmd.append('--name-only')
2327 else: 2319 else:
2328 # Only generate context-less patches. 2320 # Only generate context-less patches.
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
2437 ('AppEngine is misbehaving and returned HTTP %d, again. Keep faith ' 2429 ('AppEngine is misbehaving and returned HTTP %d, again. Keep faith '
2438 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) 2430 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e)))
2439 2431
2440 2432
2441 if __name__ == '__main__': 2433 if __name__ == '__main__':
2442 # These affect sys.stdout so do it outside of main() to simplify mocks in 2434 # These affect sys.stdout so do it outside of main() to simplify mocks in
2443 # unit testing. 2435 # unit testing.
2444 fix_encoding.fix_encoding() 2436 fix_encoding.fix_encoding()
2445 colorama.init() 2437 colorama.init()
2446 sys.exit(main(sys.argv[1:])) 2438 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « no previous file | tests/git_cl_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698