##// END OF EJS Templates
Don't scan for readmes if changeset is an EmptyChangeset
marcink -
r2788:2d6d6c34 beta
parent child Browse files
Show More
@@ -1,245 +1,247 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.summary
3 rhodecode.controllers.summary
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Summary controller for Rhodecode
6 Summary controller for Rhodecode
7
7
8 :created_on: Apr 18, 2010
8 :created_on: Apr 18, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import traceback
26 import traceback
27 import calendar
27 import calendar
28 import logging
28 import logging
29 import urllib
29 import urllib
30 from time import mktime
30 from time import mktime
31 from datetime import timedelta, date
31 from datetime import timedelta, date
32 from urlparse import urlparse
32 from urlparse import urlparse
33 from rhodecode.lib.compat import product
33 from rhodecode.lib.compat import product
34
34
35 from rhodecode.lib.vcs.exceptions import ChangesetError, EmptyRepositoryError, \
35 from rhodecode.lib.vcs.exceptions import ChangesetError, EmptyRepositoryError, \
36 NodeDoesNotExistError
36 NodeDoesNotExistError
37
37
38 from pylons import tmpl_context as c, request, url, config
38 from pylons import tmpl_context as c, request, url, config
39 from pylons.i18n.translation import _
39 from pylons.i18n.translation import _
40
40
41 from beaker.cache import cache_region, region_invalidate
41 from beaker.cache import cache_region, region_invalidate
42
42
43 from rhodecode.config.conf import ALL_READMES, ALL_EXTS, LANGUAGES_EXTENSIONS_MAP
43 from rhodecode.config.conf import ALL_READMES, ALL_EXTS, LANGUAGES_EXTENSIONS_MAP
44 from rhodecode.model.db import Statistics, CacheInvalidation
44 from rhodecode.model.db import Statistics, CacheInvalidation
45 from rhodecode.lib.utils2 import safe_unicode
45 from rhodecode.lib.utils2 import safe_unicode
46 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
46 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
47 from rhodecode.lib.base import BaseRepoController, render
47 from rhodecode.lib.base import BaseRepoController, render
48 from rhodecode.lib.vcs.backends.base import EmptyChangeset
48 from rhodecode.lib.vcs.backends.base import EmptyChangeset
49 from rhodecode.lib.markup_renderer import MarkupRenderer
49 from rhodecode.lib.markup_renderer import MarkupRenderer
50 from rhodecode.lib.celerylib import run_task
50 from rhodecode.lib.celerylib import run_task
51 from rhodecode.lib.celerylib.tasks import get_commits_stats
51 from rhodecode.lib.celerylib.tasks import get_commits_stats
52 from rhodecode.lib.helpers import RepoPage
52 from rhodecode.lib.helpers import RepoPage
53 from rhodecode.lib.compat import json, OrderedDict
53 from rhodecode.lib.compat import json, OrderedDict
54 from rhodecode.lib.vcs.nodes import FileNode
54 from rhodecode.lib.vcs.nodes import FileNode
55
55
56 log = logging.getLogger(__name__)
56 log = logging.getLogger(__name__)
57
57
58 README_FILES = [''.join([x[0][0], x[1][0]]) for x in
58 README_FILES = [''.join([x[0][0], x[1][0]]) for x in
59 sorted(list(product(ALL_READMES, ALL_EXTS)),
59 sorted(list(product(ALL_READMES, ALL_EXTS)),
60 key=lambda y:y[0][1] + y[1][1])]
60 key=lambda y:y[0][1] + y[1][1])]
61
61
62
62
63 class SummaryController(BaseRepoController):
63 class SummaryController(BaseRepoController):
64
64
65 @LoginRequired()
65 @LoginRequired()
66 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
66 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
67 'repository.admin')
67 'repository.admin')
68 def __before__(self):
68 def __before__(self):
69 super(SummaryController, self).__before__()
69 super(SummaryController, self).__before__()
70
70
71 def index(self, repo_name):
71 def index(self, repo_name):
72 c.dbrepo = dbrepo = c.rhodecode_db_repo
72 c.dbrepo = dbrepo = c.rhodecode_db_repo
73 c.following = self.scm_model.is_following_repo(repo_name,
73 c.following = self.scm_model.is_following_repo(repo_name,
74 self.rhodecode_user.user_id)
74 self.rhodecode_user.user_id)
75
75
76 def url_generator(**kw):
76 def url_generator(**kw):
77 return url('shortlog_home', repo_name=repo_name, size=10, **kw)
77 return url('shortlog_home', repo_name=repo_name, size=10, **kw)
78
78
79 c.repo_changesets = RepoPage(c.rhodecode_repo, page=1,
79 c.repo_changesets = RepoPage(c.rhodecode_repo, page=1,
80 items_per_page=10, url=url_generator)
80 items_per_page=10, url=url_generator)
81
81
82 if self.rhodecode_user.username == 'default':
82 if self.rhodecode_user.username == 'default':
83 # for default(anonymous) user we don't need to pass credentials
83 # for default(anonymous) user we don't need to pass credentials
84 username = ''
84 username = ''
85 password = ''
85 password = ''
86 else:
86 else:
87 username = str(self.rhodecode_user.username)
87 username = str(self.rhodecode_user.username)
88 password = '@'
88 password = '@'
89
89
90 parsed_url = urlparse(url.current(qualified=True))
90 parsed_url = urlparse(url.current(qualified=True))
91
91
92 default_clone_uri = '{scheme}://{user}{pass}{netloc}{path}'
92 default_clone_uri = '{scheme}://{user}{pass}{netloc}{path}'
93
93
94 uri_tmpl = config.get('clone_uri', default_clone_uri)
94 uri_tmpl = config.get('clone_uri', default_clone_uri)
95 uri_tmpl = uri_tmpl.replace('{', '%(').replace('}', ')s')
95 uri_tmpl = uri_tmpl.replace('{', '%(').replace('}', ')s')
96 decoded_path = safe_unicode(urllib.unquote(parsed_url.path))
96 decoded_path = safe_unicode(urllib.unquote(parsed_url.path))
97 uri_dict = {
97 uri_dict = {
98 'user': username,
98 'user': username,
99 'pass': password,
99 'pass': password,
100 'scheme': parsed_url.scheme,
100 'scheme': parsed_url.scheme,
101 'netloc': parsed_url.netloc,
101 'netloc': parsed_url.netloc,
102 'path': decoded_path
102 'path': decoded_path
103 }
103 }
104
104
105 uri = uri_tmpl % uri_dict
105 uri = uri_tmpl % uri_dict
106 # generate another clone url by id
106 # generate another clone url by id
107 uri_dict.update(
107 uri_dict.update(
108 {'path': decoded_path.replace(repo_name, '_%s' % c.dbrepo.repo_id)}
108 {'path': decoded_path.replace(repo_name, '_%s' % c.dbrepo.repo_id)}
109 )
109 )
110 uri_id = uri_tmpl % uri_dict
110 uri_id = uri_tmpl % uri_dict
111
111
112 c.clone_repo_url = uri
112 c.clone_repo_url = uri
113 c.clone_repo_url_id = uri_id
113 c.clone_repo_url_id = uri_id
114 c.repo_tags = OrderedDict()
114 c.repo_tags = OrderedDict()
115 for name, hash_ in c.rhodecode_repo.tags.items()[:10]:
115 for name, hash_ in c.rhodecode_repo.tags.items()[:10]:
116 try:
116 try:
117 c.repo_tags[name] = c.rhodecode_repo.get_changeset(hash_)
117 c.repo_tags[name] = c.rhodecode_repo.get_changeset(hash_)
118 except ChangesetError:
118 except ChangesetError:
119 c.repo_tags[name] = EmptyChangeset(hash_)
119 c.repo_tags[name] = EmptyChangeset(hash_)
120
120
121 c.repo_branches = OrderedDict()
121 c.repo_branches = OrderedDict()
122 for name, hash_ in c.rhodecode_repo.branches.items()[:10]:
122 for name, hash_ in c.rhodecode_repo.branches.items()[:10]:
123 try:
123 try:
124 c.repo_branches[name] = c.rhodecode_repo.get_changeset(hash_)
124 c.repo_branches[name] = c.rhodecode_repo.get_changeset(hash_)
125 except ChangesetError:
125 except ChangesetError:
126 c.repo_branches[name] = EmptyChangeset(hash_)
126 c.repo_branches[name] = EmptyChangeset(hash_)
127
127
128 td = date.today() + timedelta(days=1)
128 td = date.today() + timedelta(days=1)
129 td_1m = td - timedelta(days=calendar.mdays[td.month])
129 td_1m = td - timedelta(days=calendar.mdays[td.month])
130 td_1y = td - timedelta(days=365)
130 td_1y = td - timedelta(days=365)
131
131
132 ts_min_m = mktime(td_1m.timetuple())
132 ts_min_m = mktime(td_1m.timetuple())
133 ts_min_y = mktime(td_1y.timetuple())
133 ts_min_y = mktime(td_1y.timetuple())
134 ts_max_y = mktime(td.timetuple())
134 ts_max_y = mktime(td.timetuple())
135
135
136 if dbrepo.enable_statistics:
136 if dbrepo.enable_statistics:
137 c.show_stats = True
137 c.show_stats = True
138 c.no_data_msg = _('No data loaded yet')
138 c.no_data_msg = _('No data loaded yet')
139 run_task(get_commits_stats, c.dbrepo.repo_name, ts_min_y, ts_max_y)
139 run_task(get_commits_stats, c.dbrepo.repo_name, ts_min_y, ts_max_y)
140 else:
140 else:
141 c.show_stats = False
141 c.show_stats = False
142 c.no_data_msg = _('Statistics are disabled for this repository')
142 c.no_data_msg = _('Statistics are disabled for this repository')
143 c.ts_min = ts_min_m
143 c.ts_min = ts_min_m
144 c.ts_max = ts_max_y
144 c.ts_max = ts_max_y
145
145
146 stats = self.sa.query(Statistics)\
146 stats = self.sa.query(Statistics)\
147 .filter(Statistics.repository == dbrepo)\
147 .filter(Statistics.repository == dbrepo)\
148 .scalar()
148 .scalar()
149
149
150 c.stats_percentage = 0
150 c.stats_percentage = 0
151
151
152 if stats and stats.languages:
152 if stats and stats.languages:
153 c.no_data = False is dbrepo.enable_statistics
153 c.no_data = False is dbrepo.enable_statistics
154 lang_stats_d = json.loads(stats.languages)
154 lang_stats_d = json.loads(stats.languages)
155 c.commit_data = stats.commit_activity
155 c.commit_data = stats.commit_activity
156 c.overview_data = stats.commit_activity_combined
156 c.overview_data = stats.commit_activity_combined
157
157
158 lang_stats = ((x, {"count": y,
158 lang_stats = ((x, {"count": y,
159 "desc": LANGUAGES_EXTENSIONS_MAP.get(x)})
159 "desc": LANGUAGES_EXTENSIONS_MAP.get(x)})
160 for x, y in lang_stats_d.items())
160 for x, y in lang_stats_d.items())
161
161
162 c.trending_languages = json.dumps(
162 c.trending_languages = json.dumps(
163 sorted(lang_stats, reverse=True, key=lambda k: k[1])[:10]
163 sorted(lang_stats, reverse=True, key=lambda k: k[1])[:10]
164 )
164 )
165 last_rev = stats.stat_on_revision + 1
165 last_rev = stats.stat_on_revision + 1
166 c.repo_last_rev = c.rhodecode_repo.count()\
166 c.repo_last_rev = c.rhodecode_repo.count()\
167 if c.rhodecode_repo.revisions else 0
167 if c.rhodecode_repo.revisions else 0
168 if last_rev == 0 or c.repo_last_rev == 0:
168 if last_rev == 0 or c.repo_last_rev == 0:
169 pass
169 pass
170 else:
170 else:
171 c.stats_percentage = '%.2f' % ((float((last_rev)) /
171 c.stats_percentage = '%.2f' % ((float((last_rev)) /
172 c.repo_last_rev) * 100)
172 c.repo_last_rev) * 100)
173 else:
173 else:
174 c.commit_data = json.dumps({})
174 c.commit_data = json.dumps({})
175 c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10]])
175 c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10]])
176 c.trending_languages = json.dumps({})
176 c.trending_languages = json.dumps({})
177 c.no_data = True
177 c.no_data = True
178
178
179 c.enable_downloads = dbrepo.enable_downloads
179 c.enable_downloads = dbrepo.enable_downloads
180 if c.enable_downloads:
180 if c.enable_downloads:
181 c.download_options = self._get_download_links(c.rhodecode_repo)
181 c.download_options = self._get_download_links(c.rhodecode_repo)
182
182
183 c.readme_data, c.readme_file = \
183 c.readme_data, c.readme_file = \
184 self.__get_readme_data(c.rhodecode_db_repo)
184 self.__get_readme_data(c.rhodecode_db_repo)
185 return render('summary/summary.html')
185 return render('summary/summary.html')
186
186
187 def __get_readme_data(self, db_repo):
187 def __get_readme_data(self, db_repo):
188 repo_name = db_repo.repo_name
188 repo_name = db_repo.repo_name
189
189
190 @cache_region('long_term')
190 @cache_region('long_term')
191 def _get_readme_from_cache(key):
191 def _get_readme_from_cache(key):
192 readme_data = None
192 readme_data = None
193 readme_file = None
193 readme_file = None
194 log.debug('Looking for README file')
194 log.debug('Looking for README file')
195 try:
195 try:
196 # get's the landing revision! or tip if fails
196 # get's the landing revision! or tip if fails
197 cs = db_repo.get_landing_changeset()
197 cs = db_repo.get_landing_changeset()
198 if isinstance(cs, EmptyChangeset):
199 raise EmptyRepositoryError()
198 renderer = MarkupRenderer()
200 renderer = MarkupRenderer()
199 for f in README_FILES:
201 for f in README_FILES:
200 try:
202 try:
201 readme = cs.get_node(f)
203 readme = cs.get_node(f)
202 if not isinstance(readme, FileNode):
204 if not isinstance(readme, FileNode):
203 continue
205 continue
204 readme_file = f
206 readme_file = f
205 log.debug('Found README file `%s` rendering...' %
207 log.debug('Found README file `%s` rendering...' %
206 readme_file)
208 readme_file)
207 readme_data = renderer.render(readme.content, f)
209 readme_data = renderer.render(readme.content, f)
208 break
210 break
209 except NodeDoesNotExistError:
211 except NodeDoesNotExistError:
210 continue
212 continue
211 except ChangesetError:
213 except ChangesetError:
212 log.error(traceback.format_exc())
214 log.error(traceback.format_exc())
213 pass
215 pass
214 except EmptyRepositoryError:
216 except EmptyRepositoryError:
215 pass
217 pass
216 except Exception:
218 except Exception:
217 log.error(traceback.format_exc())
219 log.error(traceback.format_exc())
218
220
219 return readme_data, readme_file
221 return readme_data, readme_file
220
222
221 key = repo_name + '_README'
223 key = repo_name + '_README'
222 inv = CacheInvalidation.invalidate(key)
224 inv = CacheInvalidation.invalidate(key)
223 if inv is not None:
225 if inv is not None:
224 region_invalidate(_get_readme_from_cache, None, key)
226 region_invalidate(_get_readme_from_cache, None, key)
225 CacheInvalidation.set_valid(inv.cache_key)
227 CacheInvalidation.set_valid(inv.cache_key)
226 return _get_readme_from_cache(key)
228 return _get_readme_from_cache(key)
227
229
228 def _get_download_links(self, repo):
230 def _get_download_links(self, repo):
229
231
230 download_l = []
232 download_l = []
231
233
232 branches_group = ([], _("Branches"))
234 branches_group = ([], _("Branches"))
233 tags_group = ([], _("Tags"))
235 tags_group = ([], _("Tags"))
234
236
235 for name, chs in c.rhodecode_repo.branches.items():
237 for name, chs in c.rhodecode_repo.branches.items():
236 #chs = chs.split(':')[-1]
238 #chs = chs.split(':')[-1]
237 branches_group[0].append((chs, name),)
239 branches_group[0].append((chs, name),)
238 download_l.append(branches_group)
240 download_l.append(branches_group)
239
241
240 for name, chs in c.rhodecode_repo.tags.items():
242 for name, chs in c.rhodecode_repo.tags.items():
241 #chs = chs.split(':')[-1]
243 #chs = chs.split(':')[-1]
242 tags_group[0].append((chs, name),)
244 tags_group[0].append((chs, name),)
243 download_l.append(tags_group)
245 download_l.append(tags_group)
244
246
245 return download_l
247 return download_l
General Comments 0
You need to be logged in to leave comments. Login now