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 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 | 85 |
86 | 86 |
87 def ask_for_data(prompt): | 87 def ask_for_data(prompt): |
88 try: | 88 try: |
89 return raw_input(prompt) | 89 return raw_input(prompt) |
90 except KeyboardInterrupt: | 90 except KeyboardInterrupt: |
91 # Hide the exception. | 91 # Hide the exception. |
92 sys.exit(1) | 92 sys.exit(1) |
93 | 93 |
94 | 94 |
| 95 def git_set_branch_value(key, value): |
| 96 branch = Changelist().GetBranch() |
| 97 if branch: |
| 98 git_key = 'branch.%s.%s' % (branch, key) |
| 99 RunGit(['config', '--int', git_key, "%d" % value]) |
| 100 |
| 101 |
| 102 def git_get_branch_default(key, default): |
| 103 branch = Changelist().GetBranch() |
| 104 if branch: |
| 105 git_key = 'branch.%s.%s' % (branch, key) |
| 106 (_, stdout) = RunGitWithCode(['config', '--int', '--get', git_key]) |
| 107 try: |
| 108 return int(stdout.strip()) |
| 109 except ValueError: |
| 110 pass |
| 111 return default |
| 112 |
| 113 |
95 def add_git_similarity(parser): | 114 def add_git_similarity(parser): |
96 parser.add_option( | 115 parser.add_option( |
97 '--similarity', metavar='SIM', type='int', action='store', default=None, | 116 '--similarity', metavar='SIM', type='int', action='store', |
98 help='Sets the percentage that a pair of files need to match in order to' | 117 help='Sets the percentage that a pair of files need to match in order to' |
99 ' be considered copies (default 50)') | 118 ' be considered copies (default 50)') |
| 119 parser.add_option( |
| 120 '--find-copies', action='store_true', |
| 121 help='Allows git to look for copies.') |
| 122 parser.add_option( |
| 123 '--no-find-copies', action='store_false', dest='find_copies', |
| 124 help='Disallows git from looking for copies.') |
100 | 125 |
101 old_parser_args = parser.parse_args | 126 old_parser_args = parser.parse_args |
102 def Parse(args): | 127 def Parse(args): |
103 options, args = old_parser_args(args) | 128 options, args = old_parser_args(args) |
104 | 129 |
105 branch = Changelist().GetBranch() | |
106 key = 'branch.%s.git-cl-similarity' % branch | |
107 if options.similarity is None: | 130 if options.similarity is None: |
108 if branch: | 131 options.similarity = git_get_branch_default('git-cl-similarity', 50) |
109 (_, stdout) = RunGitWithCode(['config', '--int', '--get', key]) | |
110 try: | |
111 options.similarity = int(stdout.strip()) | |
112 except ValueError: | |
113 pass | |
114 options.similarity = options.similarity or 50 | |
115 else: | 132 else: |
116 if branch: | 133 print('Note: Saving similarity of %d%% in git config.' |
117 print('Note: Saving similarity of %d%% in git config.' | 134 % options.similarity) |
118 % options.similarity) | 135 git_set_branch_value('git-cl-similarity', options.similarity) |
119 RunGit(['config', '--int', key, str(options.similarity)]) | |
120 | 136 |
121 options.similarity = max(1, min(options.similarity, 100)) | 137 options.similarity = max(0, min(options.similarity, 100)) |
| 138 |
| 139 if options.find_copies is None: |
| 140 options.find_copies = bool( |
| 141 git_get_branch_default('git-find-copies', True)) |
| 142 else: |
| 143 git_set_branch_value('git-find-copies', int(options.find_copies)) |
122 | 144 |
123 print('Using %d%% similarity for rename/copy detection. ' | 145 print('Using %d%% similarity for rename/copy detection. ' |
124 'Override with --similarity.' % options.similarity) | 146 'Override with --similarity.' % options.similarity) |
125 | 147 |
126 return options, args | 148 return options, args |
127 parser.parse_args = Parse | 149 parser.parse_args = Parse |
128 | 150 |
129 | 151 |
130 def MatchSvnGlob(url, base_url, glob_spec, allow_wildcards): | 152 def MatchSvnGlob(url, base_url, glob_spec, allow_wildcards): |
131 """Return the corresponding git ref if |base_url| together with |glob_spec| | 153 """Return the corresponding git ref if |base_url| together with |glob_spec| |
(...skipping 30 matching lines...) Expand all Loading... |
162 # Parse specs like "trunk/src:refs/remotes/origin/trunk". | 184 # Parse specs like "trunk/src:refs/remotes/origin/trunk". |
163 if fetch_suburl: | 185 if fetch_suburl: |
164 full_url = base_url + '/' + fetch_suburl | 186 full_url = base_url + '/' + fetch_suburl |
165 else: | 187 else: |
166 full_url = base_url | 188 full_url = base_url |
167 if full_url == url: | 189 if full_url == url: |
168 return as_ref | 190 return as_ref |
169 return None | 191 return None |
170 | 192 |
171 | 193 |
172 def print_stats(similarity, args): | 194 def print_stats(similarity, find_copies, args): |
173 """Prints statistics about the change to the user.""" | 195 """Prints statistics about the change to the user.""" |
174 # --no-ext-diff is broken in some versions of Git, so try to work around | 196 # --no-ext-diff is broken in some versions of Git, so try to work around |
175 # this by overriding the environment (but there is still a problem if the | 197 # this by overriding the environment (but there is still a problem if the |
176 # git config key "diff.external" is used). | 198 # git config key "diff.external" is used). |
177 env = os.environ.copy() | 199 env = os.environ.copy() |
178 if 'GIT_EXTERNAL_DIFF' in env: | 200 if 'GIT_EXTERNAL_DIFF' in env: |
179 del env['GIT_EXTERNAL_DIFF'] | 201 del env['GIT_EXTERNAL_DIFF'] |
| 202 |
| 203 if find_copies: |
| 204 similarity_options = ['--find-copies-harder', '-l100000', |
| 205 '-C%s' % similarity] |
| 206 else: |
| 207 similarity_options = ['-M%s' % similarity] |
| 208 |
180 return subprocess2.call( | 209 return subprocess2.call( |
181 ['git', 'diff', '--no-ext-diff', '--stat', '--find-copies-harder', | 210 ['git', 'diff', '--no-ext-diff', '--stat'] + similarity_options + args, |
182 '-C%s' % similarity, '-l100000'] + args, env=env) | 211 env=env) |
183 | 212 |
184 | 213 |
185 class Settings(object): | 214 class Settings(object): |
186 def __init__(self): | 215 def __init__(self): |
187 self.default_server = None | 216 self.default_server = None |
188 self.cc = None | 217 self.cc = None |
189 self.root = None | 218 self.root = None |
190 self.is_git_svn = None | 219 self.is_git_svn = None |
191 self.svn_branch = None | 220 self.svn_branch = None |
192 self.tree_status_url = None | 221 self.tree_status_url = None |
(...skipping 873 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1066 upload_args.extend(['--reviewers', change_desc.reviewers]) | 1095 upload_args.extend(['--reviewers', change_desc.reviewers]) |
1067 if options.send_mail: | 1096 if options.send_mail: |
1068 if not change_desc.reviewers: | 1097 if not change_desc.reviewers: |
1069 DieWithError("Must specify reviewers to send email.") | 1098 DieWithError("Must specify reviewers to send email.") |
1070 upload_args.append('--send_mail') | 1099 upload_args.append('--send_mail') |
1071 cc = ','.join(filter(None, (cl.GetCCList(), options.cc))) | 1100 cc = ','.join(filter(None, (cl.GetCCList(), options.cc))) |
1072 if cc: | 1101 if cc: |
1073 upload_args.extend(['--cc', cc]) | 1102 upload_args.extend(['--cc', cc]) |
1074 | 1103 |
1075 upload_args.extend(['--git_similarity', str(options.similarity)]) | 1104 upload_args.extend(['--git_similarity', str(options.similarity)]) |
| 1105 if not options.find_copies: |
| 1106 upload_args.extend(['--git_no_find_copies']) |
1076 | 1107 |
1077 # Include the upstream repo's URL in the change -- this is useful for | 1108 # Include the upstream repo's URL in the change -- this is useful for |
1078 # projects that have their source spread across multiple repos. | 1109 # projects that have their source spread across multiple repos. |
1079 remote_url = cl.GetGitBaseUrlFromConfig() | 1110 remote_url = cl.GetGitBaseUrlFromConfig() |
1080 if not remote_url: | 1111 if not remote_url: |
1081 if settings.GetIsGitSvn(): | 1112 if settings.GetIsGitSvn(): |
1082 # URL is dependent on the current directory. | 1113 # URL is dependent on the current directory. |
1083 data = RunGit(['svn', 'info'], cwd=settings.GetRoot()) | 1114 data = RunGit(['svn', 'info'], cwd=settings.GetRoot()) |
1084 if data: | 1115 if data: |
1085 keys = dict(line.split(': ', 1) for line in data.splitlines() | 1116 keys = dict(line.split(': ', 1) for line in data.splitlines() |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1169 if not options.bypass_hooks: | 1200 if not options.bypass_hooks: |
1170 hook_results = cl.RunHook(committing=False, upstream_branch=base_branch, | 1201 hook_results = cl.RunHook(committing=False, upstream_branch=base_branch, |
1171 may_prompt=not options.force, | 1202 may_prompt=not options.force, |
1172 verbose=options.verbose, | 1203 verbose=options.verbose, |
1173 author=None) | 1204 author=None) |
1174 if not hook_results.should_continue(): | 1205 if not hook_results.should_continue(): |
1175 return 1 | 1206 return 1 |
1176 if not options.reviewers and hook_results.reviewers: | 1207 if not options.reviewers and hook_results.reviewers: |
1177 options.reviewers = hook_results.reviewers | 1208 options.reviewers = hook_results.reviewers |
1178 | 1209 |
1179 print_stats(options.similarity, args) | 1210 print_stats(options.similarity, options.find_copies, args) |
1180 if settings.GetIsGerrit(): | 1211 if settings.GetIsGerrit(): |
1181 return GerritUpload(options, args, cl) | 1212 return GerritUpload(options, args, cl) |
1182 return RietveldUpload(options, args, cl) | 1213 return RietveldUpload(options, args, cl) |
1183 | 1214 |
1184 | 1215 |
1185 def IsSubmoduleMergeCommit(ref): | 1216 def IsSubmoduleMergeCommit(ref): |
1186 # When submodules are added to the repo, we expect there to be a single | 1217 # When submodules are added to the repo, we expect there to be a single |
1187 # non-git-svn merge commit at remote HEAD with a signature comment. | 1218 # non-git-svn merge commit at remote HEAD with a signature comment. |
1188 pattern = '^SVN changes up to revision [0-9]*$' | 1219 pattern = '^SVN changes up to revision [0-9]*$' |
1189 cmd = ['rev-list', '--merges', '--grep=%s' % pattern, '%s^!' % ref] | 1220 cmd = ['rev-list', '--merges', '--grep=%s' % pattern, '%s^!' % ref] |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1303 | 1334 |
1304 if cl.GetIssue(): | 1335 if cl.GetIssue(): |
1305 description += "\n\nReview URL: %s" % cl.GetIssueURL() | 1336 description += "\n\nReview URL: %s" % cl.GetIssueURL() |
1306 | 1337 |
1307 if options.contributor: | 1338 if options.contributor: |
1308 description += "\nPatch from %s." % options.contributor | 1339 description += "\nPatch from %s." % options.contributor |
1309 print 'Description:', repr(description) | 1340 print 'Description:', repr(description) |
1310 | 1341 |
1311 branches = [base_branch, cl.GetBranchRef()] | 1342 branches = [base_branch, cl.GetBranchRef()] |
1312 if not options.force: | 1343 if not options.force: |
1313 print_stats(options.similarity, branches) | 1344 print_stats(options.similarity, options.find_copies, branches) |
1314 ask_for_data('About to commit; enter to confirm.') | 1345 ask_for_data('About to commit; enter to confirm.') |
1315 | 1346 |
1316 # We want to squash all this branch's commits into one commit with the proper | 1347 # We want to squash all this branch's commits into one commit with the proper |
1317 # description. We do this by doing a "reset --soft" to the base branch (which | 1348 # description. We do this by doing a "reset --soft" to the base branch (which |
1318 # keeps the working copy the same), then dcommitting that. If origin/master | 1349 # keeps the working copy the same), then dcommitting that. If origin/master |
1319 # has a submodule merge commit, we'll also need to cherry-pick the squashed | 1350 # has a submodule merge commit, we'll also need to cherry-pick the squashed |
1320 # commit onto a branch based on the git-svn head. | 1351 # commit onto a branch based on the git-svn head. |
1321 MERGE_BRANCH = 'git-cl-commit' | 1352 MERGE_BRANCH = 'git-cl-commit' |
1322 CHERRY_PICK_BRANCH = 'git-cl-cherry-pick' | 1353 CHERRY_PICK_BRANCH = 'git-cl-cherry-pick' |
1323 # Delete the branches if they exist. | 1354 # Delete the branches if they exist. |
(...skipping 434 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1758 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) | 1789 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) |
1759 | 1790 |
1760 # Not a known command. Default to help. | 1791 # Not a known command. Default to help. |
1761 GenUsage(parser, 'help') | 1792 GenUsage(parser, 'help') |
1762 return CMDhelp(parser, argv) | 1793 return CMDhelp(parser, argv) |
1763 | 1794 |
1764 | 1795 |
1765 if __name__ == '__main__': | 1796 if __name__ == '__main__': |
1766 fix_encoding.fix_encoding() | 1797 fix_encoding.fix_encoding() |
1767 sys.exit(main(sys.argv[1:])) | 1798 sys.exit(main(sys.argv[1:])) |
OLD | NEW |