| 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 |