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 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
194 else: | 194 else: |
195 git_set_branch_value('git-find-copies', int(options.find_copies)) | 195 git_set_branch_value('git-find-copies', int(options.find_copies)) |
196 | 196 |
197 print('Using %d%% similarity for rename/copy detection. ' | 197 print('Using %d%% similarity for rename/copy detection. ' |
198 'Override with --similarity.' % options.similarity) | 198 'Override with --similarity.' % options.similarity) |
199 | 199 |
200 return options, args | 200 return options, args |
201 parser.parse_args = Parse | 201 parser.parse_args = Parse |
202 | 202 |
203 | 203 |
204 def is_dirty_git_tree(cmd): | |
205 # Make sure index is up-to-date before running diff-index. | |
206 RunGit(['update-index', '--refresh', '-q'], error_ok=True) | |
207 dirty = RunGit(['diff-index', '--name-status', 'HEAD']) | |
208 if dirty: | |
209 print 'Cannot %s with a dirty tree. You must commit locally first.' % cmd | |
210 print 'Uncommitted files: (git diff-index --name-status HEAD)' | |
211 print dirty[:4096] | |
212 if len(dirty) > 4096: | |
213 print '... (run "git diff-index --name-status HEAD" to see full output).' | |
214 return True | |
215 return False | |
216 | |
217 | |
218 def MatchSvnGlob(url, base_url, glob_spec, allow_wildcards): | 204 def MatchSvnGlob(url, base_url, glob_spec, allow_wildcards): |
219 """Return the corresponding git ref if |base_url| together with |glob_spec| | 205 """Return the corresponding git ref if |base_url| together with |glob_spec| |
220 matches the full |url|. | 206 matches the full |url|. |
221 | 207 |
222 If |allow_wildcards| is true, |glob_spec| can contain wildcards (see below). | 208 If |allow_wildcards| is true, |glob_spec| can contain wildcards (see below). |
223 """ | 209 """ |
224 fetch_suburl, as_ref = glob_spec.split(':') | 210 fetch_suburl, as_ref = glob_spec.split(':') |
225 if allow_wildcards: | 211 if allow_wildcards: |
226 glob_match = re.match('(.+/)?(\*|{[^/]*})(/.+)?', fetch_suburl) | 212 glob_match = re.match('(.+/)?(\*|{[^/]*})(/.+)?', fetch_suburl) |
227 if glob_match: | 213 if glob_match: |
(...skipping 1420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1648 | 1634 |
1649 | 1635 |
1650 def CMDpresubmit(parser, args): | 1636 def CMDpresubmit(parser, args): |
1651 """Runs presubmit tests on the current changelist.""" | 1637 """Runs presubmit tests on the current changelist.""" |
1652 parser.add_option('-u', '--upload', action='store_true', | 1638 parser.add_option('-u', '--upload', action='store_true', |
1653 help='Run upload hook instead of the push/dcommit hook') | 1639 help='Run upload hook instead of the push/dcommit hook') |
1654 parser.add_option('-f', '--force', action='store_true', | 1640 parser.add_option('-f', '--force', action='store_true', |
1655 help='Run checks even if tree is dirty') | 1641 help='Run checks even if tree is dirty') |
1656 (options, args) = parser.parse_args(args) | 1642 (options, args) = parser.parse_args(args) |
1657 | 1643 |
1658 if not options.force and is_dirty_git_tree('presubmit'): | 1644 if not options.force and git_common.is_dirty_git_tree('presubmit'): |
1659 print 'use --force to check even if tree is dirty.' | 1645 print 'use --force to check even if tree is dirty.' |
1660 return 1 | 1646 return 1 |
1661 | 1647 |
1662 cl = Changelist() | 1648 cl = Changelist() |
1663 if args: | 1649 if args: |
1664 base_branch = args[0] | 1650 base_branch = args[0] |
1665 else: | 1651 else: |
1666 # Default to diffing against the common ancestor of the upstream branch. | 1652 # Default to diffing against the common ancestor of the upstream branch. |
1667 base_branch = cl.GetCommonAncestorWithUpstream() | 1653 base_branch = cl.GetCommonAncestorWithUpstream() |
1668 | 1654 |
(...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2025 help='email address to use to connect to Rietveld') | 2011 help='email address to use to connect to Rietveld') |
2026 parser.add_option('--tbr-owners', dest='tbr_owners', action='store_true', | 2012 parser.add_option('--tbr-owners', dest='tbr_owners', action='store_true', |
2027 help='add a set of OWNERS to TBR') | 2013 help='add a set of OWNERS to TBR') |
2028 parser.add_option('--cq-dry-run', dest='cq_dry_run', action='store_true', | 2014 parser.add_option('--cq-dry-run', dest='cq_dry_run', action='store_true', |
2029 help='Send the patchset to do a CQ dry run right after ' | 2015 help='Send the patchset to do a CQ dry run right after ' |
2030 'upload.') | 2016 'upload.') |
2031 | 2017 |
2032 add_git_similarity(parser) | 2018 add_git_similarity(parser) |
2033 (options, args) = parser.parse_args(args) | 2019 (options, args) = parser.parse_args(args) |
2034 | 2020 |
2035 if is_dirty_git_tree('upload'): | 2021 if git_common.is_dirty_git_tree('upload'): |
2036 return 1 | 2022 return 1 |
2037 | 2023 |
2038 options.reviewers = cleanup_list(options.reviewers) | 2024 options.reviewers = cleanup_list(options.reviewers) |
2039 options.cc = cleanup_list(options.cc) | 2025 options.cc = cleanup_list(options.cc) |
2040 | 2026 |
2041 cl = Changelist() | 2027 cl = Changelist() |
2042 if args: | 2028 if args: |
2043 # TODO(ukai): is it ok for gerrit case? | 2029 # TODO(ukai): is it ok for gerrit case? |
2044 base_branch = args[0] | 2030 base_branch = args[0] |
2045 else: | 2031 else: |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2155 args = [cl.GetUpstreamBranch()] | 2141 args = [cl.GetUpstreamBranch()] |
2156 | 2142 |
2157 if options.contributor: | 2143 if options.contributor: |
2158 if not re.match('^.*\s<\S+@\S+>$', options.contributor): | 2144 if not re.match('^.*\s<\S+@\S+>$', options.contributor): |
2159 print "Please provide contibutor as 'First Last <email@example.com>'" | 2145 print "Please provide contibutor as 'First Last <email@example.com>'" |
2160 return 1 | 2146 return 1 |
2161 | 2147 |
2162 base_branch = args[0] | 2148 base_branch = args[0] |
2163 base_has_submodules = IsSubmoduleMergeCommit(base_branch) | 2149 base_has_submodules = IsSubmoduleMergeCommit(base_branch) |
2164 | 2150 |
2165 if is_dirty_git_tree(cmd): | 2151 if git_common.is_dirty_git_tree(cmd): |
2166 return 1 | 2152 return 1 |
2167 | 2153 |
2168 # This rev-list syntax means "show all commits not in my branch that | 2154 # This rev-list syntax means "show all commits not in my branch that |
2169 # are in base_branch". | 2155 # are in base_branch". |
2170 upstream_commits = RunGit(['rev-list', '^' + cl.GetBranchRef(), | 2156 upstream_commits = RunGit(['rev-list', '^' + cl.GetBranchRef(), |
2171 base_branch]).splitlines() | 2157 base_branch]).splitlines() |
2172 if upstream_commits: | 2158 if upstream_commits: |
2173 print ('Base branch "%s" has %d commits ' | 2159 print ('Base branch "%s" has %d commits ' |
2174 'not in this branch.' % (base_branch, len(upstream_commits))) | 2160 'not in this branch.' % (base_branch, len(upstream_commits))) |
2175 print 'Run "git merge %s" before attempting to %s.' % (base_branch, cmd) | 2161 print 'Run "git merge %s" before attempting to %s.' % (base_branch, cmd) |
(...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2531 'attempting a 3-way merge') | 2517 'attempting a 3-way merge') |
2532 parser.add_option('-n', '--no-commit', action='store_true', dest='nocommit', | 2518 parser.add_option('-n', '--no-commit', action='store_true', dest='nocommit', |
2533 help="don't commit after patch applies") | 2519 help="don't commit after patch applies") |
2534 (options, args) = parser.parse_args(args) | 2520 (options, args) = parser.parse_args(args) |
2535 if len(args) != 1: | 2521 if len(args) != 1: |
2536 parser.print_help() | 2522 parser.print_help() |
2537 return 1 | 2523 return 1 |
2538 issue_arg = args[0] | 2524 issue_arg = args[0] |
2539 | 2525 |
2540 # We don't want uncommitted changes mixed up with the patch. | 2526 # We don't want uncommitted changes mixed up with the patch. |
2541 if is_dirty_git_tree('patch'): | 2527 if git_common.is_dirty_git_tree('patch'): |
2542 return 1 | 2528 return 1 |
2543 | 2529 |
2544 # TODO(maruel): Use apply_issue.py | 2530 # TODO(maruel): Use apply_issue.py |
2545 # TODO(ukai): use gerrit-cherry-pick for gerrit repository? | 2531 # TODO(ukai): use gerrit-cherry-pick for gerrit repository? |
2546 | 2532 |
2547 if options.newbranch: | 2533 if options.newbranch: |
2548 if options.force: | 2534 if options.force: |
2549 RunGit(['branch', '-D', options.newbranch], | 2535 RunGit(['branch', '-D', options.newbranch], |
2550 stderr=subprocess2.PIPE, error_ok=True) | 2536 stderr=subprocess2.PIPE, error_ok=True) |
2551 RunGit(['checkout', '-b', options.newbranch, | 2537 RunGit(['checkout', '-b', options.newbranch, |
2552 Changelist().GetUpstreamBranch()]) | 2538 Changelist().GetUpstreamBranch()]) |
2553 | 2539 |
2554 return PatchIssue(issue_arg, options.reject, options.nocommit, | 2540 return PatchIssue(issue_arg, options.reject, options.nocommit, |
2555 options.directory) | 2541 options.directory) |
2556 | 2542 |
2557 | 2543 |
2558 def PatchIssue(issue_arg, reject, nocommit, directory): | 2544 def PatchIssue(issue_arg, reject, nocommit, directory): |
2559 # There's a "reset --hard" when failing to apply the patch. In order | 2545 # There's a "reset --hard" when failing to apply the patch. In order |
2560 # not to destroy users' data, make sure the tree is not dirty here. | 2546 # not to destroy users' data, make sure the tree is not dirty here. |
2561 assert(not is_dirty_git_tree('apply')) | 2547 assert(not git_common.is_dirty_git_tree('apply')) |
2562 | 2548 |
2563 if type(issue_arg) is int or issue_arg.isdigit(): | 2549 if type(issue_arg) is int or issue_arg.isdigit(): |
2564 # Input is an issue id. Figure out the URL. | 2550 # Input is an issue id. Figure out the URL. |
2565 issue = int(issue_arg) | 2551 issue = int(issue_arg) |
2566 cl = Changelist(issue=issue) | 2552 cl = Changelist(issue=issue) |
2567 patchset = cl.GetMostRecentPatchset() | 2553 patchset = cl.GetMostRecentPatchset() |
2568 patch_data = cl.GetPatchSetDiff(issue, patchset) | 2554 patch_data = cl.GetPatchSetDiff(issue, patchset) |
2569 else: | 2555 else: |
2570 # Assume it's a URL to the patch. Default to https. | 2556 # Assume it's a URL to the patch. Default to https. |
2571 issue_url = gclient_utils.UpgradeToHttps(issue_arg) | 2557 issue_url = gclient_utils.UpgradeToHttps(issue_arg) |
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2914 | 2900 |
2915 def CMDdiff(parser, args): | 2901 def CMDdiff(parser, args): |
2916 """Shows differences between local tree and last upload.""" | 2902 """Shows differences between local tree and last upload.""" |
2917 parser.parse_args(args) | 2903 parser.parse_args(args) |
2918 | 2904 |
2919 # Uncommitted (staged and unstaged) changes will be destroyed by | 2905 # Uncommitted (staged and unstaged) changes will be destroyed by |
2920 # "git reset --hard" if there are merging conflicts in PatchIssue(). | 2906 # "git reset --hard" if there are merging conflicts in PatchIssue(). |
2921 # Staged changes would be committed along with the patch from last | 2907 # Staged changes would be committed along with the patch from last |
2922 # upload, hence counted toward the "last upload" side in the final | 2908 # upload, hence counted toward the "last upload" side in the final |
2923 # diff output, and this is not what we want. | 2909 # diff output, and this is not what we want. |
2924 if is_dirty_git_tree('diff'): | 2910 if git_common.is_dirty_git_tree('diff'): |
2925 return 1 | 2911 return 1 |
2926 | 2912 |
2927 cl = Changelist() | 2913 cl = Changelist() |
2928 issue = cl.GetIssue() | 2914 issue = cl.GetIssue() |
2929 branch = cl.GetBranch() | 2915 branch = cl.GetBranch() |
2930 if not issue: | 2916 if not issue: |
2931 DieWithError('No issue found for current branch (%s)' % branch) | 2917 DieWithError('No issue found for current branch (%s)' % branch) |
2932 TMP_BRANCH = 'git-cl-diff' | 2918 TMP_BRANCH = 'git-cl-diff' |
2933 base_branch = cl.GetCommonAncestorWithUpstream() | 2919 base_branch = cl.GetCommonAncestorWithUpstream() |
2934 | 2920 |
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3161 if __name__ == '__main__': | 3147 if __name__ == '__main__': |
3162 # These affect sys.stdout so do it outside of main() to simplify mocks in | 3148 # These affect sys.stdout so do it outside of main() to simplify mocks in |
3163 # unit testing. | 3149 # unit testing. |
3164 fix_encoding.fix_encoding() | 3150 fix_encoding.fix_encoding() |
3165 colorama.init() | 3151 colorama.init() |
3166 try: | 3152 try: |
3167 sys.exit(main(sys.argv[1:])) | 3153 sys.exit(main(sys.argv[1:])) |
3168 except KeyboardInterrupt: | 3154 except KeyboardInterrupt: |
3169 sys.stderr.write('interrupted\n') | 3155 sys.stderr.write('interrupted\n') |
3170 sys.exit(1) | 3156 sys.exit(1) |
OLD | NEW |