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

Side by Side Diff: appengine/findit/common/local_git_repository.py

Issue 2432113002: [Findit] Add local_git_repository (Closed)
Patch Set: Fix nits. 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
« no previous file with comments | « no previous file | appengine/findit/common/repo_util.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 os
6 import subprocess
7 import threading
8
9 from common import local_git_parsers
10 from common import repo_util
11 from common.repository import Repository
12
13 _CHANGELOG_FORMAT_STRING = ('commit %H%n'
14 'author %an%n'
15 'author-mail %ae%n'
16 'author-time %ad%n%n'
17 'committer %cn%n'
18 'committer-mail %ce%n'
19 'committer-time %cd%n%n'
20 '--Message start--%n%B%n--Message end--%n')
21 _CHANGELOGS_FORMAT_STRING = ('**Changelog start**%%n%s' %
22 _CHANGELOG_FORMAT_STRING)
23 CHECKOUT_ROOT_DIR = os.path.join(os.path.expanduser('~'), '.local_checkouts')
24
25
26 class LocalGitRepository(Repository):
27 """Represents local checkout of git repository on chromium host.
28
29 Note, to checkout internal repos automatically which you have access to,
30 follow the instructions in ('https://g3doc.corp.google.com/company/teams/
31 chrome/chrome_build_instructions.md?
32 cl=head#authentication-to-git-servers-chrome-internalgooglesourcecom') first.
33 """
34 lock = threading.Lock()
35 # Keep track all the updated repos, so every repo only get updated once.
36 updated_repos = set()
wrengr 2016/10/25 18:12:18 I'd think this should be private/protected. Would
Sharu Jiang 2016/10/26 01:31:15 no, it is neither written or read by other code. D
37 def __init__(self, repo_url=None):
38 self._host = None
39 self._repo_path = None
40 self._repo_url = None
41 self.repo_url = repo_url
wrengr 2016/10/25 18:12:18 What's the difference between self._repo_url vs se
Sharu Jiang 2016/10/26 01:31:15 the self._repo_url set the initial default value,
42
43 @property
44 def repo_path(self):
45 return self._repo_path
46
47 @property
48 def real_repo_path(self):
wrengr 2016/10/25 18:12:18 Needs docstring explaining what "real" means here.
Sharu Jiang 2016/10/26 01:31:15 Done.
49 return os.path.join(CHECKOUT_ROOT_DIR, self._host, self.repo_path)
50
51 @property
52 def repo_url(self):
wrengr 2016/10/25 18:12:18 Needs docstring explaining how this differs from t
Sharu Jiang 2016/10/26 01:31:15 Done.
53 return self._repo_url
54
55 @repo_url.setter
56 def repo_url(self, repo_url):
57 if not repo_url or self._repo_url == repo_url:
58 return
59
60 self._repo_url = repo_url
61 url_parts = repo_url.split('https://', 1)[1].split('/')
wrengr 2016/10/25 18:12:18 This regex seems very fragile. Don't we have a lib
Sharu Jiang 2016/10/26 01:31:15 Done.
62
63 self._host = url_parts[0]
64 self._repo_path = '/'.join(url_parts[1:])
wrengr 2016/10/25 18:12:18 Calling join after split is expensive. If sticking
Sharu Jiang 2016/10/26 01:31:15 Done.
65 self._CloneOrUpdateRepoIfNeeded()
66
67 def _CloneOrUpdateRepoIfNeeded(self):
68 """Clones repo, or update it if it didn't got updated before."""
69 if self.repo_url in LocalGitRepository.updated_repos:
70 return
71
72 real_repo_path = os.path.join(CHECKOUT_ROOT_DIR, self.repo_path)
73 with LocalGitRepository.lock:
74 # Clone the repo if needed.
75 if not os.path.exists(real_repo_path):
76 subprocess.call(['git', 'clone', self.repo_url, real_repo_path])
wrengr 2016/10/25 18:12:18 We should check the return value to make sure thin
Sharu Jiang 2016/10/26 01:31:15 Done.
77 # Update repo if it's already cloned.
78 else:
79 # Disable verbose of git pull.
80 with open(os.devnull, 'w') as null_handle:
81 subprocess.check_call(
wrengr 2016/10/25 18:12:18 Ditto. Especially given as we're silencing stderr.
Sharu Jiang 2016/10/26 01:31:15 Done.
82 'cd %s; git pull' % real_repo_path,
83 stdout=null_handle,
84 stderr=null_handle,
85 shell=True)
86
87 LocalGitRepository.updated_repos.add(self.repo_url)
88
89 def _GetFinalCommand(self, command):
90 # Change local time to utc time.
91 command = 'TZ=UTC %s --date=format-local:"%s"' % (
stgao 2016/10/25 23:04:23 Should TZ=UTC be set through env? Does this work a
Sharu Jiang 2016/10/26 01:31:15 Do we want to use UTC everywhere? I think it may b
92 command, local_git_parsers.DATETIME_FORMAT)
93 return 'cd %s; %s' % (self.real_repo_path, command)
wrengr 2016/10/25 18:12:18 Should be 'cd %s && %s'. If the cd fails for some
Sharu Jiang 2016/10/26 01:31:15 Done. Good to know this usage :)
94
95 def GetChangeLog(self, revision):
96 """Returns the change log of the given revision."""
97 command = ('git log --pretty=format:"%s" --max-count=1 --raw '
98 '--no-abbrev %s' % (_CHANGELOG_FORMAT_STRING, revision))
99 output = repo_util.GetCommandOutput(self._GetFinalCommand(command))
100 change_log = local_git_parsers.GitChangeLogParser()(output, self.repo_url)
101 return change_log
102
103 def GetChangeLogs(self, start_revision, end_revision): # pylint: disable=W
104 """Returns change log list in (start_revision, end_revision]."""
105 command = ('git log --pretty=format:"%s" --raw '
106 '--no-abbrev %s' % (_CHANGELOGS_FORMAT_STRING,
107 '%s..%s' % (start_revision, end_revision)))
108 output = repo_util.GetCommandOutput(self._GetFinalCommand(command))
109 return local_git_parsers.GitChangeLogsParser()(output, self.repo_url)
110
111 def GetChangeDiff(self, revision, path=None): # pylint: disable=W
112 """Returns the diff of the given revision."""
113 command = 'git log --format="" --max-count=1 %s' % revision
114 if path:
115 command += ' -p %s' % path
116 output = repo_util.GetCommandOutput(self._GetFinalCommand(command))
117 return local_git_parsers.GitDiffParser()(output)
118
119 def GetBlame(self, path, revision):
120 """Returns blame of the file at ``path`` of the given revision."""
wrengr 2016/10/25 18:12:18 Is our style to use double backticks when referrin
stgao 2016/10/25 23:04:23 In infra, double backticks is the way to go.
Sharu Jiang 2016/10/26 01:31:15 Acknowledged.
121 command = 'git blame --porcelain %s %s' % (path, revision)
122 output = repo_util.GetCommandOutput(self._GetFinalCommand(command))
123 return local_git_parsers.GitBlameParser()(output, path, revision)
124
125 def GetSource(self, path, revision):
126 """Returns source code of the file at ``path`` of the given revision."""
127 # Check whether the requested file exist or not.
128 if not os.path.isfile(os.path.join(self.real_repo_path, path)):
129 return None
130
131 command = 'git show %s:%s' % (revision, path)
132 output = repo_util.GetCommandOutput(self._GetFinalCommand(command))
133 return local_git_parsers.GitSourceParser()(output)
OLDNEW
« no previous file with comments | « no previous file | appengine/findit/common/repo_util.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698