##// END OF EJS Templates
Cleanup code
marcink -
r3952:ebde99f1 beta
parent child Browse files
Show More
@@ -1,750 +1,752 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 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, get_server_url,\
47 from rhodecode.lib.utils2 import safe_str, safe_unicode, get_server_url,\
48 _set_extras
48 _set_extras
49 from rhodecode.lib.auth import HasRepoPermissionAny, HasReposGroupPermissionAny,\
49 from rhodecode.lib.auth import HasRepoPermissionAny, HasReposGroupPermissionAny,\
50 HasUserGroupPermissionAnyDecorator, HasUserGroupPermissionAny
50 HasUserGroupPermissionAny
51 from rhodecode.lib.utils import get_filesystem_repos, make_ui, \
51 from rhodecode.lib.utils import get_filesystem_repos, make_ui, \
52 action_logger, REMOVED_REPO_PAT
52 action_logger
53 from rhodecode.model import BaseModel
53 from rhodecode.model import BaseModel
54 from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
54 from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
55 UserFollowing, UserLog, User, RepoGroup, PullRequest
55 UserFollowing, UserLog, User, RepoGroup, PullRequest
56 from rhodecode.lib.hooks import log_push_action
56 from rhodecode.lib.hooks import log_push_action
57 from rhodecode.lib.exceptions import NonRelativePathError
57 from rhodecode.lib.exceptions import NonRelativePathError
58
58
59 log = logging.getLogger(__name__)
59 log = logging.getLogger(__name__)
60
60
61
61
62 class UserTemp(object):
62 class UserTemp(object):
63 def __init__(self, user_id):
63 def __init__(self, user_id):
64 self.user_id = user_id
64 self.user_id = user_id
65
65
66 def __repr__(self):
66 def __repr__(self):
67 return "<%s('id:%s')>" % (self.__class__.__name__, self.user_id)
67 return "<%s('id:%s')>" % (self.__class__.__name__, self.user_id)
68
68
69
69
70 class RepoTemp(object):
70 class RepoTemp(object):
71 def __init__(self, repo_id):
71 def __init__(self, repo_id):
72 self.repo_id = repo_id
72 self.repo_id = repo_id
73
73
74 def __repr__(self):
74 def __repr__(self):
75 return "<%s('id:%s')>" % (self.__class__.__name__, self.repo_id)
75 return "<%s('id:%s')>" % (self.__class__.__name__, self.repo_id)
76
76
77
77
78 class CachedRepoList(object):
78 class CachedRepoList(object):
79 """
79 """
80 Cached repo list, uses in-memory cache after initialization, that is
80 Cached repo list, uses in-memory cache after initialization, that is
81 super fast
81 super fast
82 """
82 """
83
83
84 def __init__(self, db_repo_list, repos_path, order_by=None, perm_set=None):
84 def __init__(self, db_repo_list, repos_path, order_by=None, perm_set=None):
85 self.db_repo_list = db_repo_list
85 self.db_repo_list = db_repo_list
86 self.repos_path = repos_path
86 self.repos_path = repos_path
87 self.order_by = order_by
87 self.order_by = order_by
88 self.reversed = (order_by or '').startswith('-')
88 self.reversed = (order_by or '').startswith('-')
89 if not perm_set:
89 if not perm_set:
90 perm_set = ['repository.read', 'repository.write',
90 perm_set = ['repository.read', 'repository.write',
91 'repository.admin']
91 'repository.admin']
92 self.perm_set = perm_set
92 self.perm_set = perm_set
93
93
94 def __len__(self):
94 def __len__(self):
95 return len(self.db_repo_list)
95 return len(self.db_repo_list)
96
96
97 def __repr__(self):
97 def __repr__(self):
98 return '<%s (%s)>' % (self.__class__.__name__, self.__len__())
98 return '<%s (%s)>' % (self.__class__.__name__, self.__len__())
99
99
100 def __iter__(self):
100 def __iter__(self):
101 # pre-propagated valid_cache_keys to save executing select statements
101 # pre-propagated valid_cache_keys to save executing select statements
102 # for each repo
102 # for each repo
103 valid_cache_keys = CacheInvalidation.get_valid_cache_keys()
103 valid_cache_keys = CacheInvalidation.get_valid_cache_keys()
104
104
105 for dbr in self.db_repo_list:
105 for dbr in self.db_repo_list:
106 scmr = dbr.scm_instance_cached(valid_cache_keys)
106 scmr = dbr.scm_instance_cached(valid_cache_keys)
107 # check permission at this level
107 # check permission at this level
108 if not HasRepoPermissionAny(
108 if not HasRepoPermissionAny(
109 *self.perm_set)(dbr.repo_name, 'get repo check'):
109 *self.perm_set)(dbr.repo_name, 'get repo check'):
110 continue
110 continue
111
111
112 try:
112 try:
113 last_change = scmr.last_change
113 last_change = scmr.last_change
114 tip = h.get_changeset_safe(scmr, 'tip')
114 tip = h.get_changeset_safe(scmr, 'tip')
115 except Exception:
115 except Exception:
116 log.error(
116 log.error(
117 '%s this repository is present in database but it '
117 '%s this repository is present in database but it '
118 'cannot be created as an scm instance, org_exc:%s'
118 'cannot be created as an scm instance, org_exc:%s'
119 % (dbr.repo_name, traceback.format_exc())
119 % (dbr.repo_name, traceback.format_exc())
120 )
120 )
121 continue
121 continue
122
122
123 tmp_d = {}
123 tmp_d = {}
124 tmp_d['name'] = dbr.repo_name
124 tmp_d['name'] = dbr.repo_name
125 tmp_d['name_sort'] = tmp_d['name'].lower()
125 tmp_d['name_sort'] = tmp_d['name'].lower()
126 tmp_d['raw_name'] = tmp_d['name'].lower()
126 tmp_d['raw_name'] = tmp_d['name'].lower()
127 tmp_d['description'] = dbr.description
127 tmp_d['description'] = dbr.description
128 tmp_d['description_sort'] = tmp_d['description'].lower()
128 tmp_d['description_sort'] = tmp_d['description'].lower()
129 tmp_d['last_change'] = last_change
129 tmp_d['last_change'] = last_change
130 tmp_d['last_change_sort'] = time.mktime(last_change.timetuple())
130 tmp_d['last_change_sort'] = time.mktime(last_change.timetuple())
131 tmp_d['tip'] = tip.raw_id
131 tmp_d['tip'] = tip.raw_id
132 tmp_d['tip_sort'] = tip.revision
132 tmp_d['tip_sort'] = tip.revision
133 tmp_d['rev'] = tip.revision
133 tmp_d['rev'] = tip.revision
134 tmp_d['contact'] = dbr.user.full_contact
134 tmp_d['contact'] = dbr.user.full_contact
135 tmp_d['contact_sort'] = tmp_d['contact']
135 tmp_d['contact_sort'] = tmp_d['contact']
136 tmp_d['owner_sort'] = tmp_d['contact']
136 tmp_d['owner_sort'] = tmp_d['contact']
137 tmp_d['repo_archives'] = list(scmr._get_archives())
137 tmp_d['repo_archives'] = list(scmr._get_archives())
138 tmp_d['last_msg'] = tip.message
138 tmp_d['last_msg'] = tip.message
139 tmp_d['author'] = tip.author
139 tmp_d['author'] = tip.author
140 tmp_d['dbrepo'] = dbr.get_dict()
140 tmp_d['dbrepo'] = dbr.get_dict()
141 tmp_d['dbrepo_fork'] = dbr.fork.get_dict() if dbr.fork else {}
141 tmp_d['dbrepo_fork'] = dbr.fork.get_dict() if dbr.fork else {}
142 yield tmp_d
142 yield tmp_d
143
143
144
144
145 class SimpleCachedRepoList(CachedRepoList):
145 class SimpleCachedRepoList(CachedRepoList):
146 """
146 """
147 Lighter version of CachedRepoList without the scm initialisation
147 Lighter version of CachedRepoList without the scm initialisation
148 """
148 """
149
149
150 def __iter__(self):
150 def __iter__(self):
151 for dbr in self.db_repo_list:
151 for dbr in self.db_repo_list:
152 # check permission at this level
152 # check permission at this level
153 if not HasRepoPermissionAny(
153 if not HasRepoPermissionAny(
154 *self.perm_set)(dbr.repo_name, 'get repo check'):
154 *self.perm_set)(dbr.repo_name, 'get repo check'):
155 continue
155 continue
156
156
157 tmp_d = {}
157 tmp_d = {}
158 tmp_d['name'] = dbr.repo_name
158 tmp_d['name'] = dbr.repo_name
159 tmp_d['name_sort'] = tmp_d['name'].lower()
159 tmp_d['name_sort'] = tmp_d['name'].lower()
160 tmp_d['raw_name'] = tmp_d['name'].lower()
160 tmp_d['raw_name'] = tmp_d['name'].lower()
161 tmp_d['description'] = dbr.description
161 tmp_d['description'] = dbr.description
162 tmp_d['description_sort'] = tmp_d['description'].lower()
162 tmp_d['description_sort'] = tmp_d['description'].lower()
163 tmp_d['dbrepo'] = dbr.get_dict()
163 tmp_d['dbrepo'] = dbr.get_dict()
164 tmp_d['dbrepo_fork'] = dbr.fork.get_dict() if dbr.fork else {}
164 tmp_d['dbrepo_fork'] = dbr.fork.get_dict() if dbr.fork else {}
165 yield tmp_d
165 yield tmp_d
166
166
167
167
168 class _PermCheckIterator(object):
168 class _PermCheckIterator(object):
169 def __init__(self, obj_list, obj_attr, perm_set, perm_checker):
169 def __init__(self, obj_list, obj_attr, perm_set, perm_checker):
170 """
170 """
171 Creates iterator from given list of objects, additionally
171 Creates iterator from given list of objects, additionally
172 checking permission for them from perm_set var
172 checking permission for them from perm_set var
173
173
174 :param obj_list: list of db objects
174 :param obj_list: list of db objects
175 :param obj_attr: attribute of object to pass into perm_checker
175 :param obj_attr: attribute of object to pass into perm_checker
176 :param perm_set: list of permissions to check
176 :param perm_set: list of permissions to check
177 :param perm_checker: callable to check permissions against
177 :param perm_checker: callable to check permissions against
178 """
178 """
179 self.obj_list = obj_list
179 self.obj_list = obj_list
180 self.obj_attr = obj_attr
180 self.obj_attr = obj_attr
181 self.perm_set = perm_set
181 self.perm_set = perm_set
182 self.perm_checker = perm_checker
182 self.perm_checker = perm_checker
183
183
184 def __len__(self):
184 def __len__(self):
185 return len(self.obj_list)
185 return len(self.obj_list)
186
186
187 def __repr__(self):
187 def __repr__(self):
188 return '<%s (%s)>' % (self.__class__.__name__, self.__len__())
188 return '<%s (%s)>' % (self.__class__.__name__, self.__len__())
189
189
190 def __iter__(self):
190 def __iter__(self):
191 for db_obj in self.obj_list:
191 for db_obj in self.obj_list:
192 # check permission at this level
192 # check permission at this level
193 name = getattr(db_obj, self.obj_attr, None)
193 name = getattr(db_obj, self.obj_attr, None)
194 if not self.perm_checker(*self.perm_set)(name, self.__class__.__name__):
194 if not self.perm_checker(*self.perm_set)(name, self.__class__.__name__):
195 continue
195 continue
196
196
197 yield db_obj
197 yield db_obj
198
198
199
199
200 class RepoList(_PermCheckIterator):
200 class RepoList(_PermCheckIterator):
201
201
202 def __init__(self, db_repo_list, perm_set=None):
202 def __init__(self, db_repo_list, perm_set=None):
203 if not perm_set:
203 if not perm_set:
204 perm_set = ['repository.read', 'repository.write', 'repository.admin']
204 perm_set = ['repository.read', 'repository.write', 'repository.admin']
205
205
206 super(RepoList, self).__init__(obj_list=db_repo_list,
206 super(RepoList, self).__init__(obj_list=db_repo_list,
207 obj_attr='repo_name', perm_set=perm_set,
207 obj_attr='repo_name', perm_set=perm_set,
208 perm_checker=HasRepoPermissionAny)
208 perm_checker=HasRepoPermissionAny)
209
209
210
210
211 class RepoGroupList(_PermCheckIterator):
211 class RepoGroupList(_PermCheckIterator):
212
212
213 def __init__(self, db_repo_group_list, perm_set=None):
213 def __init__(self, db_repo_group_list, perm_set=None):
214 if not perm_set:
214 if not perm_set:
215 perm_set = ['group.read', 'group.write', 'group.admin']
215 perm_set = ['group.read', 'group.write', 'group.admin']
216
216
217 super(RepoGroupList, self).__init__(obj_list=db_repo_group_list,
217 super(RepoGroupList, self).__init__(obj_list=db_repo_group_list,
218 obj_attr='group_name', perm_set=perm_set,
218 obj_attr='group_name', perm_set=perm_set,
219 perm_checker=HasReposGroupPermissionAny)
219 perm_checker=HasReposGroupPermissionAny)
220
220
221
221
222 class UserGroupList(_PermCheckIterator):
222 class UserGroupList(_PermCheckIterator):
223
223
224 def __init__(self, db_user_group_list, perm_set=None):
224 def __init__(self, db_user_group_list, perm_set=None):
225 if not perm_set:
225 if not perm_set:
226 perm_set = ['usergroup.read', 'usergroup.write', 'usergroup.admin']
226 perm_set = ['usergroup.read', 'usergroup.write', 'usergroup.admin']
227
227
228 super(UserGroupList, self).__init__(obj_list=db_user_group_list,
228 super(UserGroupList, self).__init__(obj_list=db_user_group_list,
229 obj_attr='users_group_name', perm_set=perm_set,
229 obj_attr='users_group_name', perm_set=perm_set,
230 perm_checker=HasUserGroupPermissionAny)
230 perm_checker=HasUserGroupPermissionAny)
231
231
232
232
233 class ScmModel(BaseModel):
233 class ScmModel(BaseModel):
234 """
234 """
235 Generic Scm Model
235 Generic Scm Model
236 """
236 """
237
237
238 def __get_repo(self, instance):
238 def __get_repo(self, instance):
239 cls = Repository
239 cls = Repository
240 if isinstance(instance, cls):
240 if isinstance(instance, cls):
241 return instance
241 return instance
242 elif isinstance(instance, int) or safe_str(instance).isdigit():
242 elif isinstance(instance, int) or safe_str(instance).isdigit():
243 return cls.get(instance)
243 return cls.get(instance)
244 elif isinstance(instance, basestring):
244 elif isinstance(instance, basestring):
245 return cls.get_by_repo_name(instance)
245 return cls.get_by_repo_name(instance)
246 elif instance:
246 elif instance:
247 raise Exception('given object must be int, basestr or Instance'
247 raise Exception('given object must be int, basestr or Instance'
248 ' of %s got %s' % (type(cls), type(instance)))
248 ' of %s got %s' % (type(cls), type(instance)))
249
249
250 @LazyProperty
250 @LazyProperty
251 def repos_path(self):
251 def repos_path(self):
252 """
252 """
253 Get's the repositories root path from database
253 Get's the repositories root path from database
254 """
254 """
255
255
256 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
256 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
257
257
258 return q.ui_value
258 return q.ui_value
259
259
260 def repo_scan(self, repos_path=None):
260 def repo_scan(self, repos_path=None):
261 """
261 """
262 Listing of repositories in given path. This path should not be a
262 Listing of repositories in given path. This path should not be a
263 repository itself. Return a dictionary of repository objects
263 repository itself. Return a dictionary of repository objects
264
264
265 :param repos_path: path to directory containing repositories
265 :param repos_path: path to directory containing repositories
266 """
266 """
267
267
268 if repos_path is None:
268 if repos_path is None:
269 repos_path = self.repos_path
269 repos_path = self.repos_path
270
270
271 log.info('scanning for repositories in %s' % repos_path)
271 log.info('scanning for repositories in %s' % repos_path)
272
272
273 baseui = make_ui('db')
273 baseui = make_ui('db')
274 repos = {}
274 repos = {}
275
275
276 for name, path in get_filesystem_repos(repos_path, recursive=True):
276 for name, path in get_filesystem_repos(repos_path, recursive=True):
277 # name need to be decomposed and put back together using the /
277 # name need to be decomposed and put back together using the /
278 # since this is internal storage separator for rhodecode
278 # since this is internal storage separator for rhodecode
279 name = Repository.normalize_repo_name(name)
279 name = Repository.normalize_repo_name(name)
280
280
281 try:
281 try:
282 if name in repos:
282 if name in repos:
283 raise RepositoryError('Duplicate repository name %s '
283 raise RepositoryError('Duplicate repository name %s '
284 'found in %s' % (name, path))
284 'found in %s' % (name, path))
285 else:
285 else:
286
286
287 klass = get_backend(path[0])
287 klass = get_backend(path[0])
288
288
289 if path[0] == 'hg' and path[0] in BACKENDS.keys():
289 if path[0] == 'hg' and path[0] in BACKENDS.keys():
290 repos[name] = klass(safe_str(path[1]), baseui=baseui)
290 repos[name] = klass(safe_str(path[1]), baseui=baseui)
291
291
292 if path[0] == 'git' and path[0] in BACKENDS.keys():
292 if path[0] == 'git' and path[0] in BACKENDS.keys():
293 repos[name] = klass(path[1])
293 repos[name] = klass(path[1])
294 except OSError:
294 except OSError:
295 continue
295 continue
296 log.debug('found %s paths with repositories' % (len(repos)))
296 log.debug('found %s paths with repositories' % (len(repos)))
297 return repos
297 return repos
298
298
299 def get_repos(self, all_repos=None, sort_key=None, simple=False):
299 def get_repos(self, all_repos=None, sort_key=None, simple=False):
300 """
300 """
301 Get all repos from db and for each repo create it's
301 Get all repos from db and for each repo create it's
302 backend instance and fill that backed with information from database
302 backend instance and fill that backed with information from database
303
303
304 :param all_repos: list of repository names as strings
304 :param all_repos: list of repository names as strings
305 give specific repositories list, good for filtering
305 give specific repositories list, good for filtering
306
306
307 :param sort_key: initial sorting of repos
307 :param sort_key: initial sorting of repos
308 :param simple: use SimpleCachedList - one without the SCM info
308 :param simple: use SimpleCachedList - one without the SCM info
309 """
309 """
310 if all_repos is None:
310 if all_repos is None:
311 all_repos = self.sa.query(Repository)\
311 all_repos = self.sa.query(Repository)\
312 .filter(Repository.group_id == None)\
312 .filter(Repository.group_id == None)\
313 .order_by(func.lower(Repository.repo_name)).all()
313 .order_by(func.lower(Repository.repo_name)).all()
314 if simple:
314 if simple:
315 repo_iter = SimpleCachedRepoList(all_repos,
315 repo_iter = SimpleCachedRepoList(all_repos,
316 repos_path=self.repos_path,
316 repos_path=self.repos_path,
317 order_by=sort_key)
317 order_by=sort_key)
318 else:
318 else:
319 repo_iter = CachedRepoList(all_repos,
319 repo_iter = CachedRepoList(all_repos,
320 repos_path=self.repos_path,
320 repos_path=self.repos_path,
321 order_by=sort_key)
321 order_by=sort_key)
322
322
323 return repo_iter
323 return repo_iter
324
324
325 def get_repos_groups(self, all_groups=None):
325 def get_repos_groups(self, all_groups=None):
326 if all_groups is None:
326 if all_groups is None:
327 all_groups = RepoGroup.query()\
327 all_groups = RepoGroup.query()\
328 .filter(RepoGroup.group_parent_id == None).all()
328 .filter(RepoGroup.group_parent_id == None).all()
329 return [x for x in RepoGroupList(all_groups)]
329 return [x for x in RepoGroupList(all_groups)]
330
330
331 def mark_for_invalidation(self, repo_name):
331 def mark_for_invalidation(self, repo_name):
332 """
332 """
333 Mark caches of this repo invalid in the database.
333 Mark caches of this repo invalid in the database.
334
334
335 :param repo_name: the repo for which caches should be marked invalid
335 :param repo_name: the repo for which caches should be marked invalid
336 """
336 """
337 CacheInvalidation.set_invalidate(repo_name)
337 CacheInvalidation.set_invalidate(repo_name)
338 repo = Repository.get_by_repo_name(repo_name)
338 repo = Repository.get_by_repo_name(repo_name)
339 if repo:
339 if repo:
340 repo.update_changeset_cache()
340 repo.update_changeset_cache()
341
341
342 def toggle_following_repo(self, follow_repo_id, user_id):
342 def toggle_following_repo(self, follow_repo_id, user_id):
343
343
344 f = self.sa.query(UserFollowing)\
344 f = self.sa.query(UserFollowing)\
345 .filter(UserFollowing.follows_repo_id == follow_repo_id)\
345 .filter(UserFollowing.follows_repo_id == follow_repo_id)\
346 .filter(UserFollowing.user_id == user_id).scalar()
346 .filter(UserFollowing.user_id == user_id).scalar()
347
347
348 if f is not None:
348 if f is not None:
349 try:
349 try:
350 self.sa.delete(f)
350 self.sa.delete(f)
351 action_logger(UserTemp(user_id),
351 action_logger(UserTemp(user_id),
352 'stopped_following_repo',
352 'stopped_following_repo',
353 RepoTemp(follow_repo_id))
353 RepoTemp(follow_repo_id))
354 return
354 return
355 except Exception:
355 except Exception:
356 log.error(traceback.format_exc())
356 log.error(traceback.format_exc())
357 raise
357 raise
358
358
359 try:
359 try:
360 f = UserFollowing()
360 f = UserFollowing()
361 f.user_id = user_id
361 f.user_id = user_id
362 f.follows_repo_id = follow_repo_id
362 f.follows_repo_id = follow_repo_id
363 self.sa.add(f)
363 self.sa.add(f)
364
364
365 action_logger(UserTemp(user_id),
365 action_logger(UserTemp(user_id),
366 'started_following_repo',
366 'started_following_repo',
367 RepoTemp(follow_repo_id))
367 RepoTemp(follow_repo_id))
368 except Exception:
368 except Exception:
369 log.error(traceback.format_exc())
369 log.error(traceback.format_exc())
370 raise
370 raise
371
371
372 def toggle_following_user(self, follow_user_id, user_id):
372 def toggle_following_user(self, follow_user_id, user_id):
373 f = self.sa.query(UserFollowing)\
373 f = self.sa.query(UserFollowing)\
374 .filter(UserFollowing.follows_user_id == follow_user_id)\
374 .filter(UserFollowing.follows_user_id == follow_user_id)\
375 .filter(UserFollowing.user_id == user_id).scalar()
375 .filter(UserFollowing.user_id == user_id).scalar()
376
376
377 if f is not None:
377 if f is not None:
378 try:
378 try:
379 self.sa.delete(f)
379 self.sa.delete(f)
380 return
380 return
381 except Exception:
381 except Exception:
382 log.error(traceback.format_exc())
382 log.error(traceback.format_exc())
383 raise
383 raise
384
384
385 try:
385 try:
386 f = UserFollowing()
386 f = UserFollowing()
387 f.user_id = user_id
387 f.user_id = user_id
388 f.follows_user_id = follow_user_id
388 f.follows_user_id = follow_user_id
389 self.sa.add(f)
389 self.sa.add(f)
390 except Exception:
390 except Exception:
391 log.error(traceback.format_exc())
391 log.error(traceback.format_exc())
392 raise
392 raise
393
393
394 def is_following_repo(self, repo_name, user_id, cache=False):
394 def is_following_repo(self, repo_name, user_id, cache=False):
395 r = self.sa.query(Repository)\
395 r = self.sa.query(Repository)\
396 .filter(Repository.repo_name == repo_name).scalar()
396 .filter(Repository.repo_name == repo_name).scalar()
397
397
398 f = self.sa.query(UserFollowing)\
398 f = self.sa.query(UserFollowing)\
399 .filter(UserFollowing.follows_repository == r)\
399 .filter(UserFollowing.follows_repository == r)\
400 .filter(UserFollowing.user_id == user_id).scalar()
400 .filter(UserFollowing.user_id == user_id).scalar()
401
401
402 return f is not None
402 return f is not None
403
403
404 def is_following_user(self, username, user_id, cache=False):
404 def is_following_user(self, username, user_id, cache=False):
405 u = User.get_by_username(username)
405 u = User.get_by_username(username)
406
406
407 f = self.sa.query(UserFollowing)\
407 f = self.sa.query(UserFollowing)\
408 .filter(UserFollowing.follows_user == u)\
408 .filter(UserFollowing.follows_user == u)\
409 .filter(UserFollowing.user_id == user_id).scalar()
409 .filter(UserFollowing.user_id == user_id).scalar()
410
410
411 return f is not None
411 return f is not None
412
412
413 def get_followers(self, repo):
413 def get_followers(self, repo):
414 repo = self._get_repo(repo)
414 repo = self._get_repo(repo)
415
415
416 return self.sa.query(UserFollowing)\
416 return self.sa.query(UserFollowing)\
417 .filter(UserFollowing.follows_repository == repo).count()
417 .filter(UserFollowing.follows_repository == repo).count()
418
418
419 def get_forks(self, repo):
419 def get_forks(self, repo):
420 repo = self._get_repo(repo)
420 repo = self._get_repo(repo)
421 return self.sa.query(Repository)\
421 return self.sa.query(Repository)\
422 .filter(Repository.fork == repo).count()
422 .filter(Repository.fork == repo).count()
423
423
424 def get_pull_requests(self, repo):
424 def get_pull_requests(self, repo):
425 repo = self._get_repo(repo)
425 repo = self._get_repo(repo)
426 return self.sa.query(PullRequest)\
426 return self.sa.query(PullRequest)\
427 .filter(PullRequest.other_repo == repo)\
427 .filter(PullRequest.other_repo == repo)\
428 .filter(PullRequest.status != PullRequest.STATUS_CLOSED).count()
428 .filter(PullRequest.status != PullRequest.STATUS_CLOSED).count()
429
429
430 def mark_as_fork(self, repo, fork, user):
430 def mark_as_fork(self, repo, fork, user):
431 repo = self.__get_repo(repo)
431 repo = self.__get_repo(repo)
432 fork = self.__get_repo(fork)
432 fork = self.__get_repo(fork)
433 if fork and repo.repo_id == fork.repo_id:
433 if fork and repo.repo_id == fork.repo_id:
434 raise Exception("Cannot set repository as fork of itself")
434 raise Exception("Cannot set repository as fork of itself")
435 repo.fork = fork
435 repo.fork = fork
436 self.sa.add(repo)
436 self.sa.add(repo)
437 return repo
437 return repo
438
438
439 def _handle_rc_scm_extras(self, username, repo_name, repo_alias,
439 def _handle_rc_scm_extras(self, username, repo_name, repo_alias,
440 action=None):
440 action=None):
441 from rhodecode import CONFIG
441 from rhodecode import CONFIG
442 from rhodecode.lib.base import _get_ip_addr
442 from rhodecode.lib.base import _get_ip_addr
443 try:
443 try:
444 from pylons import request
444 from pylons import request
445 environ = request.environ
445 environ = request.environ
446 except TypeError:
446 except TypeError:
447 # we might use this outside of request context, let's fake the
447 # we might use this outside of request context, let's fake the
448 # environ data
448 # environ data
449 from webob import Request
449 from webob import Request
450 environ = Request.blank('').environ
450 environ = Request.blank('').environ
451 extras = {
451 extras = {
452 'ip': _get_ip_addr(environ),
452 'ip': _get_ip_addr(environ),
453 'username': username,
453 'username': username,
454 'action': action or 'push_local',
454 'action': action or 'push_local',
455 'repository': repo_name,
455 'repository': repo_name,
456 'scm': repo_alias,
456 'scm': repo_alias,
457 'config': CONFIG['__file__'],
457 'config': CONFIG['__file__'],
458 'server_url': get_server_url(environ),
458 'server_url': get_server_url(environ),
459 'make_lock': None,
459 'make_lock': None,
460 'locked_by': [None, None]
460 'locked_by': [None, None]
461 }
461 }
462 _set_extras(extras)
462 _set_extras(extras)
463
463
464 def _handle_push(self, repo, username, action, repo_name, revisions):
464 def _handle_push(self, repo, username, action, repo_name, revisions):
465 """
465 """
466 Triggers push action hooks
466 Triggers push action hooks
467
467
468 :param repo: SCM repo
468 :param repo: SCM repo
469 :param username: username who pushes
469 :param username: username who pushes
470 :param action: push/push_loca/push_remote
470 :param action: push/push_loca/push_remote
471 :param repo_name: name of repo
471 :param repo_name: name of repo
472 :param revisions: list of revisions that we pushed
472 :param revisions: list of revisions that we pushed
473 """
473 """
474 self._handle_rc_scm_extras(username, repo_name, repo_alias=repo.alias)
474 self._handle_rc_scm_extras(username, repo_name, repo_alias=repo.alias)
475 _scm_repo = repo._repo
475 _scm_repo = repo._repo
476 # trigger push hook
476 # trigger push hook
477 if repo.alias == 'hg':
477 if repo.alias == 'hg':
478 log_push_action(_scm_repo.ui, _scm_repo, node=revisions[0])
478 log_push_action(_scm_repo.ui, _scm_repo, node=revisions[0])
479 elif repo.alias == 'git':
479 elif repo.alias == 'git':
480 log_push_action(None, _scm_repo, _git_revs=revisions)
480 log_push_action(None, _scm_repo, _git_revs=revisions)
481
481
482 def _get_IMC_module(self, scm_type):
482 def _get_IMC_module(self, scm_type):
483 """
483 """
484 Returns InMemoryCommit class based on scm_type
484 Returns InMemoryCommit class based on scm_type
485
485
486 :param scm_type:
486 :param scm_type:
487 """
487 """
488 if scm_type == 'hg':
488 if scm_type == 'hg':
489 from rhodecode.lib.vcs.backends.hg import \
489 from rhodecode.lib.vcs.backends.hg import MercurialInMemoryChangeset
490 MercurialInMemoryChangeset as IMC
490 return MercurialInMemoryChangeset
491 elif scm_type == 'git':
491
492 from rhodecode.lib.vcs.backends.git import \
492 if scm_type == 'git':
493 GitInMemoryChangeset as IMC
493 from rhodecode.lib.vcs.backends.git import GitInMemoryChangeset
494 return IMC
494 return GitInMemoryChangeset
495
496 raise Exception('Invalid scm_type, must be one of hg,git got %s'
497 % (scm_type,))
495
498
496 def pull_changes(self, repo, username):
499 def pull_changes(self, repo, username):
497 dbrepo = self.__get_repo(repo)
500 dbrepo = self.__get_repo(repo)
498 clone_uri = dbrepo.clone_uri
501 clone_uri = dbrepo.clone_uri
499 if not clone_uri:
502 if not clone_uri:
500 raise Exception("This repository doesn't have a clone uri")
503 raise Exception("This repository doesn't have a clone uri")
501
504
502 repo = dbrepo.scm_instance
505 repo = dbrepo.scm_instance
503 repo_name = dbrepo.repo_name
506 repo_name = dbrepo.repo_name
504 try:
507 try:
505 if repo.alias == 'git':
508 if repo.alias == 'git':
506 repo.fetch(clone_uri)
509 repo.fetch(clone_uri)
507 # git doesn't really have something like post-fetch action
510 # git doesn't really have something like post-fetch action
508 # we fake that now. #TODO: extract fetched revisions somehow
511 # we fake that now. #TODO: extract fetched revisions somehow
509 # here
512 # here
510 self._handle_push(repo,
513 self._handle_push(repo,
511 username=username,
514 username=username,
512 action='push_remote',
515 action='push_remote',
513 repo_name=repo_name,
516 repo_name=repo_name,
514 revisions=[])
517 revisions=[])
515 else:
518 else:
516 self._handle_rc_scm_extras(username, dbrepo.repo_name,
519 self._handle_rc_scm_extras(username, dbrepo.repo_name,
517 repo.alias, action='push_remote')
520 repo.alias, action='push_remote')
518 repo.pull(clone_uri)
521 repo.pull(clone_uri)
519
522
520 self.mark_for_invalidation(repo_name)
523 self.mark_for_invalidation(repo_name)
521 except Exception:
524 except Exception:
522 log.error(traceback.format_exc())
525 log.error(traceback.format_exc())
523 raise
526 raise
524
527
525 def commit_change(self, repo, repo_name, cs, user, author, message,
528 def commit_change(self, repo, repo_name, cs, user, author, message,
526 content, f_path):
529 content, f_path):
527 """
530 """
528 Commits changes
531 Commits changes
529
532
530 :param repo: SCM instance
533 :param repo: SCM instance
531
534
532 """
535 """
533 user = self._get_user(user)
536 user = self._get_user(user)
534 IMC = self._get_IMC_module(repo.alias)
537 IMC = self._get_IMC_module(repo.alias)
535
538
536 # decoding here will force that we have proper encoded values
539 # decoding here will force that we have proper encoded values
537 # in any other case this will throw exceptions and deny commit
540 # in any other case this will throw exceptions and deny commit
538 content = safe_str(content)
541 content = safe_str(content)
539 path = safe_str(f_path)
542 path = safe_str(f_path)
540 # message and author needs to be unicode
543 # message and author needs to be unicode
541 # proper backend should then translate that into required type
544 # proper backend should then translate that into required type
542 message = safe_unicode(message)
545 message = safe_unicode(message)
543 author = safe_unicode(author)
546 author = safe_unicode(author)
544 imc = IMC(repo)
547 imc = IMC(repo)
545 imc.change(FileNode(path, content, mode=cs.get_file_mode(f_path)))
548 imc.change(FileNode(path, content, mode=cs.get_file_mode(f_path)))
546 tip = imc.commit(message=message,
549 tip = imc.commit(message=message,
547 author=author,
550 author=author,
548 parents=[cs], branch=cs.branch)
551 parents=[cs], branch=cs.branch)
549
552
550 self.mark_for_invalidation(repo_name)
553 self.mark_for_invalidation(repo_name)
551 self._handle_push(repo,
554 self._handle_push(repo,
552 username=user.username,
555 username=user.username,
553 action='push_local',
556 action='push_local',
554 repo_name=repo_name,
557 repo_name=repo_name,
555 revisions=[tip.raw_id])
558 revisions=[tip.raw_id])
556 return tip
559 return tip
557
560
558 def create_nodes(self, user, repo, message, nodes, parent_cs=None,
561 def create_nodes(self, user, repo, message, nodes, parent_cs=None,
559 author=None, trigger_push_hook=True):
562 author=None, trigger_push_hook=True):
560 """
563 """
561 Commits given multiple nodes into repo
564 Commits given multiple nodes into repo
562
565
563 :param user: RhodeCode User object or user_id, the commiter
566 :param user: RhodeCode User object or user_id, the commiter
564 :param repo: RhodeCode Repository object
567 :param repo: RhodeCode Repository object
565 :param message: commit message
568 :param message: commit message
566 :param nodes: mapping {filename:{'content':content},...}
569 :param nodes: mapping {filename:{'content':content},...}
567 :param parent_cs: parent changeset, can be empty than it's initial commit
570 :param parent_cs: parent changeset, can be empty than it's initial commit
568 :param author: author of commit, cna be different that commiter only for git
571 :param author: author of commit, cna be different that commiter only for git
569 :param trigger_push_hook: trigger push hooks
572 :param trigger_push_hook: trigger push hooks
570
573
571 :returns: new commited changeset
574 :returns: new commited changeset
572 """
575 """
573
576
574 user = self._get_user(user)
577 user = self._get_user(user)
575 scm_instance = repo.scm_instance_no_cache()
578 scm_instance = repo.scm_instance_no_cache()
576
579
577 processed_nodes = []
580 processed_nodes = []
578 for f_path in nodes:
581 for f_path in nodes:
579 if f_path.startswith('/') or f_path.startswith('.') or '../' in f_path:
582 if f_path.startswith('/') or f_path.startswith('.') or '../' in f_path:
580 raise NonRelativePathError('%s is not an relative path' % f_path)
583 raise NonRelativePathError('%s is not an relative path' % f_path)
581 if f_path:
584 if f_path:
582 f_path = os.path.normpath(f_path)
585 f_path = os.path.normpath(f_path)
583 content = nodes[f_path]['content']
586 content = nodes[f_path]['content']
584 f_path = safe_str(f_path)
587 f_path = safe_str(f_path)
585 # decoding here will force that we have proper encoded values
588 # decoding here will force that we have proper encoded values
586 # in any other case this will throw exceptions and deny commit
589 # in any other case this will throw exceptions and deny commit
587 if isinstance(content, (basestring,)):
590 if isinstance(content, (basestring,)):
588 content = safe_str(content)
591 content = safe_str(content)
589 elif isinstance(content, (file, cStringIO.OutputType,)):
592 elif isinstance(content, (file, cStringIO.OutputType,)):
590 content = content.read()
593 content = content.read()
591 else:
594 else:
592 raise Exception('Content is of unrecognized type %s' % (
595 raise Exception('Content is of unrecognized type %s' % (
593 type(content)
596 type(content)
594 ))
597 ))
595 processed_nodes.append((f_path, content))
598 processed_nodes.append((f_path, content))
596
599
597 message = safe_unicode(message)
600 message = safe_unicode(message)
598 commiter = user.full_contact
601 commiter = user.full_contact
599 author = safe_unicode(author) if author else commiter
602 author = safe_unicode(author) if author else commiter
600
603
601 IMC = self._get_IMC_module(scm_instance.alias)
604 IMC = self._get_IMC_module(scm_instance.alias)
602 imc = IMC(scm_instance)
605 imc = IMC(scm_instance)
603
606
604 if not parent_cs:
607 if not parent_cs:
605 parent_cs = EmptyChangeset(alias=scm_instance.alias)
608 parent_cs = EmptyChangeset(alias=scm_instance.alias)
606
609
607 if isinstance(parent_cs, EmptyChangeset):
610 if isinstance(parent_cs, EmptyChangeset):
608 # EmptyChangeset means we we're editing empty repository
611 # EmptyChangeset means we we're editing empty repository
609 parents = None
612 parents = None
610 else:
613 else:
611 parents = [parent_cs]
614 parents = [parent_cs]
612 # add multiple nodes
615 # add multiple nodes
613 for path, content in processed_nodes:
616 for path, content in processed_nodes:
614 imc.add(FileNode(path, content=content))
617 imc.add(FileNode(path, content=content))
615
618
616 tip = imc.commit(message=message,
619 tip = imc.commit(message=message,
617 author=author,
620 author=author,
618 parents=parents,
621 parents=parents,
619 branch=parent_cs.branch)
622 branch=parent_cs.branch)
620
623
621 self.mark_for_invalidation(repo.repo_name)
624 self.mark_for_invalidation(repo.repo_name)
622 if trigger_push_hook:
625 if trigger_push_hook:
623 self._handle_push(scm_instance,
626 self._handle_push(scm_instance,
624 username=user.username,
627 username=user.username,
625 action='push_local',
628 action='push_local',
626 repo_name=repo.repo_name,
629 repo_name=repo.repo_name,
627 revisions=[tip.raw_id])
630 revisions=[tip.raw_id])
628 return tip
631 return tip
629
632
630 def get_nodes(self, repo_name, revision, root_path='/', flat=True):
633 def get_nodes(self, repo_name, revision, root_path='/', flat=True):
631 """
634 """
632 recursive walk in root dir and return a set of all path in that dir
635 recursive walk in root dir and return a set of all path in that dir
633 based on repository walk function
636 based on repository walk function
634
637
635 :param repo_name: name of repository
638 :param repo_name: name of repository
636 :param revision: revision for which to list nodes
639 :param revision: revision for which to list nodes
637 :param root_path: root path to list
640 :param root_path: root path to list
638 :param flat: return as a list, if False returns a dict with decription
641 :param flat: return as a list, if False returns a dict with decription
639
642
640 """
643 """
641 _files = list()
644 _files = list()
642 _dirs = list()
645 _dirs = list()
643 try:
646 try:
644 _repo = self.__get_repo(repo_name)
647 _repo = self.__get_repo(repo_name)
645 changeset = _repo.scm_instance.get_changeset(revision)
648 changeset = _repo.scm_instance.get_changeset(revision)
646 root_path = root_path.lstrip('/')
649 root_path = root_path.lstrip('/')
647 for topnode, dirs, files in changeset.walk(root_path):
650 for topnode, dirs, files in changeset.walk(root_path):
648 for f in files:
651 for f in files:
649 _files.append(f.path if flat else {"name": f.path,
652 _files.append(f.path if flat else {"name": f.path,
650 "type": "file"})
653 "type": "file"})
651 for d in dirs:
654 for d in dirs:
652 _dirs.append(d.path if flat else {"name": d.path,
655 _dirs.append(d.path if flat else {"name": d.path,
653 "type": "dir"})
656 "type": "dir"})
654 except RepositoryError:
657 except RepositoryError:
655 log.debug(traceback.format_exc())
658 log.debug(traceback.format_exc())
656 raise
659 raise
657
660
658 return _dirs, _files
661 return _dirs, _files
659
662
660 def get_unread_journal(self):
663 def get_unread_journal(self):
661 return self.sa.query(UserLog).count()
664 return self.sa.query(UserLog).count()
662
665
663 def get_repo_landing_revs(self, repo=None):
666 def get_repo_landing_revs(self, repo=None):
664 """
667 """
665 Generates select option with tags branches and bookmarks (for hg only)
668 Generates select option with tags branches and bookmarks (for hg only)
666 grouped by type
669 grouped by type
667
670
668 :param repo:
671 :param repo:
669 """
672 """
670
673
671 hist_l = []
674 hist_l = []
672 choices = []
675 choices = []
673 repo = self.__get_repo(repo)
676 repo = self.__get_repo(repo)
674 hist_l.append(['tip', _('latest tip')])
677 hist_l.append(['tip', _('latest tip')])
675 choices.append('tip')
678 choices.append('tip')
676 if not repo:
679 if not repo:
677 return choices, hist_l
680 return choices, hist_l
678
681
679 repo = repo.scm_instance
682 repo = repo.scm_instance
680
683
681 branches_group = ([(k, k) for k, v in
684 branches_group = ([(k, k) for k, v in
682 repo.branches.iteritems()], _("Branches"))
685 repo.branches.iteritems()], _("Branches"))
683 hist_l.append(branches_group)
686 hist_l.append(branches_group)
684 choices.extend([x[0] for x in branches_group[0]])
687 choices.extend([x[0] for x in branches_group[0]])
685
688
686 if repo.alias == 'hg':
689 if repo.alias == 'hg':
687 bookmarks_group = ([(k, k) for k, v in
690 bookmarks_group = ([(k, k) for k, v in
688 repo.bookmarks.iteritems()], _("Bookmarks"))
691 repo.bookmarks.iteritems()], _("Bookmarks"))
689 hist_l.append(bookmarks_group)
692 hist_l.append(bookmarks_group)
690 choices.extend([x[0] for x in bookmarks_group[0]])
693 choices.extend([x[0] for x in bookmarks_group[0]])
691
694
692 tags_group = ([(k, k) for k, v in
695 tags_group = ([(k, k) for k, v in
693 repo.tags.iteritems()], _("Tags"))
696 repo.tags.iteritems()], _("Tags"))
694 hist_l.append(tags_group)
697 hist_l.append(tags_group)
695 choices.extend([x[0] for x in tags_group[0]])
698 choices.extend([x[0] for x in tags_group[0]])
696
699
697 return choices, hist_l
700 return choices, hist_l
698
701
699 def install_git_hook(self, repo, force_create=False):
702 def install_git_hook(self, repo, force_create=False):
700 """
703 """
701 Creates a rhodecode hook inside a git repository
704 Creates a rhodecode hook inside a git repository
702
705
703 :param repo: Instance of VCS repo
706 :param repo: Instance of VCS repo
704 :param force_create: Create even if same name hook exists
707 :param force_create: Create even if same name hook exists
705 """
708 """
706
709
707 loc = jn(repo.path, 'hooks')
710 loc = jn(repo.path, 'hooks')
708 if not repo.bare:
711 if not repo.bare:
709 loc = jn(repo.path, '.git', 'hooks')
712 loc = jn(repo.path, '.git', 'hooks')
710 if not os.path.isdir(loc):
713 if not os.path.isdir(loc):
711 os.makedirs(loc)
714 os.makedirs(loc)
712
715
713 tmpl_post = pkg_resources.resource_string(
716 tmpl_post = pkg_resources.resource_string(
714 'rhodecode', jn('config', 'post_receive_tmpl.py')
717 'rhodecode', jn('config', 'post_receive_tmpl.py')
715 )
718 )
716 tmpl_pre = pkg_resources.resource_string(
719 tmpl_pre = pkg_resources.resource_string(
717 'rhodecode', jn('config', 'pre_receive_tmpl.py')
720 'rhodecode', jn('config', 'pre_receive_tmpl.py')
718 )
721 )
719
722
720 for h_type, tmpl in [('pre', tmpl_pre), ('post', tmpl_post)]:
723 for h_type, tmpl in [('pre', tmpl_pre), ('post', tmpl_post)]:
721 _hook_file = jn(loc, '%s-receive' % h_type)
724 _hook_file = jn(loc, '%s-receive' % h_type)
722 _rhodecode_hook = False
725 _rhodecode_hook = False
723 log.debug('Installing git hook in repo %s' % repo)
726 log.debug('Installing git hook in repo %s' % repo)
724 if os.path.exists(_hook_file):
727 if os.path.exists(_hook_file):
725 # let's take a look at this hook, maybe it's rhodecode ?
728 # let's take a look at this hook, maybe it's rhodecode ?
726 log.debug('hook exists, checking if it is from rhodecode')
729 log.debug('hook exists, checking if it is from rhodecode')
727 _HOOK_VER_PAT = re.compile(r'^RC_HOOK_VER')
728 with open(_hook_file, 'rb') as f:
730 with open(_hook_file, 'rb') as f:
729 data = f.read()
731 data = f.read()
730 matches = re.compile(r'(?:%s)\s*=\s*(.*)'
732 matches = re.compile(r'(?:%s)\s*=\s*(.*)'
731 % 'RC_HOOK_VER').search(data)
733 % 'RC_HOOK_VER').search(data)
732 if matches:
734 if matches:
733 try:
735 try:
734 ver = matches.groups()[0]
736 ver = matches.groups()[0]
735 log.debug('got %s it is rhodecode' % (ver))
737 log.debug('got %s it is rhodecode' % (ver))
736 _rhodecode_hook = True
738 _rhodecode_hook = True
737 except Exception:
739 except Exception:
738 log.error(traceback.format_exc())
740 log.error(traceback.format_exc())
739 else:
741 else:
740 # there is no hook in this dir, so we want to create one
742 # there is no hook in this dir, so we want to create one
741 _rhodecode_hook = True
743 _rhodecode_hook = True
742
744
743 if _rhodecode_hook or force_create:
745 if _rhodecode_hook or force_create:
744 log.debug('writing %s hook file !' % h_type)
746 log.debug('writing %s hook file !' % (h_type,))
745 with open(_hook_file, 'wb') as f:
747 with open(_hook_file, 'wb') as f:
746 tmpl = tmpl.replace('_TMPL_', rhodecode.__version__)
748 tmpl = tmpl.replace('_TMPL_', rhodecode.__version__)
747 f.write(tmpl)
749 f.write(tmpl)
748 os.chmod(_hook_file, 0755)
750 os.chmod(_hook_file, 0755)
749 else:
751 else:
750 log.debug('skipping writing hook file')
752 log.debug('skipping writing hook file')
General Comments 0
You need to be logged in to leave comments. Login now