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