##// END OF EJS Templates
fixes for vcs 0.2.0and new slicing methods
marcink -
r1082:c2440bad beta
parent child Browse files
Show More
@@ -1,342 +1,342 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.admin.repos
3 rhodecode.controllers.admin.repos
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Admin controller for RhodeCode
6 Admin controller for RhodeCode
7
7
8 :created_on: Apr 7, 2010
8 :created_on: Apr 7, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 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
13 # This program is free software; you can redistribute it and/or
14 # modify it under the terms of the GNU General Public License
14 # modify it under the terms of the GNU General Public License
15 # as published by the Free Software Foundation; version 2
15 # as published by the Free Software Foundation; version 2
16 # of the License or (at your opinion) any later version of the license.
16 # of the License or (at your opinion) any later version of the license.
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, write to the Free Software
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 # MA 02110-1301, USA.
26 # MA 02110-1301, USA.
27
27
28 import logging
28 import logging
29 import traceback
29 import traceback
30 import formencode
30 import formencode
31 from operator import itemgetter
31 from operator import itemgetter
32 from formencode import htmlfill
32 from formencode import htmlfill
33
33
34 from paste.httpexceptions import HTTPInternalServerError
34 from paste.httpexceptions import HTTPInternalServerError
35 from pylons import request, response, session, tmpl_context as c, url
35 from pylons import request, response, session, tmpl_context as c, url
36 from pylons.controllers.util import abort, redirect
36 from pylons.controllers.util import abort, redirect
37 from pylons.i18n.translation import _
37 from pylons.i18n.translation import _
38
38
39 from rhodecode.lib import helpers as h
39 from rhodecode.lib import helpers as h
40 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
40 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
41 HasPermissionAnyDecorator
41 HasPermissionAnyDecorator
42 from rhodecode.lib.base import BaseController, render
42 from rhodecode.lib.base import BaseController, render
43 from rhodecode.lib.utils import invalidate_cache, action_logger, repo_name_slug
43 from rhodecode.lib.utils import invalidate_cache, action_logger, repo_name_slug
44 from rhodecode.model.db import User
44 from rhodecode.model.db import User
45 from rhodecode.model.forms import RepoForm
45 from rhodecode.model.forms import RepoForm
46 from rhodecode.model.scm import ScmModel
46 from rhodecode.model.scm import ScmModel
47 from rhodecode.model.repo import RepoModel
47 from rhodecode.model.repo import RepoModel
48
48
49
49
50 log = logging.getLogger(__name__)
50 log = logging.getLogger(__name__)
51
51
52 class ReposController(BaseController):
52 class ReposController(BaseController):
53 """REST Controller styled on the Atom Publishing Protocol"""
53 """REST Controller styled on the Atom Publishing Protocol"""
54 # To properly map this controller, ensure your config/routing.py
54 # To properly map this controller, ensure your config/routing.py
55 # file has a resource setup:
55 # file has a resource setup:
56 # map.resource('repo', 'repos')
56 # map.resource('repo', 'repos')
57
57
58 @LoginRequired()
58 @LoginRequired()
59 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
59 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
60 def __before__(self):
60 def __before__(self):
61 c.admin_user = session.get('admin_user')
61 c.admin_user = session.get('admin_user')
62 c.admin_username = session.get('admin_username')
62 c.admin_username = session.get('admin_username')
63 super(ReposController, self).__before__()
63 super(ReposController, self).__before__()
64
64
65 @HasPermissionAllDecorator('hg.admin')
65 @HasPermissionAllDecorator('hg.admin')
66 def index(self, format='html'):
66 def index(self, format='html'):
67 """GET /repos: All items in the collection"""
67 """GET /repos: All items in the collection"""
68 # url('repos')
68 # url('repos')
69 cached_repo_list = ScmModel().get_repos()
69 cached_repo_list = ScmModel().get_repos()
70 c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
70 c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
71 return render('admin/repos/repos.html')
71 return render('admin/repos/repos.html')
72
72
73 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
73 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
74 def create(self):
74 def create(self):
75 """POST /repos: Create a new item"""
75 """POST /repos: Create a new item"""
76 # url('repos')
76 # url('repos')
77 repo_model = RepoModel()
77 repo_model = RepoModel()
78 _form = RepoForm()()
78 _form = RepoForm()()
79 form_result = {}
79 form_result = {}
80 try:
80 try:
81 form_result = _form.to_python(dict(request.POST))
81 form_result = _form.to_python(dict(request.POST))
82 repo_model.create(form_result, c.rhodecode_user)
82 repo_model.create(form_result, c.rhodecode_user)
83 h.flash(_('created repository %s') % form_result['repo_name'],
83 h.flash(_('created repository %s') % form_result['repo_name'],
84 category='success')
84 category='success')
85
85
86 if request.POST.get('user_created'):
86 if request.POST.get('user_created'):
87 action_logger(self.rhodecode_user, 'user_created_repo',
87 action_logger(self.rhodecode_user, 'user_created_repo',
88 form_result['repo_name'], '', self.sa)
88 form_result['repo_name'], '', self.sa)
89 else:
89 else:
90 action_logger(self.rhodecode_user, 'admin_created_repo',
90 action_logger(self.rhodecode_user, 'admin_created_repo',
91 form_result['repo_name'], '', self.sa)
91 form_result['repo_name'], '', self.sa)
92
92
93 except formencode.Invalid, errors:
93 except formencode.Invalid, errors:
94 c.new_repo = errors.value['repo_name']
94 c.new_repo = errors.value['repo_name']
95
95
96 if request.POST.get('user_created'):
96 if request.POST.get('user_created'):
97 r = render('admin/repos/repo_add_create_repository.html')
97 r = render('admin/repos/repo_add_create_repository.html')
98 else:
98 else:
99 r = render('admin/repos/repo_add.html')
99 r = render('admin/repos/repo_add.html')
100
100
101 return htmlfill.render(
101 return htmlfill.render(
102 r,
102 r,
103 defaults=errors.value,
103 defaults=errors.value,
104 errors=errors.error_dict or {},
104 errors=errors.error_dict or {},
105 prefix_error=False,
105 prefix_error=False,
106 encoding="UTF-8")
106 encoding="UTF-8")
107
107
108 except Exception:
108 except Exception:
109 log.error(traceback.format_exc())
109 log.error(traceback.format_exc())
110 msg = _('error occurred during creation of repository %s') \
110 msg = _('error occurred during creation of repository %s') \
111 % form_result.get('repo_name')
111 % form_result.get('repo_name')
112 h.flash(msg, category='error')
112 h.flash(msg, category='error')
113 if request.POST.get('user_created'):
113 if request.POST.get('user_created'):
114 return redirect(url('home'))
114 return redirect(url('home'))
115 return redirect(url('repos'))
115 return redirect(url('repos'))
116
116
117 @HasPermissionAllDecorator('hg.admin')
117 @HasPermissionAllDecorator('hg.admin')
118 def new(self, format='html'):
118 def new(self, format='html'):
119 """GET /repos/new: Form to create a new item"""
119 """GET /repos/new: Form to create a new item"""
120 new_repo = request.GET.get('repo', '')
120 new_repo = request.GET.get('repo', '')
121 c.new_repo = repo_name_slug(new_repo)
121 c.new_repo = repo_name_slug(new_repo)
122
122
123 return render('admin/repos/repo_add.html')
123 return render('admin/repos/repo_add.html')
124
124
125 @HasPermissionAllDecorator('hg.admin')
125 @HasPermissionAllDecorator('hg.admin')
126 def update(self, repo_name):
126 def update(self, repo_name):
127 """PUT /repos/repo_name: Update an existing item"""
127 """PUT /repos/repo_name: Update an existing item"""
128 # Forms posted to this method should contain a hidden field:
128 # Forms posted to this method should contain a hidden field:
129 # <input type="hidden" name="_method" value="PUT" />
129 # <input type="hidden" name="_method" value="PUT" />
130 # Or using helpers:
130 # Or using helpers:
131 # h.form(url('repo', repo_name=ID),
131 # h.form(url('repo', repo_name=ID),
132 # method='put')
132 # method='put')
133 # url('repo', repo_name=ID)
133 # url('repo', repo_name=ID)
134 repo_model = RepoModel()
134 repo_model = RepoModel()
135 changed_name = repo_name
135 changed_name = repo_name
136 _form = RepoForm(edit=True, old_data={'repo_name':repo_name})()
136 _form = RepoForm(edit=True, old_data={'repo_name':repo_name})()
137
137
138 try:
138 try:
139 form_result = _form.to_python(dict(request.POST))
139 form_result = _form.to_python(dict(request.POST))
140 repo_model.update(repo_name, form_result)
140 repo_model.update(repo_name, form_result)
141 invalidate_cache('get_repo_cached_%s' % repo_name)
141 invalidate_cache('get_repo_cached_%s' % repo_name)
142 h.flash(_('Repository %s updated successfully' % repo_name),
142 h.flash(_('Repository %s updated successfully' % repo_name),
143 category='success')
143 category='success')
144 changed_name = form_result['repo_name']
144 changed_name = form_result['repo_name']
145 action_logger(self.rhodecode_user, 'admin_updated_repo',
145 action_logger(self.rhodecode_user, 'admin_updated_repo',
146 changed_name, '', self.sa)
146 changed_name, '', self.sa)
147
147
148 except formencode.Invalid, errors:
148 except formencode.Invalid, errors:
149 c.repo_info = repo_model.get_by_repo_name(repo_name)
149 c.repo_info = repo_model.get_by_repo_name(repo_name)
150
150
151 if c.repo_info.stats:
151 if c.repo_info.stats:
152 last_rev = c.repo_info.stats.stat_on_revision
152 last_rev = c.repo_info.stats.stat_on_revision
153 else:
153 else:
154 last_rev = 0
154 last_rev = 0
155 c.stats_revision = last_rev
155 c.stats_revision = last_rev
156 repo, dbrepo = ScmModel().get(repo_name, retval='repo')
156 repo, dbrepo = ScmModel().get(repo_name, retval='repo')
157 c.repo_last_rev = repo.revisions[-1] if repo.revisions else 0
157 c.repo_last_rev = repo.count() if repo.revisions else 0
158
158
159 if last_rev == 0:
159 if last_rev == 0:
160 c.stats_percentage = 0
160 c.stats_percentage = 0
161 else:
161 else:
162 c.stats_percentage = '%.2f' % ((float((last_rev)) /
162 c.stats_percentage = '%.2f' % ((float((last_rev)) /
163 c.repo_last_rev) * 100)
163 c.repo_last_rev) * 100)
164
164
165 c.users_array = repo_model.get_users_js()
165 c.users_array = repo_model.get_users_js()
166 c.users_groups_array = repo_model.get_users_groups_js()
166 c.users_groups_array = repo_model.get_users_groups_js()
167
167
168 errors.value.update({'user':c.repo_info.user.username})
168 errors.value.update({'user':c.repo_info.user.username})
169 return htmlfill.render(
169 return htmlfill.render(
170 render('admin/repos/repo_edit.html'),
170 render('admin/repos/repo_edit.html'),
171 defaults=errors.value,
171 defaults=errors.value,
172 errors=errors.error_dict or {},
172 errors=errors.error_dict or {},
173 prefix_error=False,
173 prefix_error=False,
174 encoding="UTF-8")
174 encoding="UTF-8")
175
175
176 except Exception:
176 except Exception:
177 log.error(traceback.format_exc())
177 log.error(traceback.format_exc())
178 h.flash(_('error occurred during update of repository %s') \
178 h.flash(_('error occurred during update of repository %s') \
179 % repo_name, category='error')
179 % repo_name, category='error')
180
180
181 return redirect(url('edit_repo', repo_name=changed_name))
181 return redirect(url('edit_repo', repo_name=changed_name))
182
182
183 @HasPermissionAllDecorator('hg.admin')
183 @HasPermissionAllDecorator('hg.admin')
184 def delete(self, repo_name):
184 def delete(self, repo_name):
185 """DELETE /repos/repo_name: Delete an existing item"""
185 """DELETE /repos/repo_name: Delete an existing item"""
186 # Forms posted to this method should contain a hidden field:
186 # Forms posted to this method should contain a hidden field:
187 # <input type="hidden" name="_method" value="DELETE" />
187 # <input type="hidden" name="_method" value="DELETE" />
188 # Or using helpers:
188 # Or using helpers:
189 # h.form(url('repo', repo_name=ID),
189 # h.form(url('repo', repo_name=ID),
190 # method='delete')
190 # method='delete')
191 # url('repo', repo_name=ID)
191 # url('repo', repo_name=ID)
192
192
193 repo_model = RepoModel()
193 repo_model = RepoModel()
194 repo = repo_model.get_by_repo_name(repo_name)
194 repo = repo_model.get_by_repo_name(repo_name)
195 if not repo:
195 if not repo:
196 h.flash(_('%s repository is not mapped to db perhaps'
196 h.flash(_('%s repository is not mapped to db perhaps'
197 ' it was moved or renamed from the filesystem'
197 ' it was moved or renamed from the filesystem'
198 ' please run the application again'
198 ' please run the application again'
199 ' in order to rescan repositories') % repo_name,
199 ' in order to rescan repositories') % repo_name,
200 category='error')
200 category='error')
201
201
202 return redirect(url('repos'))
202 return redirect(url('repos'))
203 try:
203 try:
204 action_logger(self.rhodecode_user, 'admin_deleted_repo',
204 action_logger(self.rhodecode_user, 'admin_deleted_repo',
205 repo_name, '', self.sa)
205 repo_name, '', self.sa)
206 repo_model.delete(repo)
206 repo_model.delete(repo)
207 invalidate_cache('get_repo_cached_%s' % repo_name)
207 invalidate_cache('get_repo_cached_%s' % repo_name)
208 h.flash(_('deleted repository %s') % repo_name, category='success')
208 h.flash(_('deleted repository %s') % repo_name, category='success')
209
209
210 except Exception, e:
210 except Exception, e:
211 log.error(traceback.format_exc())
211 log.error(traceback.format_exc())
212 h.flash(_('An error occurred during deletion of %s') % repo_name,
212 h.flash(_('An error occurred during deletion of %s') % repo_name,
213 category='error')
213 category='error')
214
214
215 return redirect(url('repos'))
215 return redirect(url('repos'))
216
216
217 @HasPermissionAllDecorator('hg.admin')
217 @HasPermissionAllDecorator('hg.admin')
218 def delete_perm_user(self, repo_name):
218 def delete_perm_user(self, repo_name):
219 """DELETE an existing repository permission user
219 """DELETE an existing repository permission user
220
220
221 :param repo_name:
221 :param repo_name:
222 """
222 """
223
223
224 try:
224 try:
225 repo_model = RepoModel()
225 repo_model = RepoModel()
226 repo_model.delete_perm_user(request.POST, repo_name)
226 repo_model.delete_perm_user(request.POST, repo_name)
227 except Exception, e:
227 except Exception, e:
228 h.flash(_('An error occurred during deletion of repository user'),
228 h.flash(_('An error occurred during deletion of repository user'),
229 category='error')
229 category='error')
230 raise HTTPInternalServerError()
230 raise HTTPInternalServerError()
231
231
232 @HasPermissionAllDecorator('hg.admin')
232 @HasPermissionAllDecorator('hg.admin')
233 def delete_perm_users_group(self, repo_name):
233 def delete_perm_users_group(self, repo_name):
234 """DELETE an existing repository permission users group
234 """DELETE an existing repository permission users group
235
235
236 :param repo_name:
236 :param repo_name:
237 """
237 """
238 try:
238 try:
239 repo_model = RepoModel()
239 repo_model = RepoModel()
240 repo_model.delete_perm_users_group(request.POST, repo_name)
240 repo_model.delete_perm_users_group(request.POST, repo_name)
241 except Exception, e:
241 except Exception, e:
242 h.flash(_('An error occurred during deletion of repository'
242 h.flash(_('An error occurred during deletion of repository'
243 ' users groups'),
243 ' users groups'),
244 category='error')
244 category='error')
245 raise HTTPInternalServerError()
245 raise HTTPInternalServerError()
246
246
247 @HasPermissionAllDecorator('hg.admin')
247 @HasPermissionAllDecorator('hg.admin')
248 def repo_stats(self, repo_name):
248 def repo_stats(self, repo_name):
249 """DELETE an existing repository statistics
249 """DELETE an existing repository statistics
250
250
251 :param repo_name:
251 :param repo_name:
252 """
252 """
253
253
254 try:
254 try:
255 repo_model = RepoModel()
255 repo_model = RepoModel()
256 repo_model.delete_stats(repo_name)
256 repo_model.delete_stats(repo_name)
257 except Exception, e:
257 except Exception, e:
258 h.flash(_('An error occurred during deletion of repository stats'),
258 h.flash(_('An error occurred during deletion of repository stats'),
259 category='error')
259 category='error')
260 return redirect(url('edit_repo', repo_name=repo_name))
260 return redirect(url('edit_repo', repo_name=repo_name))
261
261
262 @HasPermissionAllDecorator('hg.admin')
262 @HasPermissionAllDecorator('hg.admin')
263 def repo_cache(self, repo_name):
263 def repo_cache(self, repo_name):
264 """INVALIDATE existing repository cache
264 """INVALIDATE existing repository cache
265
265
266 :param repo_name:
266 :param repo_name:
267 """
267 """
268
268
269 try:
269 try:
270 ScmModel().mark_for_invalidation(repo_name)
270 ScmModel().mark_for_invalidation(repo_name)
271 except Exception, e:
271 except Exception, e:
272 h.flash(_('An error occurred during cache invalidation'),
272 h.flash(_('An error occurred during cache invalidation'),
273 category='error')
273 category='error')
274 return redirect(url('edit_repo', repo_name=repo_name))
274 return redirect(url('edit_repo', repo_name=repo_name))
275
275
276 @HasPermissionAllDecorator('hg.admin')
276 @HasPermissionAllDecorator('hg.admin')
277 def show(self, repo_name, format='html'):
277 def show(self, repo_name, format='html'):
278 """GET /repos/repo_name: Show a specific item"""
278 """GET /repos/repo_name: Show a specific item"""
279 # url('repo', repo_name=ID)
279 # url('repo', repo_name=ID)
280
280
281 @HasPermissionAllDecorator('hg.admin')
281 @HasPermissionAllDecorator('hg.admin')
282 def edit(self, repo_name, format='html'):
282 def edit(self, repo_name, format='html'):
283 """GET /repos/repo_name/edit: Form to edit an existing item"""
283 """GET /repos/repo_name/edit: Form to edit an existing item"""
284 # url('edit_repo', repo_name=ID)
284 # url('edit_repo', repo_name=ID)
285 repo, dbrepo = ScmModel().get(repo_name, retval='repo')
285 repo, dbrepo = ScmModel().get(repo_name, retval='repo')
286
286
287 repo_model = RepoModel()
287 repo_model = RepoModel()
288 c.repo_info = repo_model.get_by_repo_name(repo_name)
288 c.repo_info = repo_model.get_by_repo_name(repo_name)
289
289
290 if c.repo_info is None:
290 if c.repo_info is None:
291 h.flash(_('%s repository is not mapped to db perhaps'
291 h.flash(_('%s repository is not mapped to db perhaps'
292 ' it was created or renamed from the filesystem'
292 ' it was created or renamed from the filesystem'
293 ' please run the application again'
293 ' please run the application again'
294 ' in order to rescan repositories') % repo_name,
294 ' in order to rescan repositories') % repo_name,
295 category='error')
295 category='error')
296
296
297 return redirect(url('repos'))
297 return redirect(url('repos'))
298
298
299 if c.repo_info.stats:
299 if c.repo_info.stats:
300 last_rev = c.repo_info.stats.stat_on_revision
300 last_rev = c.repo_info.stats.stat_on_revision
301 else:
301 else:
302 last_rev = 0
302 last_rev = 0
303 c.stats_revision = last_rev
303 c.stats_revision = last_rev
304
304
305 c.repo_last_rev = repo.revisions[-1] if repo.revisions else 0
305 c.repo_last_rev = repo.count() if repo.revisions else 0
306
306
307 if last_rev == 0 or c.repo_last_rev == 0:
307 if last_rev == 0 or c.repo_last_rev == 0:
308 c.stats_percentage = 0
308 c.stats_percentage = 0
309 else:
309 else:
310 c.stats_percentage = '%.2f' % ((float((last_rev)) /
310 c.stats_percentage = '%.2f' % ((float((last_rev)) /
311 c.repo_last_rev) * 100)
311 c.repo_last_rev) * 100)
312
312
313 c.users_array = repo_model.get_users_js()
313 c.users_array = repo_model.get_users_js()
314 c.users_groups_array = repo_model.get_users_groups_js()
314 c.users_groups_array = repo_model.get_users_groups_js()
315
315
316 defaults = c.repo_info.get_dict()
316 defaults = c.repo_info.get_dict()
317
317
318 #fill owner
318 #fill owner
319 if c.repo_info.user:
319 if c.repo_info.user:
320 defaults.update({'user':c.repo_info.user.username})
320 defaults.update({'user':c.repo_info.user.username})
321 else:
321 else:
322 replacement_user = self.sa.query(User)\
322 replacement_user = self.sa.query(User)\
323 .filter(User.admin == True).first().username
323 .filter(User.admin == True).first().username
324 defaults.update({'user':replacement_user})
324 defaults.update({'user':replacement_user})
325
325
326
326
327 #fill repository users
327 #fill repository users
328 for p in c.repo_info.repo_to_perm:
328 for p in c.repo_info.repo_to_perm:
329 defaults.update({'u_perm_%s' % p.user.username:
329 defaults.update({'u_perm_%s' % p.user.username:
330 p.permission.permission_name})
330 p.permission.permission_name})
331
331
332 #fill repository groups
332 #fill repository groups
333 for p in c.repo_info.users_group_to_perm:
333 for p in c.repo_info.users_group_to_perm:
334 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
334 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
335 p.permission.permission_name})
335 p.permission.permission_name})
336
336
337 return htmlfill.render(
337 return htmlfill.render(
338 render('admin/repos/repo_edit.html'),
338 render('admin/repos/repo_edit.html'),
339 defaults=defaults,
339 defaults=defaults,
340 encoding="UTF-8",
340 encoding="UTF-8",
341 force_defaults=False
341 force_defaults=False
342 )
342 )
@@ -1,213 +1,212 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.changeset
3 rhodecode.controllers.changeset
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 changeset controller for pylons showoing changes beetween
6 changeset controller for pylons showoing changes beetween
7 revisions
7 revisions
8
8
9 :created_on: Apr 25, 2010
9 :created_on: Apr 25, 2010
10 :author: marcink
10 :author: marcink
11 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
12 :license: GPLv3, see COPYING for more details.
12 :license: GPLv3, see COPYING for more details.
13 """
13 """
14 # This program is free software; you can redistribute it and/or
14 # This program is free software; you can redistribute it and/or
15 # modify it under the terms of the GNU General Public License
15 # modify it under the terms of the GNU General Public License
16 # as published by the Free Software Foundation; version 2
16 # as published by the Free Software Foundation; version 2
17 # of the License or (at your opinion) any later version of the license.
17 # of the License or (at your opinion) any later version of the license.
18 #
18 #
19 # This program is distributed in the hope that it will be useful,
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
22 # GNU General Public License for more details.
23 #
23 #
24 # You should have received a copy of the GNU General Public License
24 # You should have received a copy of the GNU General Public License
25 # along with this program; if not, write to the Free Software
25 # along with this program; if not, write to the Free Software
26 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
27 # MA 02110-1301, USA.
27 # MA 02110-1301, USA.
28 import logging
28 import logging
29 import traceback
29 import traceback
30
30
31 from pylons import tmpl_context as c, url, request, response
31 from pylons import tmpl_context as c, url, request, response
32 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
33 from pylons.controllers.util import redirect
33 from pylons.controllers.util import redirect
34
34
35 import rhodecode.lib.helpers as h
35 import rhodecode.lib.helpers as h
36 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
36 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
37 from rhodecode.lib.base import BaseRepoController, render
37 from rhodecode.lib.base import BaseRepoController, render
38 from rhodecode.lib.utils import EmptyChangeset
38 from rhodecode.lib.utils import EmptyChangeset
39
39
40 from vcs.exceptions import RepositoryError, ChangesetError, \
40 from vcs.exceptions import RepositoryError, ChangesetError, \
41 ChangesetDoesNotExistError
41 ChangesetDoesNotExistError
42 from vcs.nodes import FileNode
42 from vcs.nodes import FileNode
43 from vcs.utils import diffs as differ
43 from vcs.utils import diffs as differ
44 from vcs.utils.ordered_dict import OrderedDict
44 from vcs.utils.ordered_dict import OrderedDict
45
45
46 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
47
47
48 class ChangesetController(BaseRepoController):
48 class ChangesetController(BaseRepoController):
49
49
50 @LoginRequired()
50 @LoginRequired()
51 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
51 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
52 'repository.admin')
52 'repository.admin')
53 def __before__(self):
53 def __before__(self):
54 super(ChangesetController, self).__before__()
54 super(ChangesetController, self).__before__()
55
55
56 def index(self, revision):
56 def index(self, revision):
57
57
58 def wrap_to_table(str):
58 def wrap_to_table(str):
59
59
60 return '''<table class="code-difftable">
60 return '''<table class="code-difftable">
61 <tr class="line">
61 <tr class="line">
62 <td class="lineno new"></td>
62 <td class="lineno new"></td>
63 <td class="code"><pre>%s</pre></td>
63 <td class="code"><pre>%s</pre></td>
64 </tr>
64 </tr>
65 </table>''' % str
65 </table>''' % str
66
66
67 #get ranges of revisions if preset
67 #get ranges of revisions if preset
68 rev_range = revision.split('...')[:2]
68 rev_range = revision.split('...')[:2]
69 range_limit = 50
69 range_limit = 50
70 try:
70 try:
71 if len(rev_range) == 2:
71 if len(rev_range) == 2:
72 rev_start = rev_range[0]
72 rev_start = rev_range[0]
73 rev_end = rev_range[1]
73 rev_end = rev_range[1]
74 rev_ranges = c.rhodecode_repo.get_changesets_ranges(rev_start, rev_end,
74 rev_ranges = list(c.rhodecode_repo[rev_start:rev_end])
75 range_limit)
76 else:
75 else:
77 rev_ranges = [c.rhodecode_repo.get_changeset(revision)]
76 rev_ranges = [c.rhodecode_repo.get_changeset(revision)]
78
77
79 c.cs_ranges = list(rev_ranges)
78 c.cs_ranges = list(rev_ranges)
80
79
81 except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
80 except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
82 log.error(traceback.format_exc())
81 log.error(traceback.format_exc())
83 h.flash(str(e), category='warning')
82 h.flash(str(e), category='warning')
84 return redirect(url('home'))
83 return redirect(url('home'))
85
84
86 c.changes = OrderedDict()
85 c.changes = OrderedDict()
87 c.sum_added = 0
86 c.sum_added = 0
88 c.sum_removed = 0
87 c.sum_removed = 0
89
88
90
89
91 for changeset in c.cs_ranges:
90 for changeset in c.cs_ranges:
92 c.changes[changeset.raw_id] = []
91 c.changes[changeset.raw_id] = []
93 try:
92 try:
94 changeset_parent = changeset.parents[0]
93 changeset_parent = changeset.parents[0]
95 except IndexError:
94 except IndexError:
96 changeset_parent = None
95 changeset_parent = None
97
96
98
97
99 #==================================================================
98 #==================================================================
100 # ADDED FILES
99 # ADDED FILES
101 #==================================================================
100 #==================================================================
102 for node in changeset.added:
101 for node in changeset.added:
103 filenode_old = FileNode(node.path, '', EmptyChangeset())
102 filenode_old = FileNode(node.path, '', EmptyChangeset())
104 if filenode_old.is_binary or node.is_binary:
103 if filenode_old.is_binary or node.is_binary:
105 diff = wrap_to_table(_('binary file'))
104 diff = wrap_to_table(_('binary file'))
106 else:
105 else:
107 c.sum_added += node.size
106 c.sum_added += node.size
108 if c.sum_added < self.cut_off_limit:
107 if c.sum_added < self.cut_off_limit:
109 f_udiff = differ.get_udiff(filenode_old, node)
108 f_udiff = differ.get_udiff(filenode_old, node)
110 diff = differ.DiffProcessor(f_udiff).as_html()
109 diff = differ.DiffProcessor(f_udiff).as_html()
111
110
112 else:
111 else:
113 diff = wrap_to_table(_('Changeset is to big and was cut'
112 diff = wrap_to_table(_('Changeset is to big and was cut'
114 ' off, see raw changeset instead'))
113 ' off, see raw changeset instead'))
115
114
116 cs1 = None
115 cs1 = None
117 cs2 = node.last_changeset.raw_id
116 cs2 = node.last_changeset.raw_id
118 c.changes[changeset.raw_id].append(('added', node, diff, cs1, cs2))
117 c.changes[changeset.raw_id].append(('added', node, diff, cs1, cs2))
119
118
120 #==================================================================
119 #==================================================================
121 # CHANGED FILES
120 # CHANGED FILES
122 #==================================================================
121 #==================================================================
123 for node in changeset.changed:
122 for node in changeset.changed:
124 try:
123 try:
125 filenode_old = changeset_parent.get_node(node.path)
124 filenode_old = changeset_parent.get_node(node.path)
126 except ChangesetError:
125 except ChangesetError:
127 filenode_old = FileNode(node.path, '', EmptyChangeset())
126 filenode_old = FileNode(node.path, '', EmptyChangeset())
128
127
129 if filenode_old.is_binary or node.is_binary:
128 if filenode_old.is_binary or node.is_binary:
130 diff = wrap_to_table(_('binary file'))
129 diff = wrap_to_table(_('binary file'))
131 else:
130 else:
132
131
133 if c.sum_removed < self.cut_off_limit:
132 if c.sum_removed < self.cut_off_limit:
134 f_udiff = differ.get_udiff(filenode_old, node)
133 f_udiff = differ.get_udiff(filenode_old, node)
135 diff = differ.DiffProcessor(f_udiff).as_html()
134 diff = differ.DiffProcessor(f_udiff).as_html()
136 if diff:
135 if diff:
137 c.sum_removed += len(diff)
136 c.sum_removed += len(diff)
138 else:
137 else:
139 diff = wrap_to_table(_('Changeset is to big and was cut'
138 diff = wrap_to_table(_('Changeset is to big and was cut'
140 ' off, see raw changeset instead'))
139 ' off, see raw changeset instead'))
141
140
142
141
143 cs1 = filenode_old.last_changeset.raw_id
142 cs1 = filenode_old.last_changeset.raw_id
144 cs2 = node.last_changeset.raw_id
143 cs2 = node.last_changeset.raw_id
145 c.changes[changeset.raw_id].append(('changed', node, diff, cs1, cs2))
144 c.changes[changeset.raw_id].append(('changed', node, diff, cs1, cs2))
146
145
147 #==================================================================
146 #==================================================================
148 # REMOVED FILES
147 # REMOVED FILES
149 #==================================================================
148 #==================================================================
150 for node in changeset.removed:
149 for node in changeset.removed:
151 c.changes[changeset.raw_id].append(('removed', node, None, None, None))
150 c.changes[changeset.raw_id].append(('removed', node, None, None, None))
152
151
153 if len(c.cs_ranges) == 1:
152 if len(c.cs_ranges) == 1:
154 c.changeset = c.cs_ranges[0]
153 c.changeset = c.cs_ranges[0]
155 c.changes = c.changes[c.changeset.raw_id]
154 c.changes = c.changes[c.changeset.raw_id]
156
155
157 return render('changeset/changeset.html')
156 return render('changeset/changeset.html')
158 else:
157 else:
159 return render('changeset/changeset_range.html')
158 return render('changeset/changeset_range.html')
160
159
161 def raw_changeset(self, revision):
160 def raw_changeset(self, revision):
162
161
163 method = request.GET.get('diff', 'show')
162 method = request.GET.get('diff', 'show')
164 try:
163 try:
165 c.scm_type = c.rhodecode_repo.alias
164 c.scm_type = c.rhodecode_repo.alias
166 c.changeset = c.rhodecode_repo.get_changeset(revision)
165 c.changeset = c.rhodecode_repo.get_changeset(revision)
167 except RepositoryError:
166 except RepositoryError:
168 log.error(traceback.format_exc())
167 log.error(traceback.format_exc())
169 return redirect(url('home'))
168 return redirect(url('home'))
170 else:
169 else:
171 try:
170 try:
172 c.changeset_parent = c.changeset.parents[0]
171 c.changeset_parent = c.changeset.parents[0]
173 except IndexError:
172 except IndexError:
174 c.changeset_parent = None
173 c.changeset_parent = None
175 c.changes = []
174 c.changes = []
176
175
177 for node in c.changeset.added:
176 for node in c.changeset.added:
178 filenode_old = FileNode(node.path, '')
177 filenode_old = FileNode(node.path, '')
179 if filenode_old.is_binary or node.is_binary:
178 if filenode_old.is_binary or node.is_binary:
180 diff = _('binary file') + '\n'
179 diff = _('binary file') + '\n'
181 else:
180 else:
182 f_udiff = differ.get_gitdiff(filenode_old, node)
181 f_udiff = differ.get_gitdiff(filenode_old, node)
183 diff = differ.DiffProcessor(f_udiff).raw_diff()
182 diff = differ.DiffProcessor(f_udiff).raw_diff()
184
183
185 cs1 = None
184 cs1 = None
186 cs2 = node.last_changeset.raw_id
185 cs2 = node.last_changeset.raw_id
187 c.changes.append(('added', node, diff, cs1, cs2))
186 c.changes.append(('added', node, diff, cs1, cs2))
188
187
189 for node in c.changeset.changed:
188 for node in c.changeset.changed:
190 filenode_old = c.changeset_parent.get_node(node.path)
189 filenode_old = c.changeset_parent.get_node(node.path)
191 if filenode_old.is_binary or node.is_binary:
190 if filenode_old.is_binary or node.is_binary:
192 diff = _('binary file')
191 diff = _('binary file')
193 else:
192 else:
194 f_udiff = differ.get_gitdiff(filenode_old, node)
193 f_udiff = differ.get_gitdiff(filenode_old, node)
195 diff = differ.DiffProcessor(f_udiff).raw_diff()
194 diff = differ.DiffProcessor(f_udiff).raw_diff()
196
195
197 cs1 = filenode_old.last_changeset.raw_id
196 cs1 = filenode_old.last_changeset.raw_id
198 cs2 = node.last_changeset.raw_id
197 cs2 = node.last_changeset.raw_id
199 c.changes.append(('changed', node, diff, cs1, cs2))
198 c.changes.append(('changed', node, diff, cs1, cs2))
200
199
201 response.content_type = 'text/plain'
200 response.content_type = 'text/plain'
202
201
203 if method == 'download':
202 if method == 'download':
204 response.content_disposition = 'attachment; filename=%s.patch' % revision
203 response.content_disposition = 'attachment; filename=%s.patch' % revision
205
204
206 parent = True if len(c.changeset.parents) > 0 else False
205 parent = True if len(c.changeset.parents) > 0 else False
207 c.parent_tmpl = 'Parent %s' % c.changeset.parents[0].raw_id if parent else ''
206 c.parent_tmpl = 'Parent %s' % c.changeset.parents[0].raw_id if parent else ''
208
207
209 c.diffs = ''
208 c.diffs = ''
210 for x in c.changes:
209 for x in c.changes:
211 c.diffs += x[2]
210 c.diffs += x[2]
212
211
213 return render('changeset/raw_changeset.html')
212 return render('changeset/raw_changeset.html')
@@ -1,170 +1,170 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) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 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
13 # This program is free software; you can redistribute it and/or
14 # modify it under the terms of the GNU General Public License
14 # modify it under the terms of the GNU General Public License
15 # as published by the Free Software Foundation; version 2
15 # as published by the Free Software Foundation; version 2
16 # of the License or (at your opinion) any later version of the license.
16 # of the License or (at your opinion) any later version of the license.
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, write to the Free Software
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 # MA 02110-1301, USA.
26 # MA 02110-1301, USA.
27
27
28 import calendar
28 import calendar
29 import logging
29 import logging
30 from time import mktime
30 from time import mktime
31 from datetime import datetime, timedelta, date
31 from datetime import datetime, timedelta, date
32
32
33 from vcs.exceptions import ChangesetError
33 from vcs.exceptions import ChangesetError
34
34
35 from pylons import tmpl_context as c, request, url
35 from pylons import tmpl_context as c, request, url
36 from pylons.i18n.translation import _
36 from pylons.i18n.translation import _
37
37
38 from rhodecode.model.db import Statistics
38 from rhodecode.model.db import Statistics
39
39
40 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
40 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
41 from rhodecode.lib.base import BaseRepoController, render
41 from rhodecode.lib.base import BaseRepoController, render
42 from rhodecode.lib.utils import OrderedDict, EmptyChangeset
42 from rhodecode.lib.utils import OrderedDict, EmptyChangeset
43
43
44 from rhodecode.lib.celerylib import run_task
44 from rhodecode.lib.celerylib import run_task
45 from rhodecode.lib.celerylib.tasks import get_commits_stats
45 from rhodecode.lib.celerylib.tasks import get_commits_stats
46
46
47 from webhelpers.paginate import Page
47 from webhelpers.paginate import Page
48
48
49 try:
49 try:
50 import json
50 import json
51 except ImportError:
51 except ImportError:
52 #python 2.5 compatibility
52 #python 2.5 compatibility
53 import simplejson as json
53 import simplejson as json
54 log = logging.getLogger(__name__)
54 log = logging.getLogger(__name__)
55
55
56 class SummaryController(BaseRepoController):
56 class SummaryController(BaseRepoController):
57
57
58 @LoginRequired()
58 @LoginRequired()
59 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
59 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
60 'repository.admin')
60 'repository.admin')
61 def __before__(self):
61 def __before__(self):
62 super(SummaryController, self).__before__()
62 super(SummaryController, self).__before__()
63
63
64 def index(self):
64 def index(self):
65 c.repo, dbrepo = self.scm_model.get(c.repo_name)
65 c.repo, dbrepo = self.scm_model.get(c.repo_name)
66 c.dbrepo = dbrepo
66 c.dbrepo = dbrepo
67
67
68 c.following = self.scm_model.is_following_repo(c.repo_name,
68 c.following = self.scm_model.is_following_repo(c.repo_name,
69 c.rhodecode_user.user_id)
69 c.rhodecode_user.user_id)
70 def url_generator(**kw):
70 def url_generator(**kw):
71 return url('shortlog_home', repo_name=c.repo_name, **kw)
71 return url('shortlog_home', repo_name=c.repo_name, **kw)
72
72
73 c.repo_changesets = Page(c.repo, page=1, items_per_page=10,
73 c.repo_changesets = Page(c.repo, page=1, items_per_page=10,
74 url=url_generator)
74 url=url_generator)
75
75
76 e = request.environ
76 e = request.environ
77
77
78 if self.rhodecode_user.username == 'default':
78 if self.rhodecode_user.username == 'default':
79 #for default(anonymous) user we don't need to pass credentials
79 #for default(anonymous) user we don't need to pass credentials
80 username = ''
80 username = ''
81 password = ''
81 password = ''
82 else:
82 else:
83 username = str(c.rhodecode_user.username)
83 username = str(c.rhodecode_user.username)
84 password = '@'
84 password = '@'
85
85
86 uri = u'%(protocol)s://%(user)s%(password)s%(host)s%(prefix)s/%(repo_name)s' % {
86 uri = u'%(protocol)s://%(user)s%(password)s%(host)s%(prefix)s/%(repo_name)s' % {
87 'protocol': e.get('wsgi.url_scheme'),
87 'protocol': e.get('wsgi.url_scheme'),
88 'user':username,
88 'user':username,
89 'password':password,
89 'password':password,
90 'host':e.get('HTTP_HOST'),
90 'host':e.get('HTTP_HOST'),
91 'prefix':e.get('SCRIPT_NAME'),
91 'prefix':e.get('SCRIPT_NAME'),
92 'repo_name':c.repo_name, }
92 'repo_name':c.repo_name, }
93 c.clone_repo_url = uri
93 c.clone_repo_url = uri
94 c.repo_tags = OrderedDict()
94 c.repo_tags = OrderedDict()
95 for name, hash in c.repo.tags.items()[:10]:
95 for name, hash in c.repo.tags.items()[:10]:
96 try:
96 try:
97 c.repo_tags[name] = c.repo.get_changeset(hash)
97 c.repo_tags[name] = c.repo.get_changeset(hash)
98 except ChangesetError:
98 except ChangesetError:
99 c.repo_tags[name] = EmptyChangeset(hash)
99 c.repo_tags[name] = EmptyChangeset(hash)
100
100
101 c.repo_branches = OrderedDict()
101 c.repo_branches = OrderedDict()
102 for name, hash in c.repo.branches.items()[:10]:
102 for name, hash in c.repo.branches.items()[:10]:
103 try:
103 try:
104 c.repo_branches[name] = c.repo.get_changeset(hash)
104 c.repo_branches[name] = c.repo.get_changeset(hash)
105 except ChangesetError:
105 except ChangesetError:
106 c.repo_branches[name] = EmptyChangeset(hash)
106 c.repo_branches[name] = EmptyChangeset(hash)
107
107
108 td = date.today() + timedelta(days=1)
108 td = date.today() + timedelta(days=1)
109 td_1m = td - timedelta(days=calendar.mdays[td.month])
109 td_1m = td - timedelta(days=calendar.mdays[td.month])
110 td_1y = td - timedelta(days=365)
110 td_1y = td - timedelta(days=365)
111
111
112 ts_min_m = mktime(td_1m.timetuple())
112 ts_min_m = mktime(td_1m.timetuple())
113 ts_min_y = mktime(td_1y.timetuple())
113 ts_min_y = mktime(td_1y.timetuple())
114 ts_max_y = mktime(td.timetuple())
114 ts_max_y = mktime(td.timetuple())
115
115
116 if dbrepo.enable_statistics:
116 if dbrepo.enable_statistics:
117 c.no_data_msg = _('No data loaded yet')
117 c.no_data_msg = _('No data loaded yet')
118 run_task(get_commits_stats, c.repo.name, ts_min_y, ts_max_y)
118 run_task(get_commits_stats, c.repo.name, ts_min_y, ts_max_y)
119 else:
119 else:
120 c.no_data_msg = _('Statistics update are disabled for this repository')
120 c.no_data_msg = _('Statistics are disabled for this repository')
121 c.ts_min = ts_min_m
121 c.ts_min = ts_min_m
122 c.ts_max = ts_max_y
122 c.ts_max = ts_max_y
123
123
124 stats = self.sa.query(Statistics)\
124 stats = self.sa.query(Statistics)\
125 .filter(Statistics.repository == dbrepo)\
125 .filter(Statistics.repository == dbrepo)\
126 .scalar()
126 .scalar()
127
127
128
128
129 if stats and stats.languages:
129 if stats and stats.languages:
130 c.no_data = False is dbrepo.enable_statistics
130 c.no_data = False is dbrepo.enable_statistics
131 lang_stats = json.loads(stats.languages)
131 lang_stats = json.loads(stats.languages)
132 c.commit_data = stats.commit_activity
132 c.commit_data = stats.commit_activity
133 c.overview_data = stats.commit_activity_combined
133 c.overview_data = stats.commit_activity_combined
134 c.trending_languages = json.dumps(OrderedDict(
134 c.trending_languages = json.dumps(OrderedDict(
135 sorted(lang_stats.items(), reverse=True,
135 sorted(lang_stats.items(), reverse=True,
136 key=lambda k: k[1])[:10]
136 key=lambda k: k[1])[:10]
137 )
137 )
138 )
138 )
139 else:
139 else:
140 c.commit_data = json.dumps({})
140 c.commit_data = json.dumps({})
141 c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10] ])
141 c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10] ])
142 c.trending_languages = json.dumps({})
142 c.trending_languages = json.dumps({})
143 c.no_data = True
143 c.no_data = True
144
144
145 c.enable_downloads = dbrepo.enable_downloads
145 c.enable_downloads = dbrepo.enable_downloads
146 if c.enable_downloads:
146 if c.enable_downloads:
147 c.download_options = self._get_download_links(c.repo)
147 c.download_options = self._get_download_links(c.repo)
148
148
149 return render('summary/summary.html')
149 return render('summary/summary.html')
150
150
151
151
152
152
153 def _get_download_links(self, repo):
153 def _get_download_links(self, repo):
154
154
155 download_l = []
155 download_l = []
156
156
157 branches_group = ([], _("Branches"))
157 branches_group = ([], _("Branches"))
158 tags_group = ([], _("Tags"))
158 tags_group = ([], _("Tags"))
159
159
160 for name, chs in c.rhodecode_repo.branches.items():
160 for name, chs in c.rhodecode_repo.branches.items():
161 #chs = chs.split(':')[-1]
161 #chs = chs.split(':')[-1]
162 branches_group[0].append((chs, name),)
162 branches_group[0].append((chs, name),)
163 download_l.append(branches_group)
163 download_l.append(branches_group)
164
164
165 for name, chs in c.rhodecode_repo.tags.items():
165 for name, chs in c.rhodecode_repo.tags.items():
166 #chs = chs.split(':')[-1]
166 #chs = chs.split(':')[-1]
167 tags_group[0].append((chs, name),)
167 tags_group[0].append((chs, name),)
168 download_l.append(tags_group)
168 download_l.append(tags_group)
169
169
170 return download_l
170 return download_l
@@ -1,105 +1,107 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.celerylib.__init__
3 rhodecode.lib.celerylib.__init__
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 celery libs for RhodeCode
6 celery libs for RhodeCode
7
7
8 :created_on: Nov 27, 2010
8 :created_on: Nov 27, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 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
13 # This program is free software; you can redistribute it and/or
14 # modify it under the terms of the GNU General Public License
14 # modify it under the terms of the GNU General Public License
15 # as published by the Free Software Foundation; version 2
15 # as published by the Free Software Foundation; version 2
16 # of the License or (at your opinion) any later version of the license.
16 # of the License or (at your opinion) any later version of the license.
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, write to the Free Software
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 # MA 02110-1301, USA.
26 # MA 02110-1301, USA.
27
27
28 import os
28 import os
29 import sys
29 import sys
30 import socket
30 import socket
31 import traceback
31 import traceback
32 import logging
32 import logging
33
33
34 from hashlib import md5
34 from hashlib import md5
35 from decorator import decorator
35 from decorator import decorator
36 from pylons import config
37
36 from vcs.utils.lazy import LazyProperty
38 from vcs.utils.lazy import LazyProperty
37
39
38 from rhodecode.lib import str2bool
40 from rhodecode.lib import str2bool
39 from rhodecode.lib.pidlock import DaemonLock, LockHeld
41 from rhodecode.lib.pidlock import DaemonLock, LockHeld
40
42
41 from celery.messaging import establish_connection
43 from celery.messaging import establish_connection
42 from pylons import config
44
43
45
44 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
45
47
46 try:
48 try:
47 CELERY_ON = str2bool(config['app_conf'].get('use_celery'))
49 CELERY_ON = str2bool(config['app_conf'].get('use_celery'))
48 except KeyError:
50 except KeyError:
49 CELERY_ON = False
51 CELERY_ON = False
50
52
51 class ResultWrapper(object):
53 class ResultWrapper(object):
52 def __init__(self, task):
54 def __init__(self, task):
53 self.task = task
55 self.task = task
54
56
55 @LazyProperty
57 @LazyProperty
56 def result(self):
58 def result(self):
57 return self.task
59 return self.task
58
60
59 def run_task(task, *args, **kwargs):
61 def run_task(task, *args, **kwargs):
60 if CELERY_ON:
62 if CELERY_ON:
61 try:
63 try:
62 t = task.apply_async(args=args, kwargs=kwargs)
64 t = task.apply_async(args=args, kwargs=kwargs)
63 log.info('running task %s:%s', t.task_id, task)
65 log.info('running task %s:%s', t.task_id, task)
64 return t
66 return t
65 except socket.error, e:
67 except socket.error, e:
66 if e.errno == 111:
68 if e.errno == 111:
67 log.debug('Unable to connect to celeryd. Sync execution')
69 log.debug('Unable to connect to celeryd. Sync execution')
68 else:
70 else:
69 log.error(traceback.format_exc())
71 log.error(traceback.format_exc())
70 except KeyError, e:
72 except KeyError, e:
71 log.debug('Unable to connect to celeryd. Sync execution')
73 log.debug('Unable to connect to celeryd. Sync execution')
72 except Exception, e:
74 except Exception, e:
73 log.error(traceback.format_exc())
75 log.error(traceback.format_exc())
74
76
75 log.debug('executing task %s in sync mode', task)
77 log.debug('executing task %s in sync mode', task)
76 return ResultWrapper(task(*args, **kwargs))
78 return ResultWrapper(task(*args, **kwargs))
77
79
78
80
79 def locked_task(func):
81 def locked_task(func):
80 def __wrapper(func, *fargs, **fkwargs):
82 def __wrapper(func, *fargs, **fkwargs):
81 params = list(fargs)
83 params = list(fargs)
82 params.extend(['%s-%s' % ar for ar in fkwargs.items()])
84 params.extend(['%s-%s' % ar for ar in fkwargs.items()])
83
85
84 lockkey = 'task_%s' % \
86 lockkey = 'task_%s' % \
85 md5(str(func.__name__) + '-' + \
87 md5(str(func.__name__) + '-' + \
86 '-'.join(map(str, params))).hexdigest()
88 '-'.join(map(str, params))).hexdigest()
87 log.info('running task with lockkey %s', lockkey)
89 log.info('running task with lockkey %s', lockkey)
88 try:
90 try:
89 l = DaemonLock(lockkey)
91 l = DaemonLock(lockkey)
90 ret = func(*fargs, **fkwargs)
92 ret = func(*fargs, **fkwargs)
91 l.release()
93 l.release()
92 return ret
94 return ret
93 except LockHeld:
95 except LockHeld:
94 log.info('LockHeld')
96 log.info('LockHeld')
95 return 'Task with key %s already running' % lockkey
97 return 'Task with key %s already running' % lockkey
96
98
97 return decorator(__wrapper, func)
99 return decorator(__wrapper, func)
98
100
99
101
100
102
101
103
102
104
103
105
104
106
105
107
General Comments 0
You need to be logged in to leave comments. Login now