##// END OF EJS Templates
cached-commits: don't update cache on summary page....
dan -
r4161:e6cf946d default
parent child Browse files
Show More
@@ -1,319 +1,314 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2019 RhodeCode GmbH
3 # Copyright (C) 2011-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22 import string
22 import string
23 import time
23 import time
24
24
25 import rhodecode
25 import rhodecode
26
26
27 from pyramid.view import view_config
27 from pyramid.view import view_config
28
28
29 from rhodecode.lib.view_utils import get_format_ref_id
29 from rhodecode.lib.view_utils import get_format_ref_id
30 from rhodecode.apps._base import RepoAppView
30 from rhodecode.apps._base import RepoAppView
31 from rhodecode.config.conf import (LANGUAGES_EXTENSIONS_MAP)
31 from rhodecode.config.conf import (LANGUAGES_EXTENSIONS_MAP)
32 from rhodecode.lib import helpers as h, rc_cache
32 from rhodecode.lib import helpers as h, rc_cache
33 from rhodecode.lib.utils2 import safe_str, safe_int
33 from rhodecode.lib.utils2 import safe_str, safe_int
34 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
34 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
35 from rhodecode.lib.ext_json import json
35 from rhodecode.lib.ext_json import json
36 from rhodecode.lib.vcs.backends.base import EmptyCommit
36 from rhodecode.lib.vcs.backends.base import EmptyCommit
37 from rhodecode.lib.vcs.exceptions import (
37 from rhodecode.lib.vcs.exceptions import (
38 CommitError, EmptyRepositoryError, CommitDoesNotExistError)
38 CommitError, EmptyRepositoryError, CommitDoesNotExistError)
39 from rhodecode.model.db import Statistics, CacheKey, User
39 from rhodecode.model.db import Statistics, CacheKey, User
40 from rhodecode.model.meta import Session
40 from rhodecode.model.meta import Session
41 from rhodecode.model.scm import ScmModel
41 from rhodecode.model.scm import ScmModel
42
42
43 log = logging.getLogger(__name__)
43 log = logging.getLogger(__name__)
44
44
45
45
46 class RepoSummaryView(RepoAppView):
46 class RepoSummaryView(RepoAppView):
47
47
48 def load_default_context(self):
48 def load_default_context(self):
49 c = self._get_local_tmpl_context(include_app_defaults=True)
49 c = self._get_local_tmpl_context(include_app_defaults=True)
50 c.rhodecode_repo = None
50 c.rhodecode_repo = None
51 if not c.repository_requirements_missing:
51 if not c.repository_requirements_missing:
52 c.rhodecode_repo = self.rhodecode_vcs_repo
52 c.rhodecode_repo = self.rhodecode_vcs_repo
53 return c
53 return c
54
54
55 def _load_commits_context(self, c):
55 def _load_commits_context(self, c):
56 p = safe_int(self.request.GET.get('page'), 1)
56 p = safe_int(self.request.GET.get('page'), 1)
57 size = safe_int(self.request.GET.get('size'), 10)
57 size = safe_int(self.request.GET.get('size'), 10)
58
58
59 def url_generator(page_num):
59 def url_generator(page_num):
60 query_params = {
60 query_params = {
61 'page': page_num,
61 'page': page_num,
62 'size': size
62 'size': size
63 }
63 }
64 return h.route_path(
64 return h.route_path(
65 'repo_summary_commits',
65 'repo_summary_commits',
66 repo_name=c.rhodecode_db_repo.repo_name, _query=query_params)
66 repo_name=c.rhodecode_db_repo.repo_name, _query=query_params)
67
67
68 pre_load = ['author', 'branch', 'date', 'message']
68 pre_load = ['author', 'branch', 'date', 'message']
69 try:
69 try:
70 collection = self.rhodecode_vcs_repo.get_commits(
70 collection = self.rhodecode_vcs_repo.get_commits(
71 pre_load=pre_load, translate_tags=False)
71 pre_load=pre_load, translate_tags=False)
72 except EmptyRepositoryError:
72 except EmptyRepositoryError:
73 collection = self.rhodecode_vcs_repo
73 collection = self.rhodecode_vcs_repo
74
74
75 c.repo_commits = h.RepoPage(
75 c.repo_commits = h.RepoPage(
76 collection, page=p, items_per_page=size, url_maker=url_generator)
76 collection, page=p, items_per_page=size, url_maker=url_generator)
77 page_ids = [x.raw_id for x in c.repo_commits]
77 page_ids = [x.raw_id for x in c.repo_commits]
78 c.comments = self.db_repo.get_comments(page_ids)
78 c.comments = self.db_repo.get_comments(page_ids)
79 c.statuses = self.db_repo.statuses(page_ids)
79 c.statuses = self.db_repo.statuses(page_ids)
80
80
81 def _prepare_and_set_clone_url(self, c):
81 def _prepare_and_set_clone_url(self, c):
82 username = ''
82 username = ''
83 if self._rhodecode_user.username != User.DEFAULT_USER:
83 if self._rhodecode_user.username != User.DEFAULT_USER:
84 username = safe_str(self._rhodecode_user.username)
84 username = safe_str(self._rhodecode_user.username)
85
85
86 _def_clone_uri = _def_clone_uri_id = c.clone_uri_tmpl
86 _def_clone_uri = _def_clone_uri_id = c.clone_uri_tmpl
87 _def_clone_uri_ssh = c.clone_uri_ssh_tmpl
87 _def_clone_uri_ssh = c.clone_uri_ssh_tmpl
88
88
89 if '{repo}' in _def_clone_uri:
89 if '{repo}' in _def_clone_uri:
90 _def_clone_uri_id = _def_clone_uri.replace('{repo}', '_{repoid}')
90 _def_clone_uri_id = _def_clone_uri.replace('{repo}', '_{repoid}')
91 elif '{repoid}' in _def_clone_uri:
91 elif '{repoid}' in _def_clone_uri:
92 _def_clone_uri_id = _def_clone_uri.replace('_{repoid}', '{repo}')
92 _def_clone_uri_id = _def_clone_uri.replace('_{repoid}', '{repo}')
93
93
94 c.clone_repo_url = self.db_repo.clone_url(
94 c.clone_repo_url = self.db_repo.clone_url(
95 user=username, uri_tmpl=_def_clone_uri)
95 user=username, uri_tmpl=_def_clone_uri)
96 c.clone_repo_url_id = self.db_repo.clone_url(
96 c.clone_repo_url_id = self.db_repo.clone_url(
97 user=username, uri_tmpl=_def_clone_uri_id)
97 user=username, uri_tmpl=_def_clone_uri_id)
98 c.clone_repo_url_ssh = self.db_repo.clone_url(
98 c.clone_repo_url_ssh = self.db_repo.clone_url(
99 uri_tmpl=_def_clone_uri_ssh, ssh=True)
99 uri_tmpl=_def_clone_uri_ssh, ssh=True)
100
100
101 @LoginRequired()
101 @LoginRequired()
102 @HasRepoPermissionAnyDecorator(
102 @HasRepoPermissionAnyDecorator(
103 'repository.read', 'repository.write', 'repository.admin')
103 'repository.read', 'repository.write', 'repository.admin')
104 @view_config(
104 @view_config(
105 route_name='repo_summary_commits', request_method='GET',
105 route_name='repo_summary_commits', request_method='GET',
106 renderer='rhodecode:templates/summary/summary_commits.mako')
106 renderer='rhodecode:templates/summary/summary_commits.mako')
107 def summary_commits(self):
107 def summary_commits(self):
108 c = self.load_default_context()
108 c = self.load_default_context()
109 self._prepare_and_set_clone_url(c)
109 self._prepare_and_set_clone_url(c)
110 self._load_commits_context(c)
110 self._load_commits_context(c)
111 return self._get_template_context(c)
111 return self._get_template_context(c)
112
112
113 @LoginRequired()
113 @LoginRequired()
114 @HasRepoPermissionAnyDecorator(
114 @HasRepoPermissionAnyDecorator(
115 'repository.read', 'repository.write', 'repository.admin')
115 'repository.read', 'repository.write', 'repository.admin')
116 @view_config(
116 @view_config(
117 route_name='repo_summary', request_method='GET',
117 route_name='repo_summary', request_method='GET',
118 renderer='rhodecode:templates/summary/summary.mako')
118 renderer='rhodecode:templates/summary/summary.mako')
119 @view_config(
119 @view_config(
120 route_name='repo_summary_slash', request_method='GET',
120 route_name='repo_summary_slash', request_method='GET',
121 renderer='rhodecode:templates/summary/summary.mako')
121 renderer='rhodecode:templates/summary/summary.mako')
122 @view_config(
122 @view_config(
123 route_name='repo_summary_explicit', request_method='GET',
123 route_name='repo_summary_explicit', request_method='GET',
124 renderer='rhodecode:templates/summary/summary.mako')
124 renderer='rhodecode:templates/summary/summary.mako')
125 def summary(self):
125 def summary(self):
126 c = self.load_default_context()
126 c = self.load_default_context()
127
127
128 # Prepare the clone URL
128 # Prepare the clone URL
129 self._prepare_and_set_clone_url(c)
129 self._prepare_and_set_clone_url(c)
130
130
131 # update every 5 min
132 if self.db_repo.last_commit_cache_update_diff > 60 * 5:
133 self.db_repo.update_commit_cache()
134
135 # If enabled, get statistics data
131 # If enabled, get statistics data
136
137 c.show_stats = bool(self.db_repo.enable_statistics)
132 c.show_stats = bool(self.db_repo.enable_statistics)
138
133
139 stats = Session().query(Statistics) \
134 stats = Session().query(Statistics) \
140 .filter(Statistics.repository == self.db_repo) \
135 .filter(Statistics.repository == self.db_repo) \
141 .scalar()
136 .scalar()
142
137
143 c.stats_percentage = 0
138 c.stats_percentage = 0
144
139
145 if stats and stats.languages:
140 if stats and stats.languages:
146 c.no_data = False is self.db_repo.enable_statistics
141 c.no_data = False is self.db_repo.enable_statistics
147 lang_stats_d = json.loads(stats.languages)
142 lang_stats_d = json.loads(stats.languages)
148
143
149 # Sort first by decreasing count and second by the file extension,
144 # Sort first by decreasing count and second by the file extension,
150 # so we have a consistent output.
145 # so we have a consistent output.
151 lang_stats_items = sorted(lang_stats_d.iteritems(),
146 lang_stats_items = sorted(lang_stats_d.iteritems(),
152 key=lambda k: (-k[1], k[0]))[:10]
147 key=lambda k: (-k[1], k[0]))[:10]
153 lang_stats = [(x, {"count": y,
148 lang_stats = [(x, {"count": y,
154 "desc": LANGUAGES_EXTENSIONS_MAP.get(x)})
149 "desc": LANGUAGES_EXTENSIONS_MAP.get(x)})
155 for x, y in lang_stats_items]
150 for x, y in lang_stats_items]
156
151
157 c.trending_languages = json.dumps(lang_stats)
152 c.trending_languages = json.dumps(lang_stats)
158 else:
153 else:
159 c.no_data = True
154 c.no_data = True
160 c.trending_languages = json.dumps({})
155 c.trending_languages = json.dumps({})
161
156
162 scm_model = ScmModel()
157 scm_model = ScmModel()
163 c.enable_downloads = self.db_repo.enable_downloads
158 c.enable_downloads = self.db_repo.enable_downloads
164 c.repository_followers = scm_model.get_followers(self.db_repo)
159 c.repository_followers = scm_model.get_followers(self.db_repo)
165 c.repository_forks = scm_model.get_forks(self.db_repo)
160 c.repository_forks = scm_model.get_forks(self.db_repo)
166
161
167 # first interaction with the VCS instance after here...
162 # first interaction with the VCS instance after here...
168 if c.repository_requirements_missing:
163 if c.repository_requirements_missing:
169 self.request.override_renderer = \
164 self.request.override_renderer = \
170 'rhodecode:templates/summary/missing_requirements.mako'
165 'rhodecode:templates/summary/missing_requirements.mako'
171 return self._get_template_context(c)
166 return self._get_template_context(c)
172
167
173 c.readme_data, c.readme_file = \
168 c.readme_data, c.readme_file = \
174 self._get_readme_data(self.db_repo, c.visual.default_renderer)
169 self._get_readme_data(self.db_repo, c.visual.default_renderer)
175
170
176 # loads the summary commits template context
171 # loads the summary commits template context
177 self._load_commits_context(c)
172 self._load_commits_context(c)
178
173
179 return self._get_template_context(c)
174 return self._get_template_context(c)
180
175
181 @LoginRequired()
176 @LoginRequired()
182 @HasRepoPermissionAnyDecorator(
177 @HasRepoPermissionAnyDecorator(
183 'repository.read', 'repository.write', 'repository.admin')
178 'repository.read', 'repository.write', 'repository.admin')
184 @view_config(
179 @view_config(
185 route_name='repo_stats', request_method='GET',
180 route_name='repo_stats', request_method='GET',
186 renderer='json_ext')
181 renderer='json_ext')
187 def repo_stats(self):
182 def repo_stats(self):
188 show_stats = bool(self.db_repo.enable_statistics)
183 show_stats = bool(self.db_repo.enable_statistics)
189 repo_id = self.db_repo.repo_id
184 repo_id = self.db_repo.repo_id
190
185
191 landing_commit = self.db_repo.get_landing_commit()
186 landing_commit = self.db_repo.get_landing_commit()
192 if isinstance(landing_commit, EmptyCommit):
187 if isinstance(landing_commit, EmptyCommit):
193 return {'size': 0, 'code_stats': {}}
188 return {'size': 0, 'code_stats': {}}
194
189
195 cache_seconds = safe_int(rhodecode.CONFIG.get('rc_cache.cache_repo.expiration_time'))
190 cache_seconds = safe_int(rhodecode.CONFIG.get('rc_cache.cache_repo.expiration_time'))
196 cache_on = cache_seconds > 0
191 cache_on = cache_seconds > 0
197
192
198 log.debug(
193 log.debug(
199 'Computing REPO STATS for repo_id %s commit_id `%s` '
194 'Computing REPO STATS for repo_id %s commit_id `%s` '
200 'with caching: %s[TTL: %ss]' % (
195 'with caching: %s[TTL: %ss]' % (
201 repo_id, landing_commit, cache_on, cache_seconds or 0))
196 repo_id, landing_commit, cache_on, cache_seconds or 0))
202
197
203 cache_namespace_uid = 'cache_repo.{}'.format(repo_id)
198 cache_namespace_uid = 'cache_repo.{}'.format(repo_id)
204 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
199 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
205
200
206 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
201 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
207 condition=cache_on)
202 condition=cache_on)
208 def compute_stats(repo_id, commit_id, _show_stats):
203 def compute_stats(repo_id, commit_id, _show_stats):
209 code_stats = {}
204 code_stats = {}
210 size = 0
205 size = 0
211 try:
206 try:
212 commit = self.db_repo.get_commit(commit_id)
207 commit = self.db_repo.get_commit(commit_id)
213
208
214 for node in commit.get_filenodes_generator():
209 for node in commit.get_filenodes_generator():
215 size += node.size
210 size += node.size
216 if not _show_stats:
211 if not _show_stats:
217 continue
212 continue
218 ext = string.lower(node.extension)
213 ext = string.lower(node.extension)
219 ext_info = LANGUAGES_EXTENSIONS_MAP.get(ext)
214 ext_info = LANGUAGES_EXTENSIONS_MAP.get(ext)
220 if ext_info:
215 if ext_info:
221 if ext in code_stats:
216 if ext in code_stats:
222 code_stats[ext]['count'] += 1
217 code_stats[ext]['count'] += 1
223 else:
218 else:
224 code_stats[ext] = {"count": 1, "desc": ext_info}
219 code_stats[ext] = {"count": 1, "desc": ext_info}
225 except (EmptyRepositoryError, CommitDoesNotExistError):
220 except (EmptyRepositoryError, CommitDoesNotExistError):
226 pass
221 pass
227 return {'size': h.format_byte_size_binary(size),
222 return {'size': h.format_byte_size_binary(size),
228 'code_stats': code_stats}
223 'code_stats': code_stats}
229
224
230 stats = compute_stats(self.db_repo.repo_id, landing_commit.raw_id, show_stats)
225 stats = compute_stats(self.db_repo.repo_id, landing_commit.raw_id, show_stats)
231 return stats
226 return stats
232
227
233 @LoginRequired()
228 @LoginRequired()
234 @HasRepoPermissionAnyDecorator(
229 @HasRepoPermissionAnyDecorator(
235 'repository.read', 'repository.write', 'repository.admin')
230 'repository.read', 'repository.write', 'repository.admin')
236 @view_config(
231 @view_config(
237 route_name='repo_refs_data', request_method='GET',
232 route_name='repo_refs_data', request_method='GET',
238 renderer='json_ext')
233 renderer='json_ext')
239 def repo_refs_data(self):
234 def repo_refs_data(self):
240 _ = self.request.translate
235 _ = self.request.translate
241 self.load_default_context()
236 self.load_default_context()
242
237
243 repo = self.rhodecode_vcs_repo
238 repo = self.rhodecode_vcs_repo
244 refs_to_create = [
239 refs_to_create = [
245 (_("Branch"), repo.branches, 'branch'),
240 (_("Branch"), repo.branches, 'branch'),
246 (_("Tag"), repo.tags, 'tag'),
241 (_("Tag"), repo.tags, 'tag'),
247 (_("Bookmark"), repo.bookmarks, 'book'),
242 (_("Bookmark"), repo.bookmarks, 'book'),
248 ]
243 ]
249 res = self._create_reference_data(repo, self.db_repo_name, refs_to_create)
244 res = self._create_reference_data(repo, self.db_repo_name, refs_to_create)
250 data = {
245 data = {
251 'more': False,
246 'more': False,
252 'results': res
247 'results': res
253 }
248 }
254 return data
249 return data
255
250
256 @LoginRequired()
251 @LoginRequired()
257 @HasRepoPermissionAnyDecorator(
252 @HasRepoPermissionAnyDecorator(
258 'repository.read', 'repository.write', 'repository.admin')
253 'repository.read', 'repository.write', 'repository.admin')
259 @view_config(
254 @view_config(
260 route_name='repo_refs_changelog_data', request_method='GET',
255 route_name='repo_refs_changelog_data', request_method='GET',
261 renderer='json_ext')
256 renderer='json_ext')
262 def repo_refs_changelog_data(self):
257 def repo_refs_changelog_data(self):
263 _ = self.request.translate
258 _ = self.request.translate
264 self.load_default_context()
259 self.load_default_context()
265
260
266 repo = self.rhodecode_vcs_repo
261 repo = self.rhodecode_vcs_repo
267
262
268 refs_to_create = [
263 refs_to_create = [
269 (_("Branches"), repo.branches, 'branch'),
264 (_("Branches"), repo.branches, 'branch'),
270 (_("Closed branches"), repo.branches_closed, 'branch_closed'),
265 (_("Closed branches"), repo.branches_closed, 'branch_closed'),
271 # TODO: enable when vcs can handle bookmarks filters
266 # TODO: enable when vcs can handle bookmarks filters
272 # (_("Bookmarks"), repo.bookmarks, "book"),
267 # (_("Bookmarks"), repo.bookmarks, "book"),
273 ]
268 ]
274 res = self._create_reference_data(
269 res = self._create_reference_data(
275 repo, self.db_repo_name, refs_to_create)
270 repo, self.db_repo_name, refs_to_create)
276 data = {
271 data = {
277 'more': False,
272 'more': False,
278 'results': res
273 'results': res
279 }
274 }
280 return data
275 return data
281
276
282 def _create_reference_data(self, repo, full_repo_name, refs_to_create):
277 def _create_reference_data(self, repo, full_repo_name, refs_to_create):
283 format_ref_id = get_format_ref_id(repo)
278 format_ref_id = get_format_ref_id(repo)
284
279
285 result = []
280 result = []
286 for title, refs, ref_type in refs_to_create:
281 for title, refs, ref_type in refs_to_create:
287 if refs:
282 if refs:
288 result.append({
283 result.append({
289 'text': title,
284 'text': title,
290 'children': self._create_reference_items(
285 'children': self._create_reference_items(
291 repo, full_repo_name, refs, ref_type,
286 repo, full_repo_name, refs, ref_type,
292 format_ref_id),
287 format_ref_id),
293 })
288 })
294 return result
289 return result
295
290
296 def _create_reference_items(self, repo, full_repo_name, refs, ref_type, format_ref_id):
291 def _create_reference_items(self, repo, full_repo_name, refs, ref_type, format_ref_id):
297 result = []
292 result = []
298 is_svn = h.is_svn(repo)
293 is_svn = h.is_svn(repo)
299 for ref_name, raw_id in refs.iteritems():
294 for ref_name, raw_id in refs.iteritems():
300 files_url = self._create_files_url(
295 files_url = self._create_files_url(
301 repo, full_repo_name, ref_name, raw_id, is_svn)
296 repo, full_repo_name, ref_name, raw_id, is_svn)
302 result.append({
297 result.append({
303 'text': ref_name,
298 'text': ref_name,
304 'id': format_ref_id(ref_name, raw_id),
299 'id': format_ref_id(ref_name, raw_id),
305 'raw_id': raw_id,
300 'raw_id': raw_id,
306 'type': ref_type,
301 'type': ref_type,
307 'files_url': files_url,
302 'files_url': files_url,
308 'idx': 0,
303 'idx': 0,
309 })
304 })
310 return result
305 return result
311
306
312 def _create_files_url(self, repo, full_repo_name, ref_name, raw_id, is_svn):
307 def _create_files_url(self, repo, full_repo_name, ref_name, raw_id, is_svn):
313 use_commit_id = '/' in ref_name or is_svn
308 use_commit_id = '/' in ref_name or is_svn
314 return h.route_path(
309 return h.route_path(
315 'repo_files',
310 'repo_files',
316 repo_name=full_repo_name,
311 repo_name=full_repo_name,
317 f_path=ref_name if is_svn else '',
312 f_path=ref_name if is_svn else '',
318 commit_id=raw_id if use_commit_id else ref_name,
313 commit_id=raw_id if use_commit_id else ref_name,
319 _query=dict(at=ref_name))
314 _query=dict(at=ref_name))
General Comments 0
You need to be logged in to leave comments. Login now