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 |