| 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 logging | 10 import logging |
| (...skipping 25 matching lines...) Expand all Loading... |
| 36 import breakpad # pylint: disable=W0611 | 36 import breakpad # pylint: disable=W0611 |
| 37 import fix_encoding | 37 import fix_encoding |
| 38 import gclient_utils | 38 import gclient_utils |
| 39 import presubmit_support | 39 import presubmit_support |
| 40 import rietveld | 40 import rietveld |
| 41 import scm | 41 import scm |
| 42 import subprocess2 | 42 import subprocess2 |
| 43 import watchlists | 43 import watchlists |
| 44 | 44 |
| 45 | 45 |
| 46 DEFAULT_SERVER = 'http://codereview.appspot.com' | 46 DEFAULT_SERVER = 'https://codereview.appspot.com' |
| 47 POSTUPSTREAM_HOOK_PATTERN = '.git/hooks/post-cl-%s' | 47 POSTUPSTREAM_HOOK_PATTERN = '.git/hooks/post-cl-%s' |
| 48 DESCRIPTION_BACKUP_FILE = '~/.git_cl_description_backup' | 48 DESCRIPTION_BACKUP_FILE = '~/.git_cl_description_backup' |
| 49 | 49 |
| 50 | 50 |
| 51 # Initialized in main() | 51 # Initialized in main() |
| 52 settings = None | 52 settings = None |
| 53 | 53 |
| 54 | 54 |
| 55 def DieWithError(message): | 55 def DieWithError(message): |
| 56 print >> sys.stderr, message | 56 print >> sys.stderr, message |
| (...skipping 30 matching lines...) Expand all Loading... |
| 87 | 87 |
| 88 | 88 |
| 89 def ask_for_data(prompt): | 89 def ask_for_data(prompt): |
| 90 try: | 90 try: |
| 91 return raw_input(prompt) | 91 return raw_input(prompt) |
| 92 except KeyboardInterrupt: | 92 except KeyboardInterrupt: |
| 93 # Hide the exception. | 93 # Hide the exception. |
| 94 sys.exit(1) | 94 sys.exit(1) |
| 95 | 95 |
| 96 | 96 |
| 97 def FixUrl(server): | |
| 98 """Fix a server url to defaults protocol to http:// if none is specified.""" | |
| 99 if not server: | |
| 100 return server | |
| 101 if not re.match(r'[a-z]+\://.*', server): | |
| 102 return 'http://' + server | |
| 103 return server | |
| 104 | |
| 105 | |
| 106 def MatchSvnGlob(url, base_url, glob_spec, allow_wildcards): | 97 def MatchSvnGlob(url, base_url, glob_spec, allow_wildcards): |
| 107 """Return the corresponding git ref if |base_url| together with |glob_spec| | 98 """Return the corresponding git ref if |base_url| together with |glob_spec| |
| 108 matches the full |url|. | 99 matches the full |url|. |
| 109 | 100 |
| 110 If |allow_wildcards| is true, |glob_spec| can contain wildcards (see below). | 101 If |allow_wildcards| is true, |glob_spec| can contain wildcards (see below). |
| 111 """ | 102 """ |
| 112 fetch_suburl, as_ref = glob_spec.split(':') | 103 fetch_suburl, as_ref = glob_spec.split(':') |
| 113 if allow_wildcards: | 104 if allow_wildcards: |
| 114 glob_match = re.match('(.+/)?(\*|{[^/]*})(/.+)?', fetch_suburl) | 105 glob_match = re.match('(.+/)?(\*|{[^/]*})(/.+)?', fetch_suburl) |
| 115 if glob_match: | 106 if glob_match: |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 161 """Updates the settings from a codereview.settings file, if available.""" | 152 """Updates the settings from a codereview.settings file, if available.""" |
| 162 if not self.updated: | 153 if not self.updated: |
| 163 cr_settings_file = FindCodereviewSettingsFile() | 154 cr_settings_file = FindCodereviewSettingsFile() |
| 164 if cr_settings_file: | 155 if cr_settings_file: |
| 165 LoadCodereviewSettingsFromFile(cr_settings_file) | 156 LoadCodereviewSettingsFromFile(cr_settings_file) |
| 166 self.updated = True | 157 self.updated = True |
| 167 | 158 |
| 168 def GetDefaultServerUrl(self, error_ok=False): | 159 def GetDefaultServerUrl(self, error_ok=False): |
| 169 if not self.default_server: | 160 if not self.default_server: |
| 170 self.LazyUpdateIfNeeded() | 161 self.LazyUpdateIfNeeded() |
| 171 self.default_server = FixUrl(self._GetConfig('rietveld.server', | 162 self.default_server = gclient_utils.UpgradeToHttps( |
| 172 error_ok=True)) | 163 self._GetConfig('rietveld.server', error_ok=True)) |
| 173 if error_ok: | 164 if error_ok: |
| 174 return self.default_server | 165 return self.default_server |
| 175 if not self.default_server: | 166 if not self.default_server: |
| 176 error_message = ('Could not find settings file. You must configure ' | 167 error_message = ('Could not find settings file. You must configure ' |
| 177 'your review setup by running "git cl config".') | 168 'your review setup by running "git cl config".') |
| 178 self.default_server = FixUrl(self._GetConfig( | 169 self.default_server = gclient_utils.UpgradeToHttps( |
| 179 'rietveld.server', error_message=error_message)) | 170 self._GetConfig('rietveld.server', error_message=error_message)) |
| 180 return self.default_server | 171 return self.default_server |
| 181 | 172 |
| 182 def GetRoot(self): | 173 def GetRoot(self): |
| 183 if not self.root: | 174 if not self.root: |
| 184 self.root = os.path.abspath(RunGit(['rev-parse', '--show-cdup']).strip()) | 175 self.root = os.path.abspath(RunGit(['rev-parse', '--show-cdup']).strip()) |
| 185 return self.root | 176 return self.root |
| 186 | 177 |
| 187 def GetIsGitSvn(self): | 178 def GetIsGitSvn(self): |
| 188 """Return true if this repo looks like it's using git-svn.""" | 179 """Return true if this repo looks like it's using git-svn.""" |
| 189 if self.is_git_svn is None: | 180 if self.is_git_svn is None: |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 259 if not self.tree_status_url: | 250 if not self.tree_status_url: |
| 260 error_message = ('You must configure your tree status URL by running ' | 251 error_message = ('You must configure your tree status URL by running ' |
| 261 '"git cl config".') | 252 '"git cl config".') |
| 262 self.tree_status_url = self._GetConfig('rietveld.tree-status-url', | 253 self.tree_status_url = self._GetConfig('rietveld.tree-status-url', |
| 263 error_ok=error_ok, | 254 error_ok=error_ok, |
| 264 error_message=error_message) | 255 error_message=error_message) |
| 265 return self.tree_status_url | 256 return self.tree_status_url |
| 266 | 257 |
| 267 def GetViewVCUrl(self): | 258 def GetViewVCUrl(self): |
| 268 if not self.viewvc_url: | 259 if not self.viewvc_url: |
| 269 self.viewvc_url = self._GetConfig('rietveld.viewvc-url', error_ok=True) | 260 self.viewvc_url = gclient_utils.UpgradeToHttps( |
| 261 self._GetConfig('rietveld.viewvc-url', error_ok=True)) |
| 270 return self.viewvc_url | 262 return self.viewvc_url |
| 271 | 263 |
| 272 def GetDefaultCCList(self): | 264 def GetDefaultCCList(self): |
| 273 return self._GetConfig('rietveld.cc', error_ok=True) | 265 return self._GetConfig('rietveld.cc', error_ok=True) |
| 274 | 266 |
| 275 def _GetConfig(self, param, **kwargs): | 267 def _GetConfig(self, param, **kwargs): |
| 276 self.LazyUpdateIfNeeded() | 268 self.LazyUpdateIfNeeded() |
| 277 return RunGit(['config', param], **kwargs).strip() | 269 return RunGit(['config', param], **kwargs).strip() |
| 278 | 270 |
| 279 | 271 |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 419 if remote == '.': | 411 if remote == '.': |
| 420 return None | 412 return None |
| 421 return RunGit(['config', 'remote.%s.url' % remote], error_ok=True).strip() | 413 return RunGit(['config', 'remote.%s.url' % remote], error_ok=True).strip() |
| 422 | 414 |
| 423 def GetIssue(self): | 415 def GetIssue(self): |
| 424 if not self.has_issue: | 416 if not self.has_issue: |
| 425 CheckForMigration() | 417 CheckForMigration() |
| 426 issue = RunGit(['config', self._IssueSetting()], error_ok=True).strip() | 418 issue = RunGit(['config', self._IssueSetting()], error_ok=True).strip() |
| 427 if issue: | 419 if issue: |
| 428 self.issue = issue | 420 self.issue = issue |
| 429 self.rietveld_server = FixUrl(RunGit( | 421 self.rietveld_server = gclient_utils.UpgradeToHttps(RunGit( |
| 430 ['config', self._RietveldServer()], error_ok=True).strip()) | 422 ['config', self._RietveldServer()], error_ok=True).strip()) |
| 431 else: | 423 else: |
| 432 self.issue = None | 424 self.issue = None |
| 433 if not self.rietveld_server: | 425 if not self.rietveld_server: |
| 434 self.rietveld_server = settings.GetDefaultServerUrl() | 426 self.rietveld_server = settings.GetDefaultServerUrl() |
| 435 self.has_issue = True | 427 self.has_issue = True |
| 436 return self.issue | 428 return self.issue |
| 437 | 429 |
| 438 def GetRietveldServer(self): | 430 def GetRietveldServer(self): |
| 439 self.GetIssue() | 431 self.GetIssue() |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 618 | 610 |
| 619 | 611 |
| 620 def GetCodereviewSettingsInteractively(): | 612 def GetCodereviewSettingsInteractively(): |
| 621 """Prompt the user for settings.""" | 613 """Prompt the user for settings.""" |
| 622 server = settings.GetDefaultServerUrl(error_ok=True) | 614 server = settings.GetDefaultServerUrl(error_ok=True) |
| 623 prompt = 'Rietveld server (host[:port])' | 615 prompt = 'Rietveld server (host[:port])' |
| 624 prompt += ' [%s]' % (server or DEFAULT_SERVER) | 616 prompt += ' [%s]' % (server or DEFAULT_SERVER) |
| 625 newserver = ask_for_data(prompt + ':') | 617 newserver = ask_for_data(prompt + ':') |
| 626 if not server and not newserver: | 618 if not server and not newserver: |
| 627 newserver = DEFAULT_SERVER | 619 newserver = DEFAULT_SERVER |
| 628 if newserver and newserver != server: | 620 if newserver: |
| 629 RunGit(['config', 'rietveld.server', newserver]) | 621 newserver = gclient_utils.UpgradeToHttps(newserver) |
| 622 if newserver != server: |
| 623 RunGit(['config', 'rietveld.server', newserver]) |
| 630 | 624 |
| 631 def SetProperty(initial, caption, name): | 625 def SetProperty(initial, caption, name, is_url): |
| 632 prompt = caption | 626 prompt = caption |
| 633 if initial: | 627 if initial: |
| 634 prompt += ' ("x" to clear) [%s]' % initial | 628 prompt += ' ("x" to clear) [%s]' % initial |
| 635 new_val = ask_for_data(prompt + ':') | 629 new_val = ask_for_data(prompt + ':') |
| 636 if new_val == 'x': | 630 if new_val == 'x': |
| 637 RunGit(['config', '--unset-all', 'rietveld.' + name], error_ok=True) | 631 RunGit(['config', '--unset-all', 'rietveld.' + name], error_ok=True) |
| 638 elif new_val and new_val != initial: | 632 elif new_val: |
| 639 RunGit(['config', 'rietveld.' + name, new_val]) | 633 if is_url: |
| 634 new_val = gclient_utils.UpgradeToHttps(new_val) |
| 635 if new_val != initial: |
| 636 RunGit(['config', 'rietveld.' + name, new_val]) |
| 640 | 637 |
| 641 SetProperty(settings.GetDefaultCCList(), 'CC list', 'cc') | 638 SetProperty(settings.GetDefaultCCList(), 'CC list', 'cc', False) |
| 642 SetProperty(settings.GetTreeStatusUrl(error_ok=True), 'Tree status URL', | 639 SetProperty(settings.GetTreeStatusUrl(error_ok=True), 'Tree status URL', |
| 643 'tree-status-url') | 640 'tree-status-url', False) |
| 644 SetProperty(settings.GetViewVCUrl(), 'ViewVC URL', 'viewvc-url') | 641 SetProperty(settings.GetViewVCUrl(), 'ViewVC URL', 'viewvc-url', True) |
| 645 | 642 |
| 646 # TODO: configure a default branch to diff against, rather than this | 643 # TODO: configure a default branch to diff against, rather than this |
| 647 # svn-based hackery. | 644 # svn-based hackery. |
| 648 | 645 |
| 649 | 646 |
| 650 class ChangeDescription(object): | 647 class ChangeDescription(object): |
| 651 """Contains a parsed form of the change description.""" | 648 """Contains a parsed form of the change description.""" |
| 652 def __init__(self, subject, log_desc, reviewers): | 649 def __init__(self, subject, log_desc, reviewers): |
| 653 self.subject = subject | 650 self.subject = subject |
| 654 self.log_desc = log_desc | 651 self.log_desc = log_desc |
| (...skipping 576 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1231 return 1 | 1228 return 1 |
| 1232 issue_arg = args[0] | 1229 issue_arg = args[0] |
| 1233 | 1230 |
| 1234 # TODO(maruel): Use apply_issue.py | 1231 # TODO(maruel): Use apply_issue.py |
| 1235 | 1232 |
| 1236 if re.match(r'\d+', issue_arg): | 1233 if re.match(r'\d+', issue_arg): |
| 1237 # Input is an issue id. Figure out the URL. | 1234 # Input is an issue id. Figure out the URL. |
| 1238 issue = issue_arg | 1235 issue = issue_arg |
| 1239 patch_data = Changelist().GetPatchSetDiff(issue) | 1236 patch_data = Changelist().GetPatchSetDiff(issue) |
| 1240 else: | 1237 else: |
| 1241 # Assume it's a URL to the patch. Default to http. | 1238 # Assume it's a URL to the patch. Default to https. |
| 1242 issue_url = FixUrl(issue_arg) | 1239 issue_url = gclient_utils.UpgradeToHttps(issue_arg) |
| 1243 match = re.match(r'.*?/issue(\d+)_\d+.diff', issue_url) | 1240 match = re.match(r'.*?/issue(\d+)_\d+.diff', issue_url) |
| 1244 if not match: | 1241 if not match: |
| 1245 DieWithError('Must pass an issue ID or full URL for ' | 1242 DieWithError('Must pass an issue ID or full URL for ' |
| 1246 '\'Download raw patch set\'') | 1243 '\'Download raw patch set\'') |
| 1247 issue = match.group(1) | 1244 issue = match.group(1) |
| 1248 patch_data = urllib2.urlopen(issue_arg).read() | 1245 patch_data = urllib2.urlopen(issue_arg).read() |
| 1249 | 1246 |
| 1250 if options.newbranch: | 1247 if options.newbranch: |
| 1251 if options.force: | 1248 if options.force: |
| 1252 RunGit(['branch', '-D', options.newbranch], | 1249 RunGit(['branch', '-D', options.newbranch], |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1431 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) | 1428 'and retry or visit go/isgaeup.\n%s') % (e.code, str(e))) |
| 1432 | 1429 |
| 1433 # Not a known command. Default to help. | 1430 # Not a known command. Default to help. |
| 1434 GenUsage(parser, 'help') | 1431 GenUsage(parser, 'help') |
| 1435 return CMDhelp(parser, argv) | 1432 return CMDhelp(parser, argv) |
| 1436 | 1433 |
| 1437 | 1434 |
| 1438 if __name__ == '__main__': | 1435 if __name__ == '__main__': |
| 1439 fix_encoding.fix_encoding() | 1436 fix_encoding.fix_encoding() |
| 1440 sys.exit(main(sys.argv[1:])) | 1437 sys.exit(main(sys.argv[1:])) |
| OLD | NEW |