##// END OF EJS Templates
caching: clarify that arguments to internal @cache_region functions only are used as caching key
Mads Kiilerich -
r7830:6fe3d405 default
parent child Browse files
Show More
@@ -1,168 +1,168 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
14 """
15 kallithea.controllers.feed
15 kallithea.controllers.feed
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~
17
17
18 Feed controller for Kallithea
18 Feed controller for Kallithea
19
19
20 This file was forked by the Kallithea project in July 2014.
20 This file was forked by the Kallithea project in July 2014.
21 Original author and date, and relevant copyright and licensing information is below:
21 Original author and date, and relevant copyright and licensing information is below:
22 :created_on: Apr 23, 2010
22 :created_on: Apr 23, 2010
23 :author: marcink
23 :author: marcink
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 :license: GPLv3, see LICENSE.md for more details.
25 :license: GPLv3, see LICENSE.md for more details.
26 """
26 """
27
27
28
28
29 import logging
29 import logging
30
30
31 from beaker.cache import cache_region, region_invalidate
31 from beaker.cache import cache_region, region_invalidate
32 from tg import response
32 from tg import response
33 from tg import tmpl_context as c
33 from tg import tmpl_context as c
34 from tg.i18n import ugettext as _
34 from tg.i18n import ugettext as _
35 from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
35 from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
36
36
37 from kallithea import CONFIG
37 from kallithea import CONFIG
38 from kallithea.lib import helpers as h
38 from kallithea.lib import helpers as h
39 from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired
39 from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired
40 from kallithea.lib.base import BaseRepoController
40 from kallithea.lib.base import BaseRepoController
41 from kallithea.lib.diffs import DiffProcessor
41 from kallithea.lib.diffs import DiffProcessor
42 from kallithea.lib.utils2 import safe_int, safe_unicode, str2bool
42 from kallithea.lib.utils2 import safe_int, safe_unicode, str2bool
43 from kallithea.model.db import CacheInvalidation
43 from kallithea.model.db import CacheInvalidation
44
44
45
45
46 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
47
47
48
48
49 language = 'en-us'
49 language = 'en-us'
50 ttl = "5"
50 ttl = "5"
51
51
52
52
53 class FeedController(BaseRepoController):
53 class FeedController(BaseRepoController):
54
54
55 @LoginRequired(allow_default_user=True)
55 @LoginRequired(allow_default_user=True)
56 @HasRepoPermissionLevelDecorator('read')
56 @HasRepoPermissionLevelDecorator('read')
57 def _before(self, *args, **kwargs):
57 def _before(self, *args, **kwargs):
58 super(FeedController, self)._before(*args, **kwargs)
58 super(FeedController, self)._before(*args, **kwargs)
59
59
60 def _get_title(self, cs):
60 def _get_title(self, cs):
61 return h.shorter(cs.message, 160)
61 return h.shorter(cs.message, 160)
62
62
63 def __get_desc(self, cs):
63 def __get_desc(self, cs):
64 desc_msg = [(_('%s committed on %s')
64 desc_msg = [(_('%s committed on %s')
65 % (h.person(cs.author), h.fmt_date(cs.date))) + '<br/>']
65 % (h.person(cs.author), h.fmt_date(cs.date))) + '<br/>']
66 # branches, tags, bookmarks
66 # branches, tags, bookmarks
67 for branch in cs.branches:
67 for branch in cs.branches:
68 desc_msg.append('branch: %s<br/>' % branch)
68 desc_msg.append('branch: %s<br/>' % branch)
69 for book in cs.bookmarks:
69 for book in cs.bookmarks:
70 desc_msg.append('bookmark: %s<br/>' % book)
70 desc_msg.append('bookmark: %s<br/>' % book)
71 for tag in cs.tags:
71 for tag in cs.tags:
72 desc_msg.append('tag: %s<br/>' % tag)
72 desc_msg.append('tag: %s<br/>' % tag)
73
73
74 changes = []
74 changes = []
75 diff_limit = safe_int(CONFIG.get('rss_cut_off_limit', 32 * 1024))
75 diff_limit = safe_int(CONFIG.get('rss_cut_off_limit', 32 * 1024))
76 raw_diff = cs.diff()
76 raw_diff = cs.diff()
77 diff_processor = DiffProcessor(raw_diff,
77 diff_processor = DiffProcessor(raw_diff,
78 diff_limit=diff_limit,
78 diff_limit=diff_limit,
79 inline_diff=False)
79 inline_diff=False)
80
80
81 for st in diff_processor.parsed:
81 for st in diff_processor.parsed:
82 st.update({'added': st['stats']['added'],
82 st.update({'added': st['stats']['added'],
83 'removed': st['stats']['deleted']})
83 'removed': st['stats']['deleted']})
84 changes.append('\n %(operation)s %(filename)s '
84 changes.append('\n %(operation)s %(filename)s '
85 '(%(added)s lines added, %(removed)s lines removed)'
85 '(%(added)s lines added, %(removed)s lines removed)'
86 % st)
86 % st)
87 if diff_processor.limited_diff:
87 if diff_processor.limited_diff:
88 changes = changes + ['\n ' +
88 changes = changes + ['\n ' +
89 _('Changeset was too big and was cut off...')]
89 _('Changeset was too big and was cut off...')]
90
90
91 # rev link
91 # rev link
92 _url = h.canonical_url('changeset_home', repo_name=c.db_repo.repo_name,
92 _url = h.canonical_url('changeset_home', repo_name=c.db_repo.repo_name,
93 revision=cs.raw_id)
93 revision=cs.raw_id)
94 desc_msg.append('changeset: <a href="%s">%s</a>' % (_url, cs.raw_id[:8]))
94 desc_msg.append('changeset: <a href="%s">%s</a>' % (_url, cs.raw_id[:8]))
95
95
96 desc_msg.append('<pre>')
96 desc_msg.append('<pre>')
97 desc_msg.append(h.urlify_text(cs.message))
97 desc_msg.append(h.urlify_text(cs.message))
98 desc_msg.append('\n')
98 desc_msg.append('\n')
99 desc_msg.extend(changes)
99 desc_msg.extend(changes)
100 if str2bool(CONFIG.get('rss_include_diff', False)):
100 if str2bool(CONFIG.get('rss_include_diff', False)):
101 desc_msg.append('\n\n')
101 desc_msg.append('\n\n')
102 desc_msg.append(raw_diff)
102 desc_msg.append(raw_diff)
103 desc_msg.append('</pre>')
103 desc_msg.append('</pre>')
104 return map(safe_unicode, desc_msg)
104 return map(safe_unicode, desc_msg)
105
105
106 def atom(self, repo_name):
106 def atom(self, repo_name):
107 """Produce an atom-1.0 feed via feedgenerator module"""
107 """Produce an atom-1.0 feed via feedgenerator module"""
108
108
109 @cache_region('long_term', '_get_feed_from_cache')
109 @cache_region('long_term', '_get_feed_from_cache')
110 def _get_feed_from_cache(key, kind):
110 def _get_feed_from_cache(*_cache_keys): # parameters are not really used - only as caching key
111 feed = Atom1Feed(
111 feed = Atom1Feed(
112 title=_('%s %s feed') % (c.site_name, repo_name),
112 title=_('%s %s feed') % (c.site_name, repo_name),
113 link=h.canonical_url('summary_home', repo_name=repo_name),
113 link=h.canonical_url('summary_home', repo_name=repo_name),
114 description=_('Changes on %s repository') % repo_name,
114 description=_('Changes on %s repository') % repo_name,
115 language=language,
115 language=language,
116 ttl=ttl
116 ttl=ttl
117 )
117 )
118
118
119 rss_items_per_page = safe_int(CONFIG.get('rss_items_per_page', 20))
119 rss_items_per_page = safe_int(CONFIG.get('rss_items_per_page', 20))
120 for cs in reversed(list(c.db_repo_scm_instance[-rss_items_per_page:])):
120 for cs in reversed(list(c.db_repo_scm_instance[-rss_items_per_page:])):
121 feed.add_item(title=self._get_title(cs),
121 feed.add_item(title=self._get_title(cs),
122 link=h.canonical_url('changeset_home', repo_name=repo_name,
122 link=h.canonical_url('changeset_home', repo_name=repo_name,
123 revision=cs.raw_id),
123 revision=cs.raw_id),
124 author_name=cs.author,
124 author_name=cs.author,
125 description=''.join(self.__get_desc(cs)),
125 description=''.join(self.__get_desc(cs)),
126 pubdate=cs.date,
126 pubdate=cs.date,
127 )
127 )
128
128
129 response.content_type = feed.mime_type
129 response.content_type = feed.mime_type
130 return feed.writeString('utf-8')
130 return feed.writeString('utf-8')
131
131
132 kind = 'ATOM'
132 kind = 'ATOM'
133 valid = CacheInvalidation.test_and_set_valid(repo_name, kind)
133 valid = CacheInvalidation.test_and_set_valid(repo_name, kind)
134 if not valid:
134 if not valid:
135 region_invalidate(_get_feed_from_cache, None, '_get_feed_from_cache', repo_name, kind)
135 region_invalidate(_get_feed_from_cache, None, '_get_feed_from_cache', repo_name, kind)
136 return _get_feed_from_cache(repo_name, kind)
136 return _get_feed_from_cache(repo_name, kind)
137
137
138 def rss(self, repo_name):
138 def rss(self, repo_name):
139 """Produce an rss2 feed via feedgenerator module"""
139 """Produce an rss2 feed via feedgenerator module"""
140
140
141 @cache_region('long_term', '_get_feed_from_cache')
141 @cache_region('long_term', '_get_feed_from_cache')
142 def _get_feed_from_cache(key, kind):
142 def _get_feed_from_cache(*_cache_keys): # parameters are not really used - only as caching key
143 feed = Rss201rev2Feed(
143 feed = Rss201rev2Feed(
144 title=_('%s %s feed') % (c.site_name, repo_name),
144 title=_('%s %s feed') % (c.site_name, repo_name),
145 link=h.canonical_url('summary_home', repo_name=repo_name),
145 link=h.canonical_url('summary_home', repo_name=repo_name),
146 description=_('Changes on %s repository') % repo_name,
146 description=_('Changes on %s repository') % repo_name,
147 language=language,
147 language=language,
148 ttl=ttl
148 ttl=ttl
149 )
149 )
150
150
151 rss_items_per_page = safe_int(CONFIG.get('rss_items_per_page', 20))
151 rss_items_per_page = safe_int(CONFIG.get('rss_items_per_page', 20))
152 for cs in reversed(list(c.db_repo_scm_instance[-rss_items_per_page:])):
152 for cs in reversed(list(c.db_repo_scm_instance[-rss_items_per_page:])):
153 feed.add_item(title=self._get_title(cs),
153 feed.add_item(title=self._get_title(cs),
154 link=h.canonical_url('changeset_home', repo_name=repo_name,
154 link=h.canonical_url('changeset_home', repo_name=repo_name,
155 revision=cs.raw_id),
155 revision=cs.raw_id),
156 author_name=cs.author,
156 author_name=cs.author,
157 description=''.join(self.__get_desc(cs)),
157 description=''.join(self.__get_desc(cs)),
158 pubdate=cs.date,
158 pubdate=cs.date,
159 )
159 )
160
160
161 response.content_type = feed.mime_type
161 response.content_type = feed.mime_type
162 return feed.writeString('utf-8')
162 return feed.writeString('utf-8')
163
163
164 kind = 'RSS'
164 kind = 'RSS'
165 valid = CacheInvalidation.test_and_set_valid(repo_name, kind)
165 valid = CacheInvalidation.test_and_set_valid(repo_name, kind)
166 if not valid:
166 if not valid:
167 region_invalidate(_get_feed_from_cache, None, '_get_feed_from_cache', repo_name, kind)
167 region_invalidate(_get_feed_from_cache, None, '_get_feed_from_cache', repo_name, kind)
168 return _get_feed_from_cache(repo_name, kind)
168 return _get_feed_from_cache(repo_name, kind)
@@ -1,219 +1,219 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
14 """
15 kallithea.controllers.summary
15 kallithea.controllers.summary
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17
17
18 Summary controller for Kallithea
18 Summary controller for Kallithea
19
19
20 This file was forked by the Kallithea project in July 2014.
20 This file was forked by the Kallithea project in July 2014.
21 Original author and date, and relevant copyright and licensing information is below:
21 Original author and date, and relevant copyright and licensing information is below:
22 :created_on: Apr 18, 2010
22 :created_on: Apr 18, 2010
23 :author: marcink
23 :author: marcink
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 :license: GPLv3, see LICENSE.md for more details.
25 :license: GPLv3, see LICENSE.md for more details.
26 """
26 """
27
27
28 import calendar
28 import calendar
29 import itertools
29 import itertools
30 import logging
30 import logging
31 import traceback
31 import traceback
32 from datetime import date, timedelta
32 from datetime import date, timedelta
33 from time import mktime
33 from time import mktime
34
34
35 from beaker.cache import cache_region, region_invalidate
35 from beaker.cache import cache_region, region_invalidate
36 from tg import request
36 from tg import request
37 from tg import tmpl_context as c
37 from tg import tmpl_context as c
38 from tg.i18n import ugettext as _
38 from tg.i18n import ugettext as _
39 from webob.exc import HTTPBadRequest
39 from webob.exc import HTTPBadRequest
40
40
41 from kallithea.config.conf import ALL_EXTS, ALL_READMES, LANGUAGES_EXTENSIONS_MAP
41 from kallithea.config.conf import ALL_EXTS, ALL_READMES, LANGUAGES_EXTENSIONS_MAP
42 from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired
42 from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired
43 from kallithea.lib.base import BaseRepoController, jsonify, render
43 from kallithea.lib.base import BaseRepoController, jsonify, render
44 from kallithea.lib.celerylib.tasks import get_commits_stats
44 from kallithea.lib.celerylib.tasks import get_commits_stats
45 from kallithea.lib.compat import json
45 from kallithea.lib.compat import json
46 from kallithea.lib.markup_renderer import MarkupRenderer
46 from kallithea.lib.markup_renderer import MarkupRenderer
47 from kallithea.lib.page import RepoPage
47 from kallithea.lib.page import RepoPage
48 from kallithea.lib.utils2 import safe_int
48 from kallithea.lib.utils2 import safe_int
49 from kallithea.lib.vcs.backends.base import EmptyChangeset
49 from kallithea.lib.vcs.backends.base import EmptyChangeset
50 from kallithea.lib.vcs.exceptions import ChangesetError, EmptyRepositoryError, NodeDoesNotExistError
50 from kallithea.lib.vcs.exceptions import ChangesetError, EmptyRepositoryError, NodeDoesNotExistError
51 from kallithea.lib.vcs.nodes import FileNode
51 from kallithea.lib.vcs.nodes import FileNode
52 from kallithea.model.db import CacheInvalidation, Statistics
52 from kallithea.model.db import CacheInvalidation, Statistics
53
53
54
54
55 log = logging.getLogger(__name__)
55 log = logging.getLogger(__name__)
56
56
57 README_FILES = [''.join([x[0][0], x[1][0]]) for x in
57 README_FILES = [''.join([x[0][0], x[1][0]]) for x in
58 sorted(list(itertools.product(ALL_READMES, ALL_EXTS)),
58 sorted(list(itertools.product(ALL_READMES, ALL_EXTS)),
59 key=lambda y:y[0][1] + y[1][1])]
59 key=lambda y:y[0][1] + y[1][1])]
60
60
61
61
62 class SummaryController(BaseRepoController):
62 class SummaryController(BaseRepoController):
63
63
64 def __get_readme_data(self, db_repo):
64 def __get_readme_data(self, db_repo):
65 repo_name = db_repo.repo_name
65 repo_name = db_repo.repo_name
66 log.debug('Looking for README file')
66 log.debug('Looking for README file')
67
67
68 @cache_region('long_term', '_get_readme_from_cache')
68 @cache_region('long_term', '_get_readme_from_cache')
69 def _get_readme_from_cache(key, kind):
69 def _get_readme_from_cache(*_cache_keys): # parameters are not really used - only as caching key
70 readme_data = None
70 readme_data = None
71 readme_file = None
71 readme_file = None
72 try:
72 try:
73 # gets the landing revision! or tip if fails
73 # gets the landing revision! or tip if fails
74 cs = db_repo.get_landing_changeset()
74 cs = db_repo.get_landing_changeset()
75 if isinstance(cs, EmptyChangeset):
75 if isinstance(cs, EmptyChangeset):
76 raise EmptyRepositoryError()
76 raise EmptyRepositoryError()
77 renderer = MarkupRenderer()
77 renderer = MarkupRenderer()
78 for f in README_FILES:
78 for f in README_FILES:
79 try:
79 try:
80 readme = cs.get_node(f)
80 readme = cs.get_node(f)
81 if not isinstance(readme, FileNode):
81 if not isinstance(readme, FileNode):
82 continue
82 continue
83 readme_file = f
83 readme_file = f
84 log.debug('Found README file `%s` rendering...',
84 log.debug('Found README file `%s` rendering...',
85 readme_file)
85 readme_file)
86 readme_data = renderer.render(readme.content,
86 readme_data = renderer.render(readme.content,
87 filename=f)
87 filename=f)
88 break
88 break
89 except NodeDoesNotExistError:
89 except NodeDoesNotExistError:
90 continue
90 continue
91 except ChangesetError:
91 except ChangesetError:
92 log.error(traceback.format_exc())
92 log.error(traceback.format_exc())
93 pass
93 pass
94 except EmptyRepositoryError:
94 except EmptyRepositoryError:
95 pass
95 pass
96
96
97 return readme_data, readme_file
97 return readme_data, readme_file
98
98
99 kind = 'README'
99 kind = 'README'
100 valid = CacheInvalidation.test_and_set_valid(repo_name, kind)
100 valid = CacheInvalidation.test_and_set_valid(repo_name, kind)
101 if not valid:
101 if not valid:
102 region_invalidate(_get_readme_from_cache, None, '_get_readme_from_cache', repo_name, kind)
102 region_invalidate(_get_readme_from_cache, None, '_get_readme_from_cache', repo_name, kind)
103 return _get_readme_from_cache(repo_name, kind)
103 return _get_readme_from_cache(repo_name, kind)
104
104
105 @LoginRequired(allow_default_user=True)
105 @LoginRequired(allow_default_user=True)
106 @HasRepoPermissionLevelDecorator('read')
106 @HasRepoPermissionLevelDecorator('read')
107 def index(self, repo_name):
107 def index(self, repo_name):
108 p = safe_int(request.GET.get('page'), 1)
108 p = safe_int(request.GET.get('page'), 1)
109 size = safe_int(request.GET.get('size'), 10)
109 size = safe_int(request.GET.get('size'), 10)
110 collection = c.db_repo_scm_instance
110 collection = c.db_repo_scm_instance
111 c.cs_pagination = RepoPage(collection, page=p, items_per_page=size)
111 c.cs_pagination = RepoPage(collection, page=p, items_per_page=size)
112 page_revisions = [x.raw_id for x in list(c.cs_pagination)]
112 page_revisions = [x.raw_id for x in list(c.cs_pagination)]
113 c.cs_comments = c.db_repo.get_comments(page_revisions)
113 c.cs_comments = c.db_repo.get_comments(page_revisions)
114 c.cs_statuses = c.db_repo.statuses(page_revisions)
114 c.cs_statuses = c.db_repo.statuses(page_revisions)
115
115
116 c.ssh_repo_url = None
116 c.ssh_repo_url = None
117 if request.authuser.is_default_user:
117 if request.authuser.is_default_user:
118 username = None
118 username = None
119 else:
119 else:
120 username = request.authuser.username
120 username = request.authuser.username
121 if c.ssh_enabled:
121 if c.ssh_enabled:
122 c.ssh_repo_url = c.db_repo.clone_url(clone_uri_tmpl=c.clone_ssh_tmpl)
122 c.ssh_repo_url = c.db_repo.clone_url(clone_uri_tmpl=c.clone_ssh_tmpl)
123
123
124 c.clone_repo_url = c.db_repo.clone_url(clone_uri_tmpl=c.clone_uri_tmpl, with_id=False, username=username)
124 c.clone_repo_url = c.db_repo.clone_url(clone_uri_tmpl=c.clone_uri_tmpl, with_id=False, username=username)
125 c.clone_repo_url_id = c.db_repo.clone_url(clone_uri_tmpl=c.clone_uri_tmpl, with_id=True, username=username)
125 c.clone_repo_url_id = c.db_repo.clone_url(clone_uri_tmpl=c.clone_uri_tmpl, with_id=True, username=username)
126
126
127 if c.db_repo.enable_statistics:
127 if c.db_repo.enable_statistics:
128 c.show_stats = True
128 c.show_stats = True
129 else:
129 else:
130 c.show_stats = False
130 c.show_stats = False
131
131
132 stats = Statistics.query() \
132 stats = Statistics.query() \
133 .filter(Statistics.repository == c.db_repo) \
133 .filter(Statistics.repository == c.db_repo) \
134 .scalar()
134 .scalar()
135
135
136 c.stats_percentage = 0
136 c.stats_percentage = 0
137
137
138 if stats and stats.languages:
138 if stats and stats.languages:
139 c.no_data = False is c.db_repo.enable_statistics
139 c.no_data = False is c.db_repo.enable_statistics
140 lang_stats_d = json.loads(stats.languages)
140 lang_stats_d = json.loads(stats.languages)
141
141
142 lang_stats = [(x, {"count": y,
142 lang_stats = [(x, {"count": y,
143 "desc": LANGUAGES_EXTENSIONS_MAP.get(x, '?')})
143 "desc": LANGUAGES_EXTENSIONS_MAP.get(x, '?')})
144 for x, y in lang_stats_d.items()]
144 for x, y in lang_stats_d.items()]
145 lang_stats.sort(key=lambda k: (-k[1]['count'], k[0]))
145 lang_stats.sort(key=lambda k: (-k[1]['count'], k[0]))
146
146
147 c.trending_languages = lang_stats[:10]
147 c.trending_languages = lang_stats[:10]
148 else:
148 else:
149 c.no_data = True
149 c.no_data = True
150 c.trending_languages = []
150 c.trending_languages = []
151
151
152 c.enable_downloads = c.db_repo.enable_downloads
152 c.enable_downloads = c.db_repo.enable_downloads
153 c.readme_data, c.readme_file = \
153 c.readme_data, c.readme_file = \
154 self.__get_readme_data(c.db_repo)
154 self.__get_readme_data(c.db_repo)
155 return render('summary/summary.html')
155 return render('summary/summary.html')
156
156
157 @LoginRequired()
157 @LoginRequired()
158 @HasRepoPermissionLevelDecorator('read')
158 @HasRepoPermissionLevelDecorator('read')
159 @jsonify
159 @jsonify
160 def repo_size(self, repo_name):
160 def repo_size(self, repo_name):
161 if request.is_xhr:
161 if request.is_xhr:
162 return c.db_repo._repo_size()
162 return c.db_repo._repo_size()
163 else:
163 else:
164 raise HTTPBadRequest()
164 raise HTTPBadRequest()
165
165
166 @LoginRequired(allow_default_user=True)
166 @LoginRequired(allow_default_user=True)
167 @HasRepoPermissionLevelDecorator('read')
167 @HasRepoPermissionLevelDecorator('read')
168 def statistics(self, repo_name):
168 def statistics(self, repo_name):
169 if c.db_repo.enable_statistics:
169 if c.db_repo.enable_statistics:
170 c.show_stats = True
170 c.show_stats = True
171 c.no_data_msg = _('No data ready yet')
171 c.no_data_msg = _('No data ready yet')
172 else:
172 else:
173 c.show_stats = False
173 c.show_stats = False
174 c.no_data_msg = _('Statistics are disabled for this repository')
174 c.no_data_msg = _('Statistics are disabled for this repository')
175
175
176 td = date.today() + timedelta(days=1)
176 td = date.today() + timedelta(days=1)
177 td_1m = td - timedelta(days=calendar.mdays[td.month])
177 td_1m = td - timedelta(days=calendar.mdays[td.month])
178 td_1y = td - timedelta(days=365)
178 td_1y = td - timedelta(days=365)
179
179
180 ts_min_m = mktime(td_1m.timetuple())
180 ts_min_m = mktime(td_1m.timetuple())
181 ts_min_y = mktime(td_1y.timetuple())
181 ts_min_y = mktime(td_1y.timetuple())
182 ts_max_y = mktime(td.timetuple())
182 ts_max_y = mktime(td.timetuple())
183 c.ts_min = ts_min_m
183 c.ts_min = ts_min_m
184 c.ts_max = ts_max_y
184 c.ts_max = ts_max_y
185
185
186 stats = Statistics.query() \
186 stats = Statistics.query() \
187 .filter(Statistics.repository == c.db_repo) \
187 .filter(Statistics.repository == c.db_repo) \
188 .scalar()
188 .scalar()
189 c.stats_percentage = 0
189 c.stats_percentage = 0
190 if stats and stats.languages:
190 if stats and stats.languages:
191 c.no_data = False is c.db_repo.enable_statistics
191 c.no_data = False is c.db_repo.enable_statistics
192 lang_stats_d = json.loads(stats.languages)
192 lang_stats_d = json.loads(stats.languages)
193 c.commit_data = json.loads(stats.commit_activity)
193 c.commit_data = json.loads(stats.commit_activity)
194 c.overview_data = json.loads(stats.commit_activity_combined)
194 c.overview_data = json.loads(stats.commit_activity_combined)
195
195
196 lang_stats = ((x, {"count": y,
196 lang_stats = ((x, {"count": y,
197 "desc": LANGUAGES_EXTENSIONS_MAP.get(x)})
197 "desc": LANGUAGES_EXTENSIONS_MAP.get(x)})
198 for x, y in lang_stats_d.items())
198 for x, y in lang_stats_d.items())
199
199
200 c.trending_languages = (
200 c.trending_languages = (
201 sorted(lang_stats, reverse=True, key=lambda k: k[1])[:10]
201 sorted(lang_stats, reverse=True, key=lambda k: k[1])[:10]
202 )
202 )
203 last_rev = stats.stat_on_revision + 1
203 last_rev = stats.stat_on_revision + 1
204 c.repo_last_rev = c.db_repo_scm_instance.count() \
204 c.repo_last_rev = c.db_repo_scm_instance.count() \
205 if c.db_repo_scm_instance.revisions else 0
205 if c.db_repo_scm_instance.revisions else 0
206 if last_rev == 0 or c.repo_last_rev == 0:
206 if last_rev == 0 or c.repo_last_rev == 0:
207 pass
207 pass
208 else:
208 else:
209 c.stats_percentage = '%.2f' % ((float((last_rev)) /
209 c.stats_percentage = '%.2f' % ((float((last_rev)) /
210 c.repo_last_rev) * 100)
210 c.repo_last_rev) * 100)
211 else:
211 else:
212 c.commit_data = {}
212 c.commit_data = {}
213 c.overview_data = ([[ts_min_y, 0], [ts_max_y, 10]])
213 c.overview_data = ([[ts_min_y, 0], [ts_max_y, 10]])
214 c.trending_languages = {}
214 c.trending_languages = {}
215 c.no_data = True
215 c.no_data = True
216
216
217 recurse_limit = 500 # don't recurse more than 500 times when parsing
217 recurse_limit = 500 # don't recurse more than 500 times when parsing
218 get_commits_stats(c.db_repo.repo_name, ts_min_y, ts_max_y, recurse_limit)
218 get_commits_stats(c.db_repo.repo_name, ts_min_y, ts_max_y, recurse_limit)
219 return render('summary/statistics.html')
219 return render('summary/statistics.html')
General Comments 0
You need to be logged in to leave comments. Login now