Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 # Use of this source code is governed by a BSD-style license that can be | |
| 3 # found in the LICENSE file. | |
| 4 | |
| 5 import logging | |
| 6 import os | |
| 7 import subprocess | |
| 8 import threading | |
| 9 | |
| 10 from common import local_git_parsers | |
| 11 from common import repo_util | |
| 12 from common.repository import Repository | |
| 13 | |
| 14 _CHANGELOG_FORMAT_STRING = ('commit %H%n' | |
| 15 'author %an%n' | |
| 16 'author-mail %ae%n' | |
| 17 'author-time %at%n%n' | |
| 18 'committer %cn%n' | |
| 19 'committer-mail %ce%n' | |
| 20 'committer-time %ct%n%n' | |
| 21 '--Message start--%n%B%n--Message end--%n') | |
| 22 _CHANGELOGS_FORMAT_STRING = ('**Changelog start**%%n%s' % | |
| 23 _CHANGELOG_FORMAT_STRING) | |
| 24 CHECKOUT_ROOT_DIR = os.path.join(os.path.expanduser('~'), '.local_checkouts') | |
| 25 | |
| 26 | |
| 27 class LocalGitRepository(Repository): | |
| 28 """Represents local checkout of git repository on chromium host. | |
| 29 | |
| 30 Note, to checkout internal repos automatically which you have access to, | |
| 31 follow the instructions in ('https://g3doc.corp.google.com/company/teams/ | |
| 32 chrome/chrome_build_instructions.md? | |
| 33 cl=head#authentication-to-git-servers-chrome-internalgooglesourcecom') first. | |
| 34 """ | |
| 35 lock = threading.Lock() | |
| 36 # Keep track all the updated repos, so every repo only get updated once. | |
| 37 updated_repos = set() | |
| 38 def __init__(self, repo_url=None): | |
| 39 self._repo_path = None | |
| 40 self._repo_url = None | |
| 41 self.repo_url = repo_url | |
| 42 | |
| 43 @property | |
| 44 def repo_path(self): | |
| 45 return self._repo_path | |
| 46 | |
| 47 @property | |
| 48 def repo_url(self): | |
| 49 return self._repo_url | |
| 50 | |
| 51 @repo_url.setter | |
| 52 def repo_url(self, repo_url): | |
| 53 if not repo_url or (hasattr(self, '_repo_url') and | |
|
stgao
2016/10/22 00:43:35
Why hasattr is needed? Isn't self._repo_url alread
Sharu Jiang
2016/10/25 06:45:16
Oops, should have deleted.
| |
| 54 self._repo_url == repo_url): | |
| 55 return | |
| 56 | |
| 57 self._repo_url = repo_url | |
| 58 http_trimmed_url = repo_url.split('https://', 1)[1] | |
| 59 host_trimmed_url = '/'.join(http_trimmed_url.split('/')[1:]) | |
| 60 | |
| 61 self._repo_path = host_trimmed_url | |
| 62 self._CloneOrUpdateRepoIfNeeded() | |
| 63 | |
| 64 def _CloneOrUpdateRepoIfNeeded(self): | |
| 65 """Clones repo, or update it if it didn't got updated before.""" | |
| 66 if self.repo_url in LocalGitRepository.updated_repos: | |
| 67 return | |
| 68 | |
| 69 real_repo_path = os.path.join(CHECKOUT_ROOT_DIR, self.repo_path) | |
| 70 with LocalGitRepository.lock: | |
| 71 # Clone the repo if needed. | |
| 72 if not os.path.exists(real_repo_path): | |
| 73 subprocess.call(['git', 'clone', self.repo_url, real_repo_path]) | |
| 74 # Update repo if it's already cloned. | |
| 75 else: | |
| 76 # Disable verbose of git pull. | |
| 77 with open(os.devnull, 'w') as null_handle: | |
| 78 subprocess.check_call( | |
| 79 'cd %s; git pull' % real_repo_path, | |
| 80 stdout=null_handle, | |
| 81 stderr=null_handle, | |
| 82 shell=True) | |
| 83 | |
| 84 LocalGitRepository.updated_repos.add(self.repo_url) | |
| 85 | |
| 86 def _GetLocalGitCommandOutput(self, command): | |
| 87 """Gets the output stream of a git command for a local git repo. | |
| 88 | |
| 89 If the corresponding git repo_path is not downloaded yet, download it from | |
| 90 https://chromium.googlesource.com. | |
| 91 | |
| 92 Args: | |
| 93 command (str): Command to execute at this repo to get output. | |
| 94 | |
| 95 Return: | |
| 96 Output steam of the git command. | |
| 97 """ | |
| 98 real_repo_path = os.path.join(CHECKOUT_ROOT_DIR, self.repo_path) | |
| 99 command = 'cd %s; %s' % (real_repo_path, command) | |
| 100 p = subprocess.Popen( | |
| 101 command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) | |
| 102 return p.communicate()[0] | |
| 103 | |
| 104 def GetChangeLog(self, revision): | |
| 105 """Returns the change log of the given revision.""" | |
| 106 command = ('git log --pretty=format:"%s" --max-count=1 --raw ' | |
| 107 '--no-abbrev %s' % (_CHANGELOG_FORMAT_STRING, revision)) | |
| 108 output = self._GetLocalGitCommandOutput(command) | |
| 109 change_log = local_git_parsers.GitChangeLogParser()(output) | |
| 110 change_log.commit_url = '%s/+/%s' % (self.repo_url, change_log.revision) | |
| 111 return change_log | |
| 112 | |
| 113 def GetChangeLogs(self, start_revision, end_revision): # pylint: disable=W | |
| 114 """Returns change log list in (start_revision, end_revision].""" | |
| 115 command = ('git log --pretty=format:"%s" --raw ' | |
| 116 '--no-abbrev %s' % (_CHANGELOGS_FORMAT_STRING, | |
| 117 '%s..%s' % (start_revision, end_revision))) | |
| 118 output = self._GetLocalGitCommandOutput(command) | |
| 119 return local_git_parsers.GitChangeLogsParser()(output) | |
| 120 | |
| 121 def GetChangeDiff(self, revision, path=None): # pylint: disable=W | |
| 122 """Returns the diff of the given revision.""" | |
| 123 command = 'git log --format="" --max-count=1 %s' % revision | |
| 124 if path: | |
| 125 command += ' -p %s' % path | |
| 126 output = self._GetLocalGitCommandOutput(command) | |
| 127 return local_git_parsers.GitDiffParser()(output) | |
| 128 | |
| 129 def GetBlame(self, path, revision): | |
| 130 """Returns blame of the file at ``path`` of the given revision.""" | |
| 131 command = 'git blame --porcelain %s %s' % (path, revision) | |
| 132 output = self._GetLocalGitCommandOutput(command, path) | |
| 133 return local_git_parsers.GitBlameParser()(output) | |
| 134 | |
| 135 def GetSource(self, path, revision): | |
| 136 """Returns source code of the file at ``path`` of the given revision.""" | |
| 137 # Check whether the requested file exist or not. | |
| 138 if not os.path.isfile(os.path.join( | |
| 139 os.path.join(CHECKOUT_ROOT_DIR, self.repo_path), | |
| 140 path)): | |
| 141 return None | |
| 142 | |
| 143 command = 'git show %s:%s' % (revision, path) | |
| 144 output = self._GetLocalGitCommandOutput(command, path) | |
| 145 return local_git_parsers.GitSourceParser()(output) | |
| OLD | NEW |