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 from distutils.version import LooseVersion | 10 from distutils.version import LooseVersion |
(...skipping 1843 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1854 help="don't commit after patch applies") | 1854 help="don't commit after patch applies") |
1855 (options, args) = parser.parse_args(args) | 1855 (options, args) = parser.parse_args(args) |
1856 if len(args) != 1: | 1856 if len(args) != 1: |
1857 parser.print_help() | 1857 parser.print_help() |
1858 return 1 | 1858 return 1 |
1859 issue_arg = args[0] | 1859 issue_arg = args[0] |
1860 | 1860 |
1861 # TODO(maruel): Use apply_issue.py | 1861 # TODO(maruel): Use apply_issue.py |
1862 # TODO(ukai): use gerrit-cherry-pick for gerrit repository? | 1862 # TODO(ukai): use gerrit-cherry-pick for gerrit repository? |
1863 | 1863 |
1864 if issue_arg.isdigit(): | 1864 if options.newbranch: |
| 1865 if options.force: |
| 1866 RunGit(['branch', '-D', options.newbranch], |
| 1867 stderr=subprocess2.PIPE, error_ok=True) |
| 1868 RunGit(['checkout', '-b', options.newbranch, |
| 1869 Changelist().GetUpstreamBranch()]) |
| 1870 |
| 1871 return PatchIssue(issue_arg, options.reject, options.nocommit) |
| 1872 |
| 1873 |
| 1874 def PatchIssue(issue_arg, reject, nocommit): |
| 1875 if type(issue_arg) is int or issue_arg.isdigit(): |
1865 # Input is an issue id. Figure out the URL. | 1876 # Input is an issue id. Figure out the URL. |
1866 issue = int(issue_arg) | 1877 issue = int(issue_arg) |
1867 cl = Changelist(issue=issue) | 1878 cl = Changelist(issue=issue) |
1868 patchset = cl.GetMostRecentPatchset() | 1879 patchset = cl.GetMostRecentPatchset() |
1869 patch_data = cl.GetPatchSetDiff(issue, patchset) | 1880 patch_data = cl.GetPatchSetDiff(issue, patchset) |
1870 else: | 1881 else: |
1871 # Assume it's a URL to the patch. Default to https. | 1882 # Assume it's a URL to the patch. Default to https. |
1872 issue_url = gclient_utils.UpgradeToHttps(issue_arg) | 1883 issue_url = gclient_utils.UpgradeToHttps(issue_arg) |
1873 match = re.match(r'.*?/issue(\d+)_(\d+).diff', issue_url) | 1884 match = re.match(r'.*?/issue(\d+)_(\d+).diff', issue_url) |
1874 if not match: | 1885 if not match: |
1875 DieWithError('Must pass an issue ID or full URL for ' | 1886 DieWithError('Must pass an issue ID or full URL for ' |
1876 '\'Download raw patch set\'') | 1887 '\'Download raw patch set\'') |
1877 issue = int(match.group(1)) | 1888 issue = int(match.group(1)) |
1878 patchset = int(match.group(2)) | 1889 patchset = int(match.group(2)) |
1879 patch_data = urllib2.urlopen(issue_arg).read() | 1890 patch_data = urllib2.urlopen(issue_arg).read() |
1880 | 1891 |
1881 if options.newbranch: | |
1882 if options.force: | |
1883 RunGit(['branch', '-D', options.newbranch], | |
1884 stderr=subprocess2.PIPE, error_ok=True) | |
1885 RunGit(['checkout', '-b', options.newbranch, | |
1886 Changelist().GetUpstreamBranch()]) | |
1887 | |
1888 # Switch up to the top-level directory, if necessary, in preparation for | 1892 # Switch up to the top-level directory, if necessary, in preparation for |
1889 # applying the patch. | 1893 # applying the patch. |
1890 top = RunGit(['rev-parse', '--show-cdup']).strip() | 1894 top = RunGit(['rev-parse', '--show-cdup']).strip() |
1891 if top: | 1895 if top: |
1892 os.chdir(top) | 1896 os.chdir(top) |
1893 | 1897 |
1894 # Git patches have a/ at the beginning of source paths. We strip that out | 1898 # Git patches have a/ at the beginning of source paths. We strip that out |
1895 # with a sed script rather than the -p flag to patch so we can feed either | 1899 # with a sed script rather than the -p flag to patch so we can feed either |
1896 # Git or svn-style patches into the same apply command. | 1900 # Git or svn-style patches into the same apply command. |
1897 # re.sub() should be used but flags=re.MULTILINE is only in python 2.7. | 1901 # re.sub() should be used but flags=re.MULTILINE is only in python 2.7. |
1898 try: | 1902 try: |
1899 patch_data = subprocess2.check_output( | 1903 patch_data = subprocess2.check_output( |
1900 ['sed', '-e', 's|^--- a/|--- |; s|^+++ b/|+++ |'], stdin=patch_data) | 1904 ['sed', '-e', 's|^--- a/|--- |; s|^+++ b/|+++ |'], stdin=patch_data) |
1901 except subprocess2.CalledProcessError: | 1905 except subprocess2.CalledProcessError: |
1902 DieWithError('Git patch mungling failed.') | 1906 DieWithError('Git patch mungling failed.') |
1903 logging.info(patch_data) | 1907 logging.info(patch_data) |
1904 env = os.environ.copy() | 1908 env = os.environ.copy() |
1905 # 'cat' is a magical git string that disables pagers on all platforms. | 1909 # 'cat' is a magical git string that disables pagers on all platforms. |
1906 env['GIT_PAGER'] = 'cat' | 1910 env['GIT_PAGER'] = 'cat' |
1907 | 1911 |
1908 # We use "git apply" to apply the patch instead of "patch" so that we can | 1912 # We use "git apply" to apply the patch instead of "patch" so that we can |
1909 # pick up file adds. | 1913 # pick up file adds. |
1910 # The --index flag means: also insert into the index (so we catch adds). | 1914 # The --index flag means: also insert into the index (so we catch adds). |
1911 cmd = ['git', 'apply', '--index', '-p0'] | 1915 cmd = ['git', 'apply', '--index', '-p0'] |
1912 if options.reject: | 1916 if reject: |
1913 cmd.append('--reject') | 1917 cmd.append('--reject') |
1914 elif IsGitVersionAtLeast('1.7.12'): | 1918 elif IsGitVersionAtLeast('1.7.12'): |
1915 cmd.append('--3way') | 1919 cmd.append('--3way') |
1916 try: | 1920 try: |
1917 subprocess2.check_call(cmd, env=env, | 1921 subprocess2.check_call(cmd, env=env, |
1918 stdin=patch_data, stdout=subprocess2.VOID) | 1922 stdin=patch_data, stdout=subprocess2.VOID) |
1919 except subprocess2.CalledProcessError: | 1923 except subprocess2.CalledProcessError: |
1920 DieWithError('Failed to apply the patch') | 1924 DieWithError('Failed to apply the patch') |
1921 | 1925 |
1922 # If we had an issue, commit the current state and register the issue. | 1926 # If we had an issue, commit the current state and register the issue. |
1923 if not options.nocommit: | 1927 if not nocommit: |
1924 RunGit(['commit', '-m', 'patch from issue %s' % issue]) | 1928 RunGit(['commit', '-m', 'patch from issue %s' % issue]) |
1925 cl = Changelist() | 1929 cl = Changelist() |
1926 cl.SetIssue(issue) | 1930 cl.SetIssue(issue) |
1927 cl.SetPatchset(patchset) | 1931 cl.SetPatchset(patchset) |
1928 print "Committed patch locally." | 1932 print "Committed patch locally." |
1929 else: | 1933 else: |
1930 print "Patch applied to index." | 1934 print "Patch applied to index." |
1931 return 0 | 1935 return 0 |
1932 | 1936 |
1933 | 1937 |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2121 _, args = parser.parse_args(args) | 2125 _, args = parser.parse_args(args) |
2122 if args: | 2126 if args: |
2123 parser.error('Unrecognized args: %s' % ' '.join(args)) | 2127 parser.error('Unrecognized args: %s' % ' '.join(args)) |
2124 cl = Changelist() | 2128 cl = Changelist() |
2125 # Ensure there actually is an issue to close. | 2129 # Ensure there actually is an issue to close. |
2126 cl.GetDescription() | 2130 cl.GetDescription() |
2127 cl.CloseIssue() | 2131 cl.CloseIssue() |
2128 return 0 | 2132 return 0 |
2129 | 2133 |
2130 | 2134 |
| 2135 def CMDdiff(parser, args): |
| 2136 """shows differences between local tree and last upload.""" |
| 2137 cl = Changelist() |
| 2138 branch = cl.GetBranch() |
| 2139 TMP_BRANCH = 'git-cl-diff' |
| 2140 base_branch = RunGit(['merge-base', cl.GetUpstreamBranch(), 'HEAD']).strip() |
| 2141 |
| 2142 # Create a new branch based on the merge-base |
| 2143 RunGit(['checkout', '-q', '-b', TMP_BRANCH, base_branch]) |
| 2144 try: |
| 2145 # Patch in the latest changes from rietveld. |
| 2146 rtn = PatchIssue(cl.GetIssue(), False, False) |
| 2147 if rtn != 0: |
| 2148 return rtn |
| 2149 |
| 2150 # Switch back to starting brand and diff against the temporary |
| 2151 # branch containing the latest rietveld patch. |
| 2152 subprocess2.check_call(['git', 'diff', TMP_BRANCH, branch]) |
| 2153 finally: |
| 2154 RunGit(['checkout', '-q', branch]) |
| 2155 RunGit(['branch', '-D', TMP_BRANCH]) |
| 2156 |
| 2157 return 0 |
| 2158 |
| 2159 |
2131 def CMDowners(parser, args): | 2160 def CMDowners(parser, args): |
2132 """interactively find the owners for reviewing""" | 2161 """interactively find the owners for reviewing""" |
2133 parser.add_option( | 2162 parser.add_option( |
2134 '--no-color', | 2163 '--no-color', |
2135 action='store_true', | 2164 action='store_true', |
2136 help='Use this option to disable color output') | 2165 help='Use this option to disable color output') |
2137 options, args = parser.parse_args(args) | 2166 options, args = parser.parse_args(args) |
2138 | 2167 |
2139 author = RunGit(['config', 'user.email']).strip() or None | 2168 author = RunGit(['config', 'user.email']).strip() or None |
2140 | 2169 |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2256 ('AppEngine is misbehaving and returned HTTP %d, again. Keep faith ' | 2285 ('AppEngine is misbehaving and returned HTTP %d, again. Keep faith ' |
2257 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) | 2286 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) |
2258 | 2287 |
2259 | 2288 |
2260 if __name__ == '__main__': | 2289 if __name__ == '__main__': |
2261 # These affect sys.stdout so do it outside of main() to simplify mocks in | 2290 # These affect sys.stdout so do it outside of main() to simplify mocks in |
2262 # unit testing. | 2291 # unit testing. |
2263 fix_encoding.fix_encoding() | 2292 fix_encoding.fix_encoding() |
2264 colorama.init() | 2293 colorama.init() |
2265 sys.exit(main(sys.argv[1:])) | 2294 sys.exit(main(sys.argv[1:])) |
OLD | NEW |