##// END OF EJS Templates
iterate over repos groups for bool() calls to actually work on it....
marcink -
r3418:9fe4543b beta
parent child Browse files
Show More
@@ -1,633 +1,631 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.scm
3 rhodecode.model.scm
4 ~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~
5
5
6 Scm model for RhodeCode
6 Scm model for RhodeCode
7
7
8 :created_on: Apr 9, 2010
8 :created_on: Apr 9, 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 from __future__ import with_statement
25 from __future__ import with_statement
26 import os
26 import os
27 import re
27 import re
28 import time
28 import time
29 import traceback
29 import traceback
30 import logging
30 import logging
31 import cStringIO
31 import cStringIO
32 import pkg_resources
32 import pkg_resources
33 from os.path import dirname as dn, join as jn
33 from os.path import dirname as dn, join as jn
34
34
35 from sqlalchemy import func
35 from sqlalchemy import func
36 from pylons.i18n.translation import _
36 from pylons.i18n.translation import _
37
37
38 import rhodecode
38 import rhodecode
39 from rhodecode.lib.vcs import get_backend
39 from rhodecode.lib.vcs import get_backend
40 from rhodecode.lib.vcs.exceptions import RepositoryError
40 from rhodecode.lib.vcs.exceptions import RepositoryError
41 from rhodecode.lib.vcs.utils.lazy import LazyProperty
41 from rhodecode.lib.vcs.utils.lazy import LazyProperty
42 from rhodecode.lib.vcs.nodes import FileNode
42 from rhodecode.lib.vcs.nodes import FileNode
43 from rhodecode.lib.vcs.backends.base import EmptyChangeset
43 from rhodecode.lib.vcs.backends.base import EmptyChangeset
44
44
45 from rhodecode import BACKENDS
45 from rhodecode import BACKENDS
46 from rhodecode.lib import helpers as h
46 from rhodecode.lib import helpers as h
47 from rhodecode.lib.utils2 import safe_str, safe_unicode
47 from rhodecode.lib.utils2 import safe_str, safe_unicode
48 from rhodecode.lib.auth import HasRepoPermissionAny, HasReposGroupPermissionAny
48 from rhodecode.lib.auth import HasRepoPermissionAny, HasReposGroupPermissionAny
49 from rhodecode.lib.utils import get_filesystem_repos, make_ui, \
49 from rhodecode.lib.utils import get_filesystem_repos, make_ui, \
50 action_logger, REMOVED_REPO_PAT
50 action_logger, REMOVED_REPO_PAT
51 from rhodecode.model import BaseModel
51 from rhodecode.model import BaseModel
52 from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
52 from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
53 UserFollowing, UserLog, User, RepoGroup, PullRequest
53 UserFollowing, UserLog, User, RepoGroup, PullRequest
54
54
55 log = logging.getLogger(__name__)
55 log = logging.getLogger(__name__)
56
56
57
57
58 class UserTemp(object):
58 class UserTemp(object):
59 def __init__(self, user_id):
59 def __init__(self, user_id):
60 self.user_id = user_id
60 self.user_id = user_id
61
61
62 def __repr__(self):
62 def __repr__(self):
63 return "<%s('id:%s')>" % (self.__class__.__name__, self.user_id)
63 return "<%s('id:%s')>" % (self.__class__.__name__, self.user_id)
64
64
65
65
66 class RepoTemp(object):
66 class RepoTemp(object):
67 def __init__(self, repo_id):
67 def __init__(self, repo_id):
68 self.repo_id = repo_id
68 self.repo_id = repo_id
69
69
70 def __repr__(self):
70 def __repr__(self):
71 return "<%s('id:%s')>" % (self.__class__.__name__, self.repo_id)
71 return "<%s('id:%s')>" % (self.__class__.__name__, self.repo_id)
72
72
73
73
74 class CachedRepoList(object):
74 class CachedRepoList(object):
75 """
75 """
76 Cached repo list, uses in-memory cache after initialization, that is
76 Cached repo list, uses in-memory cache after initialization, that is
77 super fast
77 super fast
78 """
78 """
79
79
80 def __init__(self, db_repo_list, repos_path, order_by=None, perm_set=None):
80 def __init__(self, db_repo_list, repos_path, order_by=None, perm_set=None):
81 self.db_repo_list = db_repo_list
81 self.db_repo_list = db_repo_list
82 self.repos_path = repos_path
82 self.repos_path = repos_path
83 self.order_by = order_by
83 self.order_by = order_by
84 self.reversed = (order_by or '').startswith('-')
84 self.reversed = (order_by or '').startswith('-')
85 if not perm_set:
85 if not perm_set:
86 perm_set = ['repository.read', 'repository.write',
86 perm_set = ['repository.read', 'repository.write',
87 'repository.admin']
87 'repository.admin']
88 self.perm_set = perm_set
88 self.perm_set = perm_set
89
89
90 def __len__(self):
90 def __len__(self):
91 return len(self.db_repo_list)
91 return len(self.db_repo_list)
92
92
93 def __repr__(self):
93 def __repr__(self):
94 return '<%s (%s)>' % (self.__class__.__name__, self.__len__())
94 return '<%s (%s)>' % (self.__class__.__name__, self.__len__())
95
95
96 def __iter__(self):
96 def __iter__(self):
97 # pre-propagated cache_map to save executing select statements
97 # pre-propagated cache_map to save executing select statements
98 # for each repo
98 # for each repo
99 cache_map = CacheInvalidation.get_cache_map()
99 cache_map = CacheInvalidation.get_cache_map()
100
100
101 for dbr in self.db_repo_list:
101 for dbr in self.db_repo_list:
102 scmr = dbr.scm_instance_cached(cache_map)
102 scmr = dbr.scm_instance_cached(cache_map)
103 # check permission at this level
103 # check permission at this level
104 if not HasRepoPermissionAny(
104 if not HasRepoPermissionAny(
105 *self.perm_set
105 *self.perm_set
106 )(dbr.repo_name, 'get repo check'):
106 )(dbr.repo_name, 'get repo check'):
107 continue
107 continue
108
108
109 try:
109 try:
110 last_change = scmr.last_change
110 last_change = scmr.last_change
111 tip = h.get_changeset_safe(scmr, 'tip')
111 tip = h.get_changeset_safe(scmr, 'tip')
112 except Exception:
112 except Exception:
113 log.error(
113 log.error(
114 '%s this repository is present in database but it '
114 '%s this repository is present in database but it '
115 'cannot be created as an scm instance, org_exc:%s'
115 'cannot be created as an scm instance, org_exc:%s'
116 % (dbr.repo_name, traceback.format_exc())
116 % (dbr.repo_name, traceback.format_exc())
117 )
117 )
118 continue
118 continue
119
119
120 tmp_d = {}
120 tmp_d = {}
121 tmp_d['name'] = dbr.repo_name
121 tmp_d['name'] = dbr.repo_name
122 tmp_d['name_sort'] = tmp_d['name'].lower()
122 tmp_d['name_sort'] = tmp_d['name'].lower()
123 tmp_d['raw_name'] = tmp_d['name'].lower()
123 tmp_d['raw_name'] = tmp_d['name'].lower()
124 tmp_d['description'] = dbr.description
124 tmp_d['description'] = dbr.description
125 tmp_d['description_sort'] = tmp_d['description'].lower()
125 tmp_d['description_sort'] = tmp_d['description'].lower()
126 tmp_d['last_change'] = last_change
126 tmp_d['last_change'] = last_change
127 tmp_d['last_change_sort'] = time.mktime(last_change.timetuple())
127 tmp_d['last_change_sort'] = time.mktime(last_change.timetuple())
128 tmp_d['tip'] = tip.raw_id
128 tmp_d['tip'] = tip.raw_id
129 tmp_d['tip_sort'] = tip.revision
129 tmp_d['tip_sort'] = tip.revision
130 tmp_d['rev'] = tip.revision
130 tmp_d['rev'] = tip.revision
131 tmp_d['contact'] = dbr.user.full_contact
131 tmp_d['contact'] = dbr.user.full_contact
132 tmp_d['contact_sort'] = tmp_d['contact']
132 tmp_d['contact_sort'] = tmp_d['contact']
133 tmp_d['owner_sort'] = tmp_d['contact']
133 tmp_d['owner_sort'] = tmp_d['contact']
134 tmp_d['repo_archives'] = list(scmr._get_archives())
134 tmp_d['repo_archives'] = list(scmr._get_archives())
135 tmp_d['last_msg'] = tip.message
135 tmp_d['last_msg'] = tip.message
136 tmp_d['author'] = tip.author
136 tmp_d['author'] = tip.author
137 tmp_d['dbrepo'] = dbr.get_dict()
137 tmp_d['dbrepo'] = dbr.get_dict()
138 tmp_d['dbrepo_fork'] = dbr.fork.get_dict() if dbr.fork else {}
138 tmp_d['dbrepo_fork'] = dbr.fork.get_dict() if dbr.fork else {}
139 yield tmp_d
139 yield tmp_d
140
140
141
141
142 class SimpleCachedRepoList(CachedRepoList):
142 class SimpleCachedRepoList(CachedRepoList):
143 """
143 """
144 Lighter version of CachedRepoList without the scm initialisation
144 Lighter version of CachedRepoList without the scm initialisation
145 """
145 """
146
146
147 def __iter__(self):
147 def __iter__(self):
148 for dbr in self.db_repo_list:
148 for dbr in self.db_repo_list:
149 # check permission at this level
149 # check permission at this level
150 if not HasRepoPermissionAny(
150 if not HasRepoPermissionAny(
151 *self.perm_set
151 *self.perm_set
152 )(dbr.repo_name, 'get repo check'):
152 )(dbr.repo_name, 'get repo check'):
153 continue
153 continue
154
154
155 tmp_d = {}
155 tmp_d = {}
156 tmp_d['name'] = dbr.repo_name
156 tmp_d['name'] = dbr.repo_name
157 tmp_d['name_sort'] = tmp_d['name'].lower()
157 tmp_d['name_sort'] = tmp_d['name'].lower()
158 tmp_d['raw_name'] = tmp_d['name'].lower()
158 tmp_d['raw_name'] = tmp_d['name'].lower()
159 tmp_d['description'] = dbr.description
159 tmp_d['description'] = dbr.description
160 tmp_d['description_sort'] = tmp_d['description'].lower()
160 tmp_d['description_sort'] = tmp_d['description'].lower()
161 tmp_d['dbrepo'] = dbr.get_dict()
161 tmp_d['dbrepo'] = dbr.get_dict()
162 tmp_d['dbrepo_fork'] = dbr.fork.get_dict() if dbr.fork else {}
162 tmp_d['dbrepo_fork'] = dbr.fork.get_dict() if dbr.fork else {}
163 yield tmp_d
163 yield tmp_d
164
164
165
165
166 class GroupList(object):
166 class GroupList(object):
167
167
168 def __init__(self, db_repo_group_list, perm_set=None):
168 def __init__(self, db_repo_group_list, perm_set=None):
169 """
169 """
170 Creates iterator from given list of group objects, additionally
170 Creates iterator from given list of group objects, additionally
171 checking permission for them from perm_set var
171 checking permission for them from perm_set var
172
172
173 :param db_repo_group_list:
173 :param db_repo_group_list:
174 :param perm_set: list of permissons to check
174 :param perm_set: list of permissons to check
175 """
175 """
176 self.db_repo_group_list = db_repo_group_list
176 self.db_repo_group_list = db_repo_group_list
177 if not perm_set:
177 if not perm_set:
178 perm_set = ['group.read', 'group.write', 'group.admin']
178 perm_set = ['group.read', 'group.write', 'group.admin']
179 self.perm_set = perm_set
179 self.perm_set = perm_set
180
180
181 def __len__(self):
181 def __len__(self):
182 return len(self.db_repo_group_list)
182 return len(self.db_repo_group_list)
183
183
184 def __repr__(self):
184 def __repr__(self):
185 return '<%s (%s)>' % (self.__class__.__name__, self.__len__())
185 return '<%s (%s)>' % (self.__class__.__name__, self.__len__())
186
186
187 def __iter__(self):
187 def __iter__(self):
188 for dbgr in self.db_repo_group_list:
188 for dbgr in self.db_repo_group_list:
189 # check permission at this level
189 # check permission at this level
190 if not HasReposGroupPermissionAny(
190 if not HasReposGroupPermissionAny(
191 *self.perm_set
191 *self.perm_set
192 )(dbgr.group_name, 'get group repo check'):
192 )(dbgr.group_name, 'get group repo check'):
193 continue
193 continue
194
194
195 yield dbgr
195 yield dbgr
196
196
197
197
198 class ScmModel(BaseModel):
198 class ScmModel(BaseModel):
199 """
199 """
200 Generic Scm Model
200 Generic Scm Model
201 """
201 """
202
202
203 def __get_repo(self, instance):
203 def __get_repo(self, instance):
204 cls = Repository
204 cls = Repository
205 if isinstance(instance, cls):
205 if isinstance(instance, cls):
206 return instance
206 return instance
207 elif isinstance(instance, int) or safe_str(instance).isdigit():
207 elif isinstance(instance, int) or safe_str(instance).isdigit():
208 return cls.get(instance)
208 return cls.get(instance)
209 elif isinstance(instance, basestring):
209 elif isinstance(instance, basestring):
210 return cls.get_by_repo_name(instance)
210 return cls.get_by_repo_name(instance)
211 elif instance:
211 elif instance:
212 raise Exception('given object must be int, basestr or Instance'
212 raise Exception('given object must be int, basestr or Instance'
213 ' of %s got %s' % (type(cls), type(instance)))
213 ' of %s got %s' % (type(cls), type(instance)))
214
214
215 @LazyProperty
215 @LazyProperty
216 def repos_path(self):
216 def repos_path(self):
217 """
217 """
218 Get's the repositories root path from database
218 Get's the repositories root path from database
219 """
219 """
220
220
221 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
221 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
222
222
223 return q.ui_value
223 return q.ui_value
224
224
225 def repo_scan(self, repos_path=None):
225 def repo_scan(self, repos_path=None):
226 """
226 """
227 Listing of repositories in given path. This path should not be a
227 Listing of repositories in given path. This path should not be a
228 repository itself. Return a dictionary of repository objects
228 repository itself. Return a dictionary of repository objects
229
229
230 :param repos_path: path to directory containing repositories
230 :param repos_path: path to directory containing repositories
231 """
231 """
232
232
233 if repos_path is None:
233 if repos_path is None:
234 repos_path = self.repos_path
234 repos_path = self.repos_path
235
235
236 log.info('scanning for repositories in %s' % repos_path)
236 log.info('scanning for repositories in %s' % repos_path)
237
237
238 baseui = make_ui('db')
238 baseui = make_ui('db')
239 repos = {}
239 repos = {}
240
240
241 for name, path in get_filesystem_repos(repos_path, recursive=True):
241 for name, path in get_filesystem_repos(repos_path, recursive=True):
242 # name need to be decomposed and put back together using the /
242 # name need to be decomposed and put back together using the /
243 # since this is internal storage separator for rhodecode
243 # since this is internal storage separator for rhodecode
244 name = Repository.normalize_repo_name(name)
244 name = Repository.normalize_repo_name(name)
245
245
246 try:
246 try:
247 if name in repos:
247 if name in repos:
248 raise RepositoryError('Duplicate repository name %s '
248 raise RepositoryError('Duplicate repository name %s '
249 'found in %s' % (name, path))
249 'found in %s' % (name, path))
250 else:
250 else:
251
251
252 klass = get_backend(path[0])
252 klass = get_backend(path[0])
253
253
254 if path[0] == 'hg' and path[0] in BACKENDS.keys():
254 if path[0] == 'hg' and path[0] in BACKENDS.keys():
255 repos[name] = klass(safe_str(path[1]), baseui=baseui)
255 repos[name] = klass(safe_str(path[1]), baseui=baseui)
256
256
257 if path[0] == 'git' and path[0] in BACKENDS.keys():
257 if path[0] == 'git' and path[0] in BACKENDS.keys():
258 repos[name] = klass(path[1])
258 repos[name] = klass(path[1])
259 except OSError:
259 except OSError:
260 continue
260 continue
261 log.debug('found %s paths with repositories' % (len(repos)))
261 log.debug('found %s paths with repositories' % (len(repos)))
262 return repos
262 return repos
263
263
264 def get_repos(self, all_repos=None, sort_key=None, simple=False):
264 def get_repos(self, all_repos=None, sort_key=None, simple=False):
265 """
265 """
266 Get all repos from db and for each repo create it's
266 Get all repos from db and for each repo create it's
267 backend instance and fill that backed with information from database
267 backend instance and fill that backed with information from database
268
268
269 :param all_repos: list of repository names as strings
269 :param all_repos: list of repository names as strings
270 give specific repositories list, good for filtering
270 give specific repositories list, good for filtering
271
271
272 :param sort_key: initial sorting of repos
272 :param sort_key: initial sorting of repos
273 :param simple: use SimpleCachedList - one without the SCM info
273 :param simple: use SimpleCachedList - one without the SCM info
274 """
274 """
275 if all_repos is None:
275 if all_repos is None:
276 all_repos = self.sa.query(Repository)\
276 all_repos = self.sa.query(Repository)\
277 .filter(Repository.group_id == None)\
277 .filter(Repository.group_id == None)\
278 .order_by(func.lower(Repository.repo_name)).all()
278 .order_by(func.lower(Repository.repo_name)).all()
279 if simple:
279 if simple:
280 repo_iter = SimpleCachedRepoList(all_repos,
280 repo_iter = SimpleCachedRepoList(all_repos,
281 repos_path=self.repos_path,
281 repos_path=self.repos_path,
282 order_by=sort_key)
282 order_by=sort_key)
283 else:
283 else:
284 repo_iter = CachedRepoList(all_repos,
284 repo_iter = CachedRepoList(all_repos,
285 repos_path=self.repos_path,
285 repos_path=self.repos_path,
286 order_by=sort_key)
286 order_by=sort_key)
287
287
288 return repo_iter
288 return repo_iter
289
289
290 def get_repos_groups(self, all_groups=None):
290 def get_repos_groups(self, all_groups=None):
291 if all_groups is None:
291 if all_groups is None:
292 all_groups = RepoGroup.query()\
292 all_groups = RepoGroup.query()\
293 .filter(RepoGroup.group_parent_id == None).all()
293 .filter(RepoGroup.group_parent_id == None).all()
294 group_iter = GroupList(all_groups)
294 return [x for x in GroupList(all_groups)]
295
296 return group_iter
297
295
298 def mark_for_invalidation(self, repo_name):
296 def mark_for_invalidation(self, repo_name):
299 """
297 """
300 Puts cache invalidation task into db for
298 Puts cache invalidation task into db for
301 further global cache invalidation
299 further global cache invalidation
302
300
303 :param repo_name: this repo that should invalidation take place
301 :param repo_name: this repo that should invalidation take place
304 """
302 """
305 invalidated_keys = CacheInvalidation.set_invalidate(repo_name=repo_name)
303 invalidated_keys = CacheInvalidation.set_invalidate(repo_name=repo_name)
306 repo = Repository.get_by_repo_name(repo_name)
304 repo = Repository.get_by_repo_name(repo_name)
307 if repo:
305 if repo:
308 repo.update_changeset_cache()
306 repo.update_changeset_cache()
309 return invalidated_keys
307 return invalidated_keys
310
308
311 def toggle_following_repo(self, follow_repo_id, user_id):
309 def toggle_following_repo(self, follow_repo_id, user_id):
312
310
313 f = self.sa.query(UserFollowing)\
311 f = self.sa.query(UserFollowing)\
314 .filter(UserFollowing.follows_repo_id == follow_repo_id)\
312 .filter(UserFollowing.follows_repo_id == follow_repo_id)\
315 .filter(UserFollowing.user_id == user_id).scalar()
313 .filter(UserFollowing.user_id == user_id).scalar()
316
314
317 if f is not None:
315 if f is not None:
318 try:
316 try:
319 self.sa.delete(f)
317 self.sa.delete(f)
320 action_logger(UserTemp(user_id),
318 action_logger(UserTemp(user_id),
321 'stopped_following_repo',
319 'stopped_following_repo',
322 RepoTemp(follow_repo_id))
320 RepoTemp(follow_repo_id))
323 return
321 return
324 except:
322 except:
325 log.error(traceback.format_exc())
323 log.error(traceback.format_exc())
326 raise
324 raise
327
325
328 try:
326 try:
329 f = UserFollowing()
327 f = UserFollowing()
330 f.user_id = user_id
328 f.user_id = user_id
331 f.follows_repo_id = follow_repo_id
329 f.follows_repo_id = follow_repo_id
332 self.sa.add(f)
330 self.sa.add(f)
333
331
334 action_logger(UserTemp(user_id),
332 action_logger(UserTemp(user_id),
335 'started_following_repo',
333 'started_following_repo',
336 RepoTemp(follow_repo_id))
334 RepoTemp(follow_repo_id))
337 except:
335 except:
338 log.error(traceback.format_exc())
336 log.error(traceback.format_exc())
339 raise
337 raise
340
338
341 def toggle_following_user(self, follow_user_id, user_id):
339 def toggle_following_user(self, follow_user_id, user_id):
342 f = self.sa.query(UserFollowing)\
340 f = self.sa.query(UserFollowing)\
343 .filter(UserFollowing.follows_user_id == follow_user_id)\
341 .filter(UserFollowing.follows_user_id == follow_user_id)\
344 .filter(UserFollowing.user_id == user_id).scalar()
342 .filter(UserFollowing.user_id == user_id).scalar()
345
343
346 if f is not None:
344 if f is not None:
347 try:
345 try:
348 self.sa.delete(f)
346 self.sa.delete(f)
349 return
347 return
350 except:
348 except:
351 log.error(traceback.format_exc())
349 log.error(traceback.format_exc())
352 raise
350 raise
353
351
354 try:
352 try:
355 f = UserFollowing()
353 f = UserFollowing()
356 f.user_id = user_id
354 f.user_id = user_id
357 f.follows_user_id = follow_user_id
355 f.follows_user_id = follow_user_id
358 self.sa.add(f)
356 self.sa.add(f)
359 except:
357 except:
360 log.error(traceback.format_exc())
358 log.error(traceback.format_exc())
361 raise
359 raise
362
360
363 def is_following_repo(self, repo_name, user_id, cache=False):
361 def is_following_repo(self, repo_name, user_id, cache=False):
364 r = self.sa.query(Repository)\
362 r = self.sa.query(Repository)\
365 .filter(Repository.repo_name == repo_name).scalar()
363 .filter(Repository.repo_name == repo_name).scalar()
366
364
367 f = self.sa.query(UserFollowing)\
365 f = self.sa.query(UserFollowing)\
368 .filter(UserFollowing.follows_repository == r)\
366 .filter(UserFollowing.follows_repository == r)\
369 .filter(UserFollowing.user_id == user_id).scalar()
367 .filter(UserFollowing.user_id == user_id).scalar()
370
368
371 return f is not None
369 return f is not None
372
370
373 def is_following_user(self, username, user_id, cache=False):
371 def is_following_user(self, username, user_id, cache=False):
374 u = User.get_by_username(username)
372 u = User.get_by_username(username)
375
373
376 f = self.sa.query(UserFollowing)\
374 f = self.sa.query(UserFollowing)\
377 .filter(UserFollowing.follows_user == u)\
375 .filter(UserFollowing.follows_user == u)\
378 .filter(UserFollowing.user_id == user_id).scalar()
376 .filter(UserFollowing.user_id == user_id).scalar()
379
377
380 return f is not None
378 return f is not None
381
379
382 def get_followers(self, repo):
380 def get_followers(self, repo):
383 repo = self._get_repo(repo)
381 repo = self._get_repo(repo)
384
382
385 return self.sa.query(UserFollowing)\
383 return self.sa.query(UserFollowing)\
386 .filter(UserFollowing.follows_repository == repo).count()
384 .filter(UserFollowing.follows_repository == repo).count()
387
385
388 def get_forks(self, repo):
386 def get_forks(self, repo):
389 repo = self._get_repo(repo)
387 repo = self._get_repo(repo)
390 return self.sa.query(Repository)\
388 return self.sa.query(Repository)\
391 .filter(Repository.fork == repo).count()
389 .filter(Repository.fork == repo).count()
392
390
393 def get_pull_requests(self, repo):
391 def get_pull_requests(self, repo):
394 repo = self._get_repo(repo)
392 repo = self._get_repo(repo)
395 return self.sa.query(PullRequest)\
393 return self.sa.query(PullRequest)\
396 .filter(PullRequest.other_repo == repo).count()
394 .filter(PullRequest.other_repo == repo).count()
397
395
398 def mark_as_fork(self, repo, fork, user):
396 def mark_as_fork(self, repo, fork, user):
399 repo = self.__get_repo(repo)
397 repo = self.__get_repo(repo)
400 fork = self.__get_repo(fork)
398 fork = self.__get_repo(fork)
401 if fork and repo.repo_id == fork.repo_id:
399 if fork and repo.repo_id == fork.repo_id:
402 raise Exception("Cannot set repository as fork of itself")
400 raise Exception("Cannot set repository as fork of itself")
403 repo.fork = fork
401 repo.fork = fork
404 self.sa.add(repo)
402 self.sa.add(repo)
405 return repo
403 return repo
406
404
407 def pull_changes(self, repo, username):
405 def pull_changes(self, repo, username):
408 dbrepo = self.__get_repo(repo)
406 dbrepo = self.__get_repo(repo)
409 clone_uri = dbrepo.clone_uri
407 clone_uri = dbrepo.clone_uri
410 if not clone_uri:
408 if not clone_uri:
411 raise Exception("This repository doesn't have a clone uri")
409 raise Exception("This repository doesn't have a clone uri")
412
410
413 repo = dbrepo.scm_instance
411 repo = dbrepo.scm_instance
414 from rhodecode import CONFIG
412 from rhodecode import CONFIG
415 try:
413 try:
416 extras = {
414 extras = {
417 'ip': '',
415 'ip': '',
418 'username': username,
416 'username': username,
419 'action': 'push_remote',
417 'action': 'push_remote',
420 'repository': dbrepo.repo_name,
418 'repository': dbrepo.repo_name,
421 'scm': repo.alias,
419 'scm': repo.alias,
422 'config': CONFIG['__file__'],
420 'config': CONFIG['__file__'],
423 'make_lock': None,
421 'make_lock': None,
424 'locked_by': [None, None]
422 'locked_by': [None, None]
425 }
423 }
426
424
427 Repository.inject_ui(repo, extras=extras)
425 Repository.inject_ui(repo, extras=extras)
428
426
429 if repo.alias == 'git':
427 if repo.alias == 'git':
430 repo.fetch(clone_uri)
428 repo.fetch(clone_uri)
431 else:
429 else:
432 repo.pull(clone_uri)
430 repo.pull(clone_uri)
433 self.mark_for_invalidation(dbrepo.repo_name)
431 self.mark_for_invalidation(dbrepo.repo_name)
434 except:
432 except:
435 log.error(traceback.format_exc())
433 log.error(traceback.format_exc())
436 raise
434 raise
437
435
438 def commit_change(self, repo, repo_name, cs, user, author, message,
436 def commit_change(self, repo, repo_name, cs, user, author, message,
439 content, f_path):
437 content, f_path):
440 """
438 """
441 Commits changes
439 Commits changes
442
440
443 :param repo: SCM instance
441 :param repo: SCM instance
444
442
445 """
443 """
446
444
447 if repo.alias == 'hg':
445 if repo.alias == 'hg':
448 from rhodecode.lib.vcs.backends.hg import \
446 from rhodecode.lib.vcs.backends.hg import \
449 MercurialInMemoryChangeset as IMC
447 MercurialInMemoryChangeset as IMC
450 elif repo.alias == 'git':
448 elif repo.alias == 'git':
451 from rhodecode.lib.vcs.backends.git import \
449 from rhodecode.lib.vcs.backends.git import \
452 GitInMemoryChangeset as IMC
450 GitInMemoryChangeset as IMC
453
451
454 # decoding here will force that we have proper encoded values
452 # decoding here will force that we have proper encoded values
455 # in any other case this will throw exceptions and deny commit
453 # in any other case this will throw exceptions and deny commit
456 content = safe_str(content)
454 content = safe_str(content)
457 path = safe_str(f_path)
455 path = safe_str(f_path)
458 # message and author needs to be unicode
456 # message and author needs to be unicode
459 # proper backend should then translate that into required type
457 # proper backend should then translate that into required type
460 message = safe_unicode(message)
458 message = safe_unicode(message)
461 author = safe_unicode(author)
459 author = safe_unicode(author)
462 m = IMC(repo)
460 m = IMC(repo)
463 m.change(FileNode(path, content))
461 m.change(FileNode(path, content))
464 tip = m.commit(message=message,
462 tip = m.commit(message=message,
465 author=author,
463 author=author,
466 parents=[cs], branch=cs.branch)
464 parents=[cs], branch=cs.branch)
467
465
468 action = 'push_local:%s' % tip.raw_id
466 action = 'push_local:%s' % tip.raw_id
469 action_logger(user, action, repo_name)
467 action_logger(user, action, repo_name)
470 self.mark_for_invalidation(repo_name)
468 self.mark_for_invalidation(repo_name)
471 return tip
469 return tip
472
470
473 def create_node(self, repo, repo_name, cs, user, author, message, content,
471 def create_node(self, repo, repo_name, cs, user, author, message, content,
474 f_path):
472 f_path):
475 if repo.alias == 'hg':
473 if repo.alias == 'hg':
476 from rhodecode.lib.vcs.backends.hg import MercurialInMemoryChangeset as IMC
474 from rhodecode.lib.vcs.backends.hg import MercurialInMemoryChangeset as IMC
477 elif repo.alias == 'git':
475 elif repo.alias == 'git':
478 from rhodecode.lib.vcs.backends.git import GitInMemoryChangeset as IMC
476 from rhodecode.lib.vcs.backends.git import GitInMemoryChangeset as IMC
479 # decoding here will force that we have proper encoded values
477 # decoding here will force that we have proper encoded values
480 # in any other case this will throw exceptions and deny commit
478 # in any other case this will throw exceptions and deny commit
481
479
482 if isinstance(content, (basestring,)):
480 if isinstance(content, (basestring,)):
483 content = safe_str(content)
481 content = safe_str(content)
484 elif isinstance(content, (file, cStringIO.OutputType,)):
482 elif isinstance(content, (file, cStringIO.OutputType,)):
485 content = content.read()
483 content = content.read()
486 else:
484 else:
487 raise Exception('Content is of unrecognized type %s' % (
485 raise Exception('Content is of unrecognized type %s' % (
488 type(content)
486 type(content)
489 ))
487 ))
490
488
491 message = safe_unicode(message)
489 message = safe_unicode(message)
492 author = safe_unicode(author)
490 author = safe_unicode(author)
493 path = safe_str(f_path)
491 path = safe_str(f_path)
494 m = IMC(repo)
492 m = IMC(repo)
495
493
496 if isinstance(cs, EmptyChangeset):
494 if isinstance(cs, EmptyChangeset):
497 # EmptyChangeset means we we're editing empty repository
495 # EmptyChangeset means we we're editing empty repository
498 parents = None
496 parents = None
499 else:
497 else:
500 parents = [cs]
498 parents = [cs]
501
499
502 m.add(FileNode(path, content=content))
500 m.add(FileNode(path, content=content))
503 tip = m.commit(message=message,
501 tip = m.commit(message=message,
504 author=author,
502 author=author,
505 parents=parents, branch=cs.branch)
503 parents=parents, branch=cs.branch)
506
504
507 action = 'push_local:%s' % tip.raw_id
505 action = 'push_local:%s' % tip.raw_id
508 action_logger(user, action, repo_name)
506 action_logger(user, action, repo_name)
509 self.mark_for_invalidation(repo_name)
507 self.mark_for_invalidation(repo_name)
510 return tip
508 return tip
511
509
512 def get_nodes(self, repo_name, revision, root_path='/', flat=True):
510 def get_nodes(self, repo_name, revision, root_path='/', flat=True):
513 """
511 """
514 recursive walk in root dir and return a set of all path in that dir
512 recursive walk in root dir and return a set of all path in that dir
515 based on repository walk function
513 based on repository walk function
516
514
517 :param repo_name: name of repository
515 :param repo_name: name of repository
518 :param revision: revision for which to list nodes
516 :param revision: revision for which to list nodes
519 :param root_path: root path to list
517 :param root_path: root path to list
520 :param flat: return as a list, if False returns a dict with decription
518 :param flat: return as a list, if False returns a dict with decription
521
519
522 """
520 """
523 _files = list()
521 _files = list()
524 _dirs = list()
522 _dirs = list()
525 try:
523 try:
526 _repo = self.__get_repo(repo_name)
524 _repo = self.__get_repo(repo_name)
527 changeset = _repo.scm_instance.get_changeset(revision)
525 changeset = _repo.scm_instance.get_changeset(revision)
528 root_path = root_path.lstrip('/')
526 root_path = root_path.lstrip('/')
529 for topnode, dirs, files in changeset.walk(root_path):
527 for topnode, dirs, files in changeset.walk(root_path):
530 for f in files:
528 for f in files:
531 _files.append(f.path if flat else {"name": f.path,
529 _files.append(f.path if flat else {"name": f.path,
532 "type": "file"})
530 "type": "file"})
533 for d in dirs:
531 for d in dirs:
534 _dirs.append(d.path if flat else {"name": d.path,
532 _dirs.append(d.path if flat else {"name": d.path,
535 "type": "dir"})
533 "type": "dir"})
536 except RepositoryError:
534 except RepositoryError:
537 log.debug(traceback.format_exc())
535 log.debug(traceback.format_exc())
538 raise
536 raise
539
537
540 return _dirs, _files
538 return _dirs, _files
541
539
542 def get_unread_journal(self):
540 def get_unread_journal(self):
543 return self.sa.query(UserLog).count()
541 return self.sa.query(UserLog).count()
544
542
545 def get_repo_landing_revs(self, repo=None):
543 def get_repo_landing_revs(self, repo=None):
546 """
544 """
547 Generates select option with tags branches and bookmarks (for hg only)
545 Generates select option with tags branches and bookmarks (for hg only)
548 grouped by type
546 grouped by type
549
547
550 :param repo:
548 :param repo:
551 :type repo:
549 :type repo:
552 """
550 """
553
551
554 hist_l = []
552 hist_l = []
555 choices = []
553 choices = []
556 repo = self.__get_repo(repo)
554 repo = self.__get_repo(repo)
557 hist_l.append(['tip', _('latest tip')])
555 hist_l.append(['tip', _('latest tip')])
558 choices.append('tip')
556 choices.append('tip')
559 if not repo:
557 if not repo:
560 return choices, hist_l
558 return choices, hist_l
561
559
562 repo = repo.scm_instance
560 repo = repo.scm_instance
563
561
564 branches_group = ([(k, k) for k, v in
562 branches_group = ([(k, k) for k, v in
565 repo.branches.iteritems()], _("Branches"))
563 repo.branches.iteritems()], _("Branches"))
566 hist_l.append(branches_group)
564 hist_l.append(branches_group)
567 choices.extend([x[0] for x in branches_group[0]])
565 choices.extend([x[0] for x in branches_group[0]])
568
566
569 if repo.alias == 'hg':
567 if repo.alias == 'hg':
570 bookmarks_group = ([(k, k) for k, v in
568 bookmarks_group = ([(k, k) for k, v in
571 repo.bookmarks.iteritems()], _("Bookmarks"))
569 repo.bookmarks.iteritems()], _("Bookmarks"))
572 hist_l.append(bookmarks_group)
570 hist_l.append(bookmarks_group)
573 choices.extend([x[0] for x in bookmarks_group[0]])
571 choices.extend([x[0] for x in bookmarks_group[0]])
574
572
575 tags_group = ([(k, k) for k, v in
573 tags_group = ([(k, k) for k, v in
576 repo.tags.iteritems()], _("Tags"))
574 repo.tags.iteritems()], _("Tags"))
577 hist_l.append(tags_group)
575 hist_l.append(tags_group)
578 choices.extend([x[0] for x in tags_group[0]])
576 choices.extend([x[0] for x in tags_group[0]])
579
577
580 return choices, hist_l
578 return choices, hist_l
581
579
582 def install_git_hook(self, repo, force_create=False):
580 def install_git_hook(self, repo, force_create=False):
583 """
581 """
584 Creates a rhodecode hook inside a git repository
582 Creates a rhodecode hook inside a git repository
585
583
586 :param repo: Instance of VCS repo
584 :param repo: Instance of VCS repo
587 :param force_create: Create even if same name hook exists
585 :param force_create: Create even if same name hook exists
588 """
586 """
589
587
590 loc = jn(repo.path, 'hooks')
588 loc = jn(repo.path, 'hooks')
591 if not repo.bare:
589 if not repo.bare:
592 loc = jn(repo.path, '.git', 'hooks')
590 loc = jn(repo.path, '.git', 'hooks')
593 if not os.path.isdir(loc):
591 if not os.path.isdir(loc):
594 os.makedirs(loc)
592 os.makedirs(loc)
595
593
596 tmpl_post = pkg_resources.resource_string(
594 tmpl_post = pkg_resources.resource_string(
597 'rhodecode', jn('config', 'post_receive_tmpl.py')
595 'rhodecode', jn('config', 'post_receive_tmpl.py')
598 )
596 )
599 tmpl_pre = pkg_resources.resource_string(
597 tmpl_pre = pkg_resources.resource_string(
600 'rhodecode', jn('config', 'pre_receive_tmpl.py')
598 'rhodecode', jn('config', 'pre_receive_tmpl.py')
601 )
599 )
602
600
603 for h_type, tmpl in [('pre', tmpl_pre), ('post', tmpl_post)]:
601 for h_type, tmpl in [('pre', tmpl_pre), ('post', tmpl_post)]:
604 _hook_file = jn(loc, '%s-receive' % h_type)
602 _hook_file = jn(loc, '%s-receive' % h_type)
605 _rhodecode_hook = False
603 _rhodecode_hook = False
606 log.debug('Installing git hook in repo %s' % repo)
604 log.debug('Installing git hook in repo %s' % repo)
607 if os.path.exists(_hook_file):
605 if os.path.exists(_hook_file):
608 # let's take a look at this hook, maybe it's rhodecode ?
606 # let's take a look at this hook, maybe it's rhodecode ?
609 log.debug('hook exists, checking if it is from rhodecode')
607 log.debug('hook exists, checking if it is from rhodecode')
610 _HOOK_VER_PAT = re.compile(r'^RC_HOOK_VER')
608 _HOOK_VER_PAT = re.compile(r'^RC_HOOK_VER')
611 with open(_hook_file, 'rb') as f:
609 with open(_hook_file, 'rb') as f:
612 data = f.read()
610 data = f.read()
613 matches = re.compile(r'(?:%s)\s*=\s*(.*)'
611 matches = re.compile(r'(?:%s)\s*=\s*(.*)'
614 % 'RC_HOOK_VER').search(data)
612 % 'RC_HOOK_VER').search(data)
615 if matches:
613 if matches:
616 try:
614 try:
617 ver = matches.groups()[0]
615 ver = matches.groups()[0]
618 log.debug('got %s it is rhodecode' % (ver))
616 log.debug('got %s it is rhodecode' % (ver))
619 _rhodecode_hook = True
617 _rhodecode_hook = True
620 except:
618 except:
621 log.error(traceback.format_exc())
619 log.error(traceback.format_exc())
622 else:
620 else:
623 # there is no hook in this dir, so we want to create one
621 # there is no hook in this dir, so we want to create one
624 _rhodecode_hook = True
622 _rhodecode_hook = True
625
623
626 if _rhodecode_hook or force_create:
624 if _rhodecode_hook or force_create:
627 log.debug('writing %s hook file !' % h_type)
625 log.debug('writing %s hook file !' % h_type)
628 with open(_hook_file, 'wb') as f:
626 with open(_hook_file, 'wb') as f:
629 tmpl = tmpl.replace('_TMPL_', rhodecode.__version__)
627 tmpl = tmpl.replace('_TMPL_', rhodecode.__version__)
630 f.write(tmpl)
628 f.write(tmpl)
631 os.chmod(_hook_file, 0755)
629 os.chmod(_hook_file, 0755)
632 else:
630 else:
633 log.debug('skipping writing hook file')
631 log.debug('skipping writing hook file')
General Comments 0
You need to be logged in to leave comments. Login now