##// END OF EJS Templates
Summary: Split the readme logic into sub-methods
johbo -
r769:bd21d310 default
parent child Browse files
Show More
@@ -1,301 +1,306 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 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 """
21 """
22 Summary controller for RhodeCode Enterprise
22 Summary controller for RhodeCode Enterprise
23 """
23 """
24
24
25 import logging
25 import logging
26 from string import lower
26 from string import lower
27
27
28 from pylons import tmpl_context as c, request
28 from pylons import tmpl_context as c, request
29 from pylons.i18n.translation import _
29 from pylons.i18n.translation import _
30 from beaker.cache import cache_region, region_invalidate
30 from beaker.cache import cache_region, region_invalidate
31
31
32 from rhodecode.config.conf import (LANGUAGES_EXTENSIONS_MAP)
32 from rhodecode.config.conf import (LANGUAGES_EXTENSIONS_MAP)
33 from rhodecode.controllers import utils
33 from rhodecode.controllers import utils
34 from rhodecode.controllers.changelog import _load_changelog_summary
34 from rhodecode.controllers.changelog import _load_changelog_summary
35 from rhodecode.lib import caches, helpers as h
35 from rhodecode.lib import caches, helpers as h
36 from rhodecode.lib.utils import jsonify
36 from rhodecode.lib.utils import jsonify
37 from rhodecode.lib.utils2 import safe_str
37 from rhodecode.lib.utils2 import safe_str
38 from rhodecode.lib.auth import (
38 from rhodecode.lib.auth import (
39 LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous, XHRRequired)
39 LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous, XHRRequired)
40 from rhodecode.lib.base import BaseRepoController, render
40 from rhodecode.lib.base import BaseRepoController, render
41 from rhodecode.lib.markup_renderer import MarkupRenderer
41 from rhodecode.lib.markup_renderer import MarkupRenderer
42 from rhodecode.lib.ext_json import json
42 from rhodecode.lib.ext_json import json
43 from rhodecode.lib.vcs.backends.base import EmptyCommit
43 from rhodecode.lib.vcs.backends.base import EmptyCommit
44 from rhodecode.lib.vcs.exceptions import (
44 from rhodecode.lib.vcs.exceptions import (
45 CommitError, EmptyRepositoryError, NodeDoesNotExistError)
45 CommitError, EmptyRepositoryError, NodeDoesNotExistError)
46 from rhodecode.model.db import Statistics, CacheKey, User
46 from rhodecode.model.db import Statistics, CacheKey, User
47 from rhodecode.model.repo import ReadmeFinder
47 from rhodecode.model.repo import ReadmeFinder
48
48
49
49
50 log = logging.getLogger(__name__)
50 log = logging.getLogger(__name__)
51
51
52
52
53 class SummaryController(BaseRepoController):
53 class SummaryController(BaseRepoController):
54
54
55 def __before__(self):
55 def __before__(self):
56 super(SummaryController, self).__before__()
56 super(SummaryController, self).__before__()
57
57
58 def __get_readme_data(self, db_repo):
58 def __get_readme_data(self, db_repo):
59 repo_name = db_repo.repo_name
59 repo_name = db_repo.repo_name
60 log.debug('Looking for README file')
60 log.debug('Looking for README file')
61 default_renderer = c.visual.default_renderer
61 default_renderer = c.visual.default_renderer
62
62
63 @cache_region('long_term')
63 @cache_region('long_term')
64 def _generate_readme(cache_key):
64 def _generate_readme(cache_key):
65 readme_data = None
65 readme_data = None
66 readme_file = None
66 readme_file = None
67 try:
67 commit = self._get_landing_commit_or_none(db_repo)
68 # Find the landing commit
68 if commit:
69 commit = db_repo.get_landing_commit()
69 log.debug("Searching for a README file.")
70 if isinstance(commit, EmptyCommit):
71 raise EmptyRepositoryError()
72
73 readme_file = ReadmeFinder(default_renderer).search(commit)
70 readme_file = ReadmeFinder(default_renderer).search(commit)
74
71 if readme_file:
75 # Render the readme if one was found
72 readme_data = self._render_readme_or_none(commit, readme_file)
76 if readme_file:
77 renderer = MarkupRenderer()
78 node = commit.get_node(readme_file)
79 log.debug('Found README file `%s` rendering...',
80 readme_file)
81 readme_data = renderer.render(
82 node.content, filename=readme_file)
83 except CommitError:
84 log.exception(
85 "Problem getting commit when trying to render the README.")
86 except EmptyRepositoryError:
87 log.debug("Repository is empty, no README to render.")
88 except Exception:
89 log.exception("Exception while trying to render the README")
90
91 return readme_data, readme_file
73 return readme_data, readme_file
92
74
93 invalidator_context = CacheKey.repo_context_cache(
75 invalidator_context = CacheKey.repo_context_cache(
94 _generate_readme, repo_name, CacheKey.CACHE_TYPE_README)
76 _generate_readme, repo_name, CacheKey.CACHE_TYPE_README)
95
77
96 with invalidator_context as context:
78 with invalidator_context as context:
97 context.invalidate()
79 context.invalidate()
98 computed = context.compute()
80 computed = context.compute()
99
81
100 return computed
82 return computed
101
83
84 def _get_landing_commit_or_none(self, db_repo):
85 log.debug("Getting the landing commit.")
86 try:
87 commit = db_repo.get_landing_commit()
88 if not isinstance(commit, EmptyCommit):
89 return commit
90 else:
91 log.debug("Repository is empty, no README to render.")
92 except CommitError:
93 log.exception(
94 "Problem getting commit when trying to render the README.")
95
96 def _render_readme_or_none(self, commit, readme_file):
97 log.debug(
98 'Found README file `%s` rendering...', readme_file)
99 renderer = MarkupRenderer()
100 node = commit.get_node(readme_file)
101 try:
102 return renderer.render(node.content, filename=readme_file)
103 except Exception:
104 log.exception(
105 "Exception while trying to render the README")
106
102 @LoginRequired()
107 @LoginRequired()
103 @HasRepoPermissionAnyDecorator(
108 @HasRepoPermissionAnyDecorator(
104 'repository.read', 'repository.write', 'repository.admin')
109 'repository.read', 'repository.write', 'repository.admin')
105 def index(self, repo_name):
110 def index(self, repo_name):
106
111
107 # Prepare the clone URL
112 # Prepare the clone URL
108
113
109 username = ''
114 username = ''
110 if c.rhodecode_user.username != User.DEFAULT_USER:
115 if c.rhodecode_user.username != User.DEFAULT_USER:
111 username = safe_str(c.rhodecode_user.username)
116 username = safe_str(c.rhodecode_user.username)
112
117
113 _def_clone_uri = _def_clone_uri_by_id = c.clone_uri_tmpl
118 _def_clone_uri = _def_clone_uri_by_id = c.clone_uri_tmpl
114 if '{repo}' in _def_clone_uri:
119 if '{repo}' in _def_clone_uri:
115 _def_clone_uri_by_id = _def_clone_uri.replace(
120 _def_clone_uri_by_id = _def_clone_uri.replace(
116 '{repo}', '_{repoid}')
121 '{repo}', '_{repoid}')
117 elif '{repoid}' in _def_clone_uri:
122 elif '{repoid}' in _def_clone_uri:
118 _def_clone_uri_by_id = _def_clone_uri.replace(
123 _def_clone_uri_by_id = _def_clone_uri.replace(
119 '_{repoid}', '{repo}')
124 '_{repoid}', '{repo}')
120
125
121 c.clone_repo_url = c.rhodecode_db_repo.clone_url(
126 c.clone_repo_url = c.rhodecode_db_repo.clone_url(
122 user=username, uri_tmpl=_def_clone_uri)
127 user=username, uri_tmpl=_def_clone_uri)
123 c.clone_repo_url_id = c.rhodecode_db_repo.clone_url(
128 c.clone_repo_url_id = c.rhodecode_db_repo.clone_url(
124 user=username, uri_tmpl=_def_clone_uri_by_id)
129 user=username, uri_tmpl=_def_clone_uri_by_id)
125
130
126 # If enabled, get statistics data
131 # If enabled, get statistics data
127
132
128 c.show_stats = bool(c.rhodecode_db_repo.enable_statistics)
133 c.show_stats = bool(c.rhodecode_db_repo.enable_statistics)
129
134
130 stats = self.sa.query(Statistics)\
135 stats = self.sa.query(Statistics)\
131 .filter(Statistics.repository == c.rhodecode_db_repo)\
136 .filter(Statistics.repository == c.rhodecode_db_repo)\
132 .scalar()
137 .scalar()
133
138
134 c.stats_percentage = 0
139 c.stats_percentage = 0
135
140
136 if stats and stats.languages:
141 if stats and stats.languages:
137 c.no_data = False is c.rhodecode_db_repo.enable_statistics
142 c.no_data = False is c.rhodecode_db_repo.enable_statistics
138 lang_stats_d = json.loads(stats.languages)
143 lang_stats_d = json.loads(stats.languages)
139
144
140 # Sort first by decreasing count and second by the file extension,
145 # Sort first by decreasing count and second by the file extension,
141 # so we have a consistent output.
146 # so we have a consistent output.
142 lang_stats_items = sorted(lang_stats_d.iteritems(),
147 lang_stats_items = sorted(lang_stats_d.iteritems(),
143 key=lambda k: (-k[1], k[0]))[:10]
148 key=lambda k: (-k[1], k[0]))[:10]
144 lang_stats = [(x, {"count": y,
149 lang_stats = [(x, {"count": y,
145 "desc": LANGUAGES_EXTENSIONS_MAP.get(x)})
150 "desc": LANGUAGES_EXTENSIONS_MAP.get(x)})
146 for x, y in lang_stats_items]
151 for x, y in lang_stats_items]
147
152
148 c.trending_languages = json.dumps(lang_stats)
153 c.trending_languages = json.dumps(lang_stats)
149 else:
154 else:
150 c.no_data = True
155 c.no_data = True
151 c.trending_languages = json.dumps({})
156 c.trending_languages = json.dumps({})
152
157
153 c.enable_downloads = c.rhodecode_db_repo.enable_downloads
158 c.enable_downloads = c.rhodecode_db_repo.enable_downloads
154 c.repository_followers = self.scm_model.get_followers(
159 c.repository_followers = self.scm_model.get_followers(
155 c.rhodecode_db_repo)
160 c.rhodecode_db_repo)
156 c.repository_forks = self.scm_model.get_forks(c.rhodecode_db_repo)
161 c.repository_forks = self.scm_model.get_forks(c.rhodecode_db_repo)
157 c.repository_is_user_following = self.scm_model.is_following_repo(
162 c.repository_is_user_following = self.scm_model.is_following_repo(
158 c.repo_name, c.rhodecode_user.user_id)
163 c.repo_name, c.rhodecode_user.user_id)
159
164
160 if c.repository_requirements_missing:
165 if c.repository_requirements_missing:
161 return render('summary/missing_requirements.html')
166 return render('summary/missing_requirements.html')
162
167
163 c.readme_data, c.readme_file = \
168 c.readme_data, c.readme_file = \
164 self.__get_readme_data(c.rhodecode_db_repo)
169 self.__get_readme_data(c.rhodecode_db_repo)
165
170
166 _load_changelog_summary()
171 _load_changelog_summary()
167
172
168 if request.is_xhr:
173 if request.is_xhr:
169 return render('changelog/changelog_summary_data.html')
174 return render('changelog/changelog_summary_data.html')
170
175
171 return render('summary/summary.html')
176 return render('summary/summary.html')
172
177
173 @LoginRequired()
178 @LoginRequired()
174 @XHRRequired()
179 @XHRRequired()
175 @HasRepoPermissionAnyDecorator(
180 @HasRepoPermissionAnyDecorator(
176 'repository.read', 'repository.write', 'repository.admin')
181 'repository.read', 'repository.write', 'repository.admin')
177 @jsonify
182 @jsonify
178 def repo_stats(self, repo_name, commit_id):
183 def repo_stats(self, repo_name, commit_id):
179 _namespace = caches.get_repo_namespace_key(
184 _namespace = caches.get_repo_namespace_key(
180 caches.SUMMARY_STATS, repo_name)
185 caches.SUMMARY_STATS, repo_name)
181 show_stats = bool(c.rhodecode_db_repo.enable_statistics)
186 show_stats = bool(c.rhodecode_db_repo.enable_statistics)
182 cache_manager = caches.get_cache_manager('repo_cache_long', _namespace)
187 cache_manager = caches.get_cache_manager('repo_cache_long', _namespace)
183 _cache_key = caches.compute_key_from_params(
188 _cache_key = caches.compute_key_from_params(
184 repo_name, commit_id, show_stats)
189 repo_name, commit_id, show_stats)
185
190
186 def compute_stats():
191 def compute_stats():
187 code_stats = {}
192 code_stats = {}
188 size = 0
193 size = 0
189 try:
194 try:
190 scm_instance = c.rhodecode_db_repo.scm_instance()
195 scm_instance = c.rhodecode_db_repo.scm_instance()
191 commit = scm_instance.get_commit(commit_id)
196 commit = scm_instance.get_commit(commit_id)
192
197
193 for node in commit.get_filenodes_generator():
198 for node in commit.get_filenodes_generator():
194 size += node.size
199 size += node.size
195 if not show_stats:
200 if not show_stats:
196 continue
201 continue
197 ext = lower(node.extension)
202 ext = lower(node.extension)
198 ext_info = LANGUAGES_EXTENSIONS_MAP.get(ext)
203 ext_info = LANGUAGES_EXTENSIONS_MAP.get(ext)
199 if ext_info:
204 if ext_info:
200 if ext in code_stats:
205 if ext in code_stats:
201 code_stats[ext]['count'] += 1
206 code_stats[ext]['count'] += 1
202 else:
207 else:
203 code_stats[ext] = {"count": 1, "desc": ext_info}
208 code_stats[ext] = {"count": 1, "desc": ext_info}
204 except EmptyRepositoryError:
209 except EmptyRepositoryError:
205 pass
210 pass
206 return {'size': h.format_byte_size_binary(size),
211 return {'size': h.format_byte_size_binary(size),
207 'code_stats': code_stats}
212 'code_stats': code_stats}
208
213
209 stats = cache_manager.get(_cache_key, createfunc=compute_stats)
214 stats = cache_manager.get(_cache_key, createfunc=compute_stats)
210 return stats
215 return stats
211
216
212 def _switcher_reference_data(self, repo_name, references, is_svn):
217 def _switcher_reference_data(self, repo_name, references, is_svn):
213 """Prepare reference data for given `references`"""
218 """Prepare reference data for given `references`"""
214 items = []
219 items = []
215 for name, commit_id in references.items():
220 for name, commit_id in references.items():
216 use_commit_id = '/' in name or is_svn
221 use_commit_id = '/' in name or is_svn
217 items.append({
222 items.append({
218 'name': name,
223 'name': name,
219 'commit_id': commit_id,
224 'commit_id': commit_id,
220 'files_url': h.url(
225 'files_url': h.url(
221 'files_home',
226 'files_home',
222 repo_name=repo_name,
227 repo_name=repo_name,
223 f_path=name if is_svn else '',
228 f_path=name if is_svn else '',
224 revision=commit_id if use_commit_id else name,
229 revision=commit_id if use_commit_id else name,
225 at=name)
230 at=name)
226 })
231 })
227 return items
232 return items
228
233
229 @LoginRequired()
234 @LoginRequired()
230 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
235 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
231 'repository.admin')
236 'repository.admin')
232 @jsonify
237 @jsonify
233 def repo_refs_data(self, repo_name):
238 def repo_refs_data(self, repo_name):
234 repo = c.rhodecode_repo
239 repo = c.rhodecode_repo
235 refs_to_create = [
240 refs_to_create = [
236 (_("Branch"), repo.branches, 'branch'),
241 (_("Branch"), repo.branches, 'branch'),
237 (_("Tag"), repo.tags, 'tag'),
242 (_("Tag"), repo.tags, 'tag'),
238 (_("Bookmark"), repo.bookmarks, 'book'),
243 (_("Bookmark"), repo.bookmarks, 'book'),
239 ]
244 ]
240 res = self._create_reference_data(repo, repo_name, refs_to_create)
245 res = self._create_reference_data(repo, repo_name, refs_to_create)
241 data = {
246 data = {
242 'more': False,
247 'more': False,
243 'results': res
248 'results': res
244 }
249 }
245 return data
250 return data
246
251
247 @jsonify
252 @jsonify
248 def repo_refs_changelog_data(self, repo_name):
253 def repo_refs_changelog_data(self, repo_name):
249 repo = c.rhodecode_repo
254 repo = c.rhodecode_repo
250
255
251 refs_to_create = [
256 refs_to_create = [
252 (_("Branches"), repo.branches, 'branch'),
257 (_("Branches"), repo.branches, 'branch'),
253 (_("Closed branches"), repo.branches_closed, 'branch_closed'),
258 (_("Closed branches"), repo.branches_closed, 'branch_closed'),
254 # TODO: enable when vcs can handle bookmarks filters
259 # TODO: enable when vcs can handle bookmarks filters
255 # (_("Bookmarks"), repo.bookmarks, "book"),
260 # (_("Bookmarks"), repo.bookmarks, "book"),
256 ]
261 ]
257 res = self._create_reference_data(repo, repo_name, refs_to_create)
262 res = self._create_reference_data(repo, repo_name, refs_to_create)
258 data = {
263 data = {
259 'more': False,
264 'more': False,
260 'results': res
265 'results': res
261 }
266 }
262 return data
267 return data
263
268
264 def _create_reference_data(self, repo, full_repo_name, refs_to_create):
269 def _create_reference_data(self, repo, full_repo_name, refs_to_create):
265 format_ref_id = utils.get_format_ref_id(repo)
270 format_ref_id = utils.get_format_ref_id(repo)
266
271
267 result = []
272 result = []
268 for title, refs, ref_type in refs_to_create:
273 for title, refs, ref_type in refs_to_create:
269 if refs:
274 if refs:
270 result.append({
275 result.append({
271 'text': title,
276 'text': title,
272 'children': self._create_reference_items(
277 'children': self._create_reference_items(
273 repo, full_repo_name, refs, ref_type, format_ref_id),
278 repo, full_repo_name, refs, ref_type, format_ref_id),
274 })
279 })
275 return result
280 return result
276
281
277 def _create_reference_items(self, repo, full_repo_name, refs, ref_type,
282 def _create_reference_items(self, repo, full_repo_name, refs, ref_type,
278 format_ref_id):
283 format_ref_id):
279 result = []
284 result = []
280 is_svn = h.is_svn(repo)
285 is_svn = h.is_svn(repo)
281 for ref_name, raw_id in refs.iteritems():
286 for ref_name, raw_id in refs.iteritems():
282 files_url = self._create_files_url(
287 files_url = self._create_files_url(
283 repo, full_repo_name, ref_name, raw_id, is_svn)
288 repo, full_repo_name, ref_name, raw_id, is_svn)
284 result.append({
289 result.append({
285 'text': ref_name,
290 'text': ref_name,
286 'id': format_ref_id(ref_name, raw_id),
291 'id': format_ref_id(ref_name, raw_id),
287 'raw_id': raw_id,
292 'raw_id': raw_id,
288 'type': ref_type,
293 'type': ref_type,
289 'files_url': files_url,
294 'files_url': files_url,
290 })
295 })
291 return result
296 return result
292
297
293 def _create_files_url(self, repo, full_repo_name, ref_name, raw_id,
298 def _create_files_url(self, repo, full_repo_name, ref_name, raw_id,
294 is_svn):
299 is_svn):
295 use_commit_id = '/' in ref_name or is_svn
300 use_commit_id = '/' in ref_name or is_svn
296 return h.url(
301 return h.url(
297 'files_home',
302 'files_home',
298 repo_name=full_repo_name,
303 repo_name=full_repo_name,
299 f_path=ref_name if is_svn else '',
304 f_path=ref_name if is_svn else '',
300 revision=raw_id if use_commit_id else ref_name,
305 revision=raw_id if use_commit_id else ref_name,
301 at=ref_name)
306 at=ref_name)
General Comments 0
You need to be logged in to leave comments. Login now