Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(441)

Side by Side Diff: appengine/findit/lib/gitiles/local_git_repository.py

Issue 2432113002: [Findit] Add local_git_repository (Closed)
Patch Set: Rebase. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 from urlparse import urlparse
8 import subprocess
9 import threading
10
11 from lib.gitiles import local_git_parsers
12 from lib.gitiles import repo_util
13 from lib.gitiles.git_repository import GitRepository
14
15 _CHANGELOG_FORMAT_STRING = ('commit %H%n'
16 'author %an%n'
17 'author-mail %ae%n'
18 'author-time %ad%n%n'
19 'committer %cn%n'
20 'committer-mail %ce%n'
21 'committer-time %cd%n%n'
22 '--Message start--%n%B%n--Message end--%n')
23 _CHANGELOGS_FORMAT_STRING = ('**Changelog start**%%n%s' %
24 _CHANGELOG_FORMAT_STRING)
25 CHECKOUT_ROOT_DIR = os.path.join(os.path.expanduser('~'), '.local_checkouts')
26
27
28 class LocalGitRepository(GitRepository):
29 """Represents local checkout of git repository on chromium host.
30
31 Note, to checkout internal repos automatically which you have access to,
32 follow the instructions in ('https://g3doc.corp.google.com/company/teams/
33 chrome/chrome_build_instructions.md?
34 cl=head#authentication-to-git-servers-chrome-internalgooglesourcecom') first.
35 """
36 lock = threading.Lock()
37 # Keep track all the updated repos, so every repo only get updated once.
38 _updated_repos = set()
39 def __init__(self, repo_url=None):
40 self._host = None
41 self._repo_path = None
42 self._repo_url = None
43 self.repo_url = repo_url
wrengr 2016/11/01 20:26:52 I still think you should rename the repo_url and _
Sharu Jiang 2016/11/05 01:18:15 Done.
44
45 @property
46 def repo_path(self):
47 return self._repo_path
48
49 @property
50 def real_repo_path(self):
51 """Absolute path of the local repository."""
52 return os.path.join(CHECKOUT_ROOT_DIR, self._host, self.repo_path)
53
54 @property
55 def repo_url(self):
56 """Url of remote repository which the local repo checks out from."""
57 return self._repo_url
58
59 @repo_url.setter
60 def repo_url(self, repo_url):
61 if self._repo_url == repo_url:
62 return
63
64 self._repo_url = repo_url
65 if not self._repo_url:
66 return
67
68 parsed_url = urlparse(repo_url)
69 self._host = parsed_url.netloc
70 # Remove the / in the front of path.
71 self._repo_path = parsed_url.path[1:]
72
73 self._CloneOrUpdateRepoIfNeeded()
74
75 def _CloneOrUpdateRepoIfNeeded(self):
76 """Clones repo, or update it if it didn't got updated before."""
77 if self.repo_url in LocalGitRepository._updated_repos:
78 return
79
80 with LocalGitRepository.lock:
81 # Clone the repo if needed.
82 if not os.path.exists(self.real_repo_path):
wrengr 2016/11/01 20:26:53 In general it's bad to check whether a file/direct
Sharu Jiang 2016/11/05 01:18:15 what if one process is git cloning the repo, and a
wrengr 2016/11/08 19:32:37 Probably. Depends on whether git is smart enough t
83 try:
84 subprocess.check_call(['git', 'clone',
85 self.repo_url, self.real_repo_path])
86 except subprocess.CalledProcessError as e: # pragma: no cover.
87 logging.error('Exception while cloning %s: %s', self.repo_url, e)
88 return
89 # Update repo if it's already cloned.
90 else:
91 try:
92 # Disable verbose of cd and git pull.
93 with open(os.devnull, 'w') as null_handle:
94 subprocess.check_call(
95 'cd %s && git pull' % self.real_repo_path,
96 stdout=null_handle, stderr=null_handle, shell=True)
97 except subprocess.CalledProcessError as e: # pragma: no cover.
98 logging.error('Exception while updating %s: %s', self.repo_path, e)
99 return
100
101 LocalGitRepository._updated_repos.add(self.repo_url)
102
103 def _GetFinalCommand(self, command, format_date=False):
104 # Change local time to utc time.
105 if format_date:
106 command = 'TZ=UTC %s --date=format-local:"%s"' % (
107 command, local_git_parsers.DATETIME_FORMAT)
108 return 'cd %s && %s' % (self.real_repo_path, command)
109
110 def GetChangeLog(self, revision):
111 """Returns the change log of the given revision."""
112 revision = 'HEAD' if revision == 'master' else revision
113 command = ('git log --pretty=format:"%s" --max-count=1 --raw '
114 '--no-abbrev %s' % (_CHANGELOG_FORMAT_STRING, revision))
115 output = repo_util.GetCommandOutput(self._GetFinalCommand(command, True))
116 if not output:
117 return None
118
119 return local_git_parsers.GitChangeLogParser()(output, self.repo_url)
120
121 def GetChangeLogs(self, start_revision, end_revision): # pylint: disable=W
122 """Returns change log list in (start_revision, end_revision]."""
123 start_revision = 'HEAD' if start_revision == 'master' else start_revision
wrengr 2016/11/01 20:26:53 Since this conditional rewrite is used in a bunch
Sharu Jiang 2016/11/05 01:18:15 Done.
124 end_revision = 'HEAD' if end_revision == 'master' else end_revision
125 command = ('git log --pretty=format:"%s" --raw '
126 '--no-abbrev %s' % (_CHANGELOGS_FORMAT_STRING,
127 '%s..%s' % (start_revision, end_revision)))
128 output = repo_util.GetCommandOutput(self._GetFinalCommand(command, True))
129 if not output:
130 return None
131
132 return local_git_parsers.GitChangeLogsParser()(output, self.repo_url)
wrengr 2016/11/01 20:26:52 Presumably you want to save the result of local_gi
Sharu Jiang 2016/11/05 01:18:15 Acknowledged.
133
134 def GetChangeDiff(self, revision, path=None): # pylint: disable=W
135 """Returns the diff of the given revision."""
136 revision = 'HEAD' if revision == 'master' else revision
137 command = 'git log --format="" --max-count=1 %s' % revision
138 if path:
139 command += ' -p %s' % path
140 output = repo_util.GetCommandOutput(self._GetFinalCommand(command))
141 if not output:
142 return None
143
144 return local_git_parsers.GitDiffParser()(output)
145
146 def GetBlame(self, path, revision):
147 """Returns blame of the file at ``path`` of the given revision."""
148 revision = 'HEAD' if revision == 'master' else revision
149 command = 'git blame --incremental %s %s' % (path, revision)
150 output = repo_util.GetCommandOutput(self._GetFinalCommand(command))
151 if not output:
152 return None
153
154 return local_git_parsers.GitBlameParser()(output, path, revision)
155
156 def GetSource(self, path, revision):
157 """Returns source code of the file at ``path`` of the given revision."""
158 # Check whether the requested file exist or not.
159 if not os.path.isfile(os.path.join(self.real_repo_path, path)):
160 return None
161 revision = 'HEAD' if revision == 'master' else revision
162 command = 'git show %s:%s' % (revision, path)
163 output = repo_util.GetCommandOutput(self._GetFinalCommand(command))
164 if not output:
165 return None
166
167 return local_git_parsers.GitSourceParser()(output)
OLDNEW
« no previous file with comments | « no previous file | appengine/findit/lib/gitiles/repo_util.py » ('j') | appengine/findit/lib/gitiles/repo_util.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698