| OLD | NEW |
| 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 import json | 10 import json |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 58 logging.debug('Failed running %s', args) | 58 logging.debug('Failed running %s', args) |
| 59 if not error_ok: | 59 if not error_ok: |
| 60 DieWithError( | 60 DieWithError( |
| 61 'Command "%s" failed.\n%s' % ( | 61 'Command "%s" failed.\n%s' % ( |
| 62 ' '.join(args), error_message or e.stdout or '')) | 62 ' '.join(args), error_message or e.stdout or '')) |
| 63 return e.stdout | 63 return e.stdout |
| 64 | 64 |
| 65 | 65 |
| 66 def RunGit(args, **kwargs): | 66 def RunGit(args, **kwargs): |
| 67 """Returns stdout.""" | 67 """Returns stdout.""" |
| 68 return RunCommand(['git'] + args, **kwargs) | 68 return RunCommand(['git', '--no-pager'] + args, **kwargs) |
| 69 | 69 |
| 70 | 70 |
| 71 def RunGitWithCode(args): | 71 def RunGitWithCode(args): |
| 72 """Returns return code and stdout.""" | 72 """Returns return code and stdout.""" |
| 73 try: | 73 try: |
| 74 out, code = subprocess2.communicate(['git'] + args, stdout=subprocess2.PIPE) | 74 out, code = subprocess2.communicate(['git', '--no-pager'] + args, |
| 75 stdout=subprocess2.PIPE) |
| 75 return code, out[0] | 76 return code, out[0] |
| 76 except ValueError: | 77 except ValueError: |
| 77 # When the subprocess fails, it returns None. That triggers a ValueError | 78 # When the subprocess fails, it returns None. That triggers a ValueError |
| 78 # when trying to unpack the return value into (out, code). | 79 # when trying to unpack the return value into (out, code). |
| 79 return 1, '' | 80 return 1, '' |
| 80 | 81 |
| 81 | 82 |
| 82 def usage(more): | 83 def usage(more): |
| 83 def hook(fn): | 84 def hook(fn): |
| 84 fn.usage_more = more | 85 fn.usage_more = more |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 221 if 'GIT_EXTERNAL_DIFF' in env: | 222 if 'GIT_EXTERNAL_DIFF' in env: |
| 222 del env['GIT_EXTERNAL_DIFF'] | 223 del env['GIT_EXTERNAL_DIFF'] |
| 223 | 224 |
| 224 if find_copies: | 225 if find_copies: |
| 225 similarity_options = ['--find-copies-harder', '-l100000', | 226 similarity_options = ['--find-copies-harder', '-l100000', |
| 226 '-C%s' % similarity] | 227 '-C%s' % similarity] |
| 227 else: | 228 else: |
| 228 similarity_options = ['-M%s' % similarity] | 229 similarity_options = ['-M%s' % similarity] |
| 229 | 230 |
| 230 return subprocess2.call( | 231 return subprocess2.call( |
| 231 ['git', 'diff', '--no-ext-diff', '--stat'] + similarity_options + args, | 232 ['git', '--no-pager', |
| 233 'diff', '--no-ext-diff', '--stat'] + similarity_options + args, |
| 232 env=env) | 234 env=env) |
| 233 | 235 |
| 234 | 236 |
| 235 class Settings(object): | 237 class Settings(object): |
| 236 def __init__(self): | 238 def __init__(self): |
| 237 self.default_server = None | 239 self.default_server = None |
| 238 self.cc = None | 240 self.cc = None |
| 239 self.root = None | 241 self.root = None |
| 240 self.is_git_svn = None | 242 self.is_git_svn = None |
| 241 self.svn_branch = None | 243 self.svn_branch = None |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 290 # Strategy: | 292 # Strategy: |
| 291 # 1) iterate through our branch history and find the svn URL. | 293 # 1) iterate through our branch history and find the svn URL. |
| 292 # 2) find the svn-remote that fetches from the URL. | 294 # 2) find the svn-remote that fetches from the URL. |
| 293 | 295 |
| 294 # regexp matching the git-svn line that contains the URL. | 296 # regexp matching the git-svn line that contains the URL. |
| 295 git_svn_re = re.compile(r'^\s*git-svn-id: (\S+)@', re.MULTILINE) | 297 git_svn_re = re.compile(r'^\s*git-svn-id: (\S+)@', re.MULTILINE) |
| 296 | 298 |
| 297 # We don't want to go through all of history, so read a line from the | 299 # We don't want to go through all of history, so read a line from the |
| 298 # pipe at a time. | 300 # pipe at a time. |
| 299 # The -100 is an arbitrary limit so we don't search forever. | 301 # The -100 is an arbitrary limit so we don't search forever. |
| 300 cmd = ['git', 'log', '-100', '--pretty=medium'] | 302 cmd = ['git', '--no-pager', 'log', '-100', '--pretty=medium'] |
| 301 proc = subprocess2.Popen(cmd, stdout=subprocess2.PIPE) | 303 proc = subprocess2.Popen(cmd, stdout=subprocess2.PIPE) |
| 302 url = None | 304 url = None |
| 303 for line in proc.stdout: | 305 for line in proc.stdout: |
| 304 match = git_svn_re.match(line) | 306 match = git_svn_re.match(line) |
| 305 if match: | 307 if match: |
| 306 url = match.group(1) | 308 url = match.group(1) |
| 307 proc.stdout.close() # Cut pipe. | 309 proc.stdout.close() # Cut pipe. |
| 308 break | 310 break |
| 309 | 311 |
| 310 if url: | 312 if url: |
| (...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 659 RunGit(['config', self._RietveldServer(), self.rietveld_server]) | 661 RunGit(['config', self._RietveldServer(), self.rietveld_server]) |
| 660 else: | 662 else: |
| 661 RunGit(['config', '--unset', self._IssueSetting()]) | 663 RunGit(['config', '--unset', self._IssueSetting()]) |
| 662 self.SetPatchset(0) | 664 self.SetPatchset(0) |
| 663 self.has_issue = False | 665 self.has_issue = False |
| 664 | 666 |
| 665 def GetChange(self, upstream_branch, author): | 667 def GetChange(self, upstream_branch, author): |
| 666 if not self.GitSanityChecks(upstream_branch): | 668 if not self.GitSanityChecks(upstream_branch): |
| 667 DieWithError('\nGit sanity check failure') | 669 DieWithError('\nGit sanity check failure') |
| 668 | 670 |
| 669 root = RunCommand(['git', 'rev-parse', '--show-cdup']).strip() or '.' | 671 root = RunCommand(['git', '--no-pager', 'rev-parse', '--show-cdup']).strip() |
| 672 if not root: |
| 673 root = '.' |
| 670 absroot = os.path.abspath(root) | 674 absroot = os.path.abspath(root) |
| 671 | 675 |
| 672 # We use the sha1 of HEAD as a name of this change. | 676 # We use the sha1 of HEAD as a name of this change. |
| 673 name = RunCommand(['git', 'rev-parse', 'HEAD']).strip() | 677 name = RunCommand(['git', '--no-pager', 'rev-parse', 'HEAD']).strip() |
| 674 # Need to pass a relative path for msysgit. | 678 # Need to pass a relative path for msysgit. |
| 675 try: | 679 try: |
| 676 files = scm.GIT.CaptureStatus([root], '.', upstream_branch) | 680 files = scm.GIT.CaptureStatus([root], '.', upstream_branch) |
| 677 except subprocess2.CalledProcessError: | 681 except subprocess2.CalledProcessError: |
| 678 DieWithError( | 682 DieWithError( |
| 679 ('\nFailed to diff against upstream branch %s!\n\n' | 683 ('\nFailed to diff against upstream branch %s!\n\n' |
| 680 'This branch probably doesn\'t exist anymore. To reset the\n' | 684 'This branch probably doesn\'t exist anymore. To reset the\n' |
| 681 'tracking branch, please run\n' | 685 'tracking branch, please run\n' |
| 682 ' git branch --set-upstream %s trunk\n' | 686 ' git branch --set-upstream %s trunk\n' |
| 683 'replacing trunk with origin/master or the relevant branch') % | 687 'replacing trunk with origin/master or the relevant branch') % |
| 684 (upstream_branch, self.GetBranch())) | 688 (upstream_branch, self.GetBranch())) |
| 685 | 689 |
| 686 issue = self.GetIssue() | 690 issue = self.GetIssue() |
| 687 patchset = self.GetPatchset() | 691 patchset = self.GetPatchset() |
| 688 if issue: | 692 if issue: |
| 689 description = self.GetDescription() | 693 description = self.GetDescription() |
| 690 else: | 694 else: |
| 691 # If the change was never uploaded, use the log messages of all commits | 695 # If the change was never uploaded, use the log messages of all commits |
| 692 # up to the branch point, as git cl upload will prefill the description | 696 # up to the branch point, as git cl upload will prefill the description |
| 693 # with these log messages. | 697 # with these log messages. |
| 694 description = RunCommand(['git', 'log', '--pretty=format:%s%n%n%b', | 698 description = RunCommand(['git', '--no-pager', |
| 699 'log', '--pretty=format:%s%n%n%b', |
| 695 '%s...' % (upstream_branch)]).strip() | 700 '%s...' % (upstream_branch)]).strip() |
| 696 | 701 |
| 697 if not author: | 702 if not author: |
| 698 author = RunGit(['config', 'user.email']).strip() or None | 703 author = RunGit(['config', 'user.email']).strip() or None |
| 699 return presubmit_support.GitChange( | 704 return presubmit_support.GitChange( |
| 700 name, | 705 name, |
| 701 description, | 706 description, |
| 702 absroot, | 707 absroot, |
| 703 files, | 708 files, |
| 704 issue, | 709 issue, |
| (...skipping 996 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1701 # re.sub() should be used but flags=re.MULTILINE is only in python 2.7. | 1706 # re.sub() should be used but flags=re.MULTILINE is only in python 2.7. |
| 1702 try: | 1707 try: |
| 1703 patch_data = subprocess2.check_output( | 1708 patch_data = subprocess2.check_output( |
| 1704 ['sed', '-e', 's|^--- a/|--- |; s|^+++ b/|+++ |'], stdin=patch_data) | 1709 ['sed', '-e', 's|^--- a/|--- |; s|^+++ b/|+++ |'], stdin=patch_data) |
| 1705 except subprocess2.CalledProcessError: | 1710 except subprocess2.CalledProcessError: |
| 1706 DieWithError('Git patch mungling failed.') | 1711 DieWithError('Git patch mungling failed.') |
| 1707 logging.info(patch_data) | 1712 logging.info(patch_data) |
| 1708 # We use "git apply" to apply the patch instead of "patch" so that we can | 1713 # We use "git apply" to apply the patch instead of "patch" so that we can |
| 1709 # pick up file adds. | 1714 # pick up file adds. |
| 1710 # The --index flag means: also insert into the index (so we catch adds). | 1715 # The --index flag means: also insert into the index (so we catch adds). |
| 1711 cmd = ['git', 'apply', '--index', '-p0'] | 1716 cmd = ['git', '--no-pager', 'apply', '--index', '-p0'] |
| 1712 if options.reject: | 1717 if options.reject: |
| 1713 cmd.append('--reject') | 1718 cmd.append('--reject') |
| 1714 try: | 1719 try: |
| 1715 subprocess2.check_call(cmd, stdin=patch_data, stdout=subprocess2.VOID) | 1720 subprocess2.check_call(cmd, stdin=patch_data, stdout=subprocess2.VOID) |
| 1716 except subprocess2.CalledProcessError: | 1721 except subprocess2.CalledProcessError: |
| 1717 DieWithError('Failed to apply the patch') | 1722 DieWithError('Failed to apply the patch') |
| 1718 | 1723 |
| 1719 # If we had an issue, commit the current state and register the issue. | 1724 # If we had an issue, commit the current state and register the issue. |
| 1720 if not options.nocommit: | 1725 if not options.nocommit: |
| 1721 RunGit(['commit', '-m', 'patch from issue %s' % issue]) | 1726 RunGit(['commit', '-m', 'patch from issue %s' % issue]) |
| 1722 cl = Changelist() | 1727 cl = Changelist() |
| 1723 cl.SetIssue(issue) | 1728 cl.SetIssue(issue) |
| 1724 cl.SetPatchset(patchset) | 1729 cl.SetPatchset(patchset) |
| 1725 print "Committed patch locally." | 1730 print "Committed patch locally." |
| 1726 else: | 1731 else: |
| 1727 print "Patch applied to index." | 1732 print "Patch applied to index." |
| 1728 return 0 | 1733 return 0 |
| 1729 | 1734 |
| 1730 | 1735 |
| 1731 def CMDrebase(parser, args): | 1736 def CMDrebase(parser, args): |
| 1732 """rebase current branch on top of svn repo""" | 1737 """rebase current branch on top of svn repo""" |
| 1733 # Provide a wrapper for git svn rebase to help avoid accidental | 1738 # Provide a wrapper for git svn rebase to help avoid accidental |
| 1734 # git svn dcommit. | 1739 # git svn dcommit. |
| 1735 # It's the only command that doesn't use parser at all since we just defer | 1740 # It's the only command that doesn't use parser at all since we just defer |
| 1736 # execution to git-svn. | 1741 # execution to git-svn. |
| 1737 return subprocess2.call(['git', 'svn', 'rebase'] + args) | 1742 return subprocess2.call(['git', '--no-pager', 'svn', 'rebase'] + args) |
| 1738 | 1743 |
| 1739 | 1744 |
| 1740 def GetTreeStatus(): | 1745 def GetTreeStatus(): |
| 1741 """Fetches the tree status and returns either 'open', 'closed', | 1746 """Fetches the tree status and returns either 'open', 'closed', |
| 1742 'unknown' or 'unset'.""" | 1747 'unknown' or 'unset'.""" |
| 1743 url = settings.GetTreeStatusUrl(error_ok=True) | 1748 url = settings.GetTreeStatusUrl(error_ok=True) |
| 1744 if url: | 1749 if url: |
| 1745 status = urllib2.urlopen(url).read().lower() | 1750 status = urllib2.urlopen(url).read().lower() |
| 1746 if status.find('closed') != -1 or status == '0': | 1751 if status.find('closed') != -1 or status == '0': |
| 1747 return 'closed' | 1752 return 'closed' |
| (...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1992 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) | 1997 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) |
| 1993 | 1998 |
| 1994 # Not a known command. Default to help. | 1999 # Not a known command. Default to help. |
| 1995 GenUsage(parser, 'help') | 2000 GenUsage(parser, 'help') |
| 1996 return CMDhelp(parser, argv) | 2001 return CMDhelp(parser, argv) |
| 1997 | 2002 |
| 1998 | 2003 |
| 1999 if __name__ == '__main__': | 2004 if __name__ == '__main__': |
| 2000 fix_encoding.fix_encoding() | 2005 fix_encoding.fix_encoding() |
| 2001 sys.exit(main(sys.argv[1:])) | 2006 sys.exit(main(sys.argv[1:])) |
| OLD | NEW |